Forward X11 to macOS (Docker)

xsddiagram is used as an example application.


Dockerfile

FROM debian:bullseye-slim

# Install packages
RUN apt update && apt-get install -y xsddiagram libgtk2.0-0

# Allow X11 forwarding
ENV DISPLAY=host.docker.internal:0

# Run xsddiagram
CMD ["xsddiagram"]

xsddiagram.py

import os
import subprocess
import sys

def run_command(command):
    try:
        return subprocess.run(command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    except subprocess.CalledProcessError as e:
        print(f"Error: {e}")
        sys.exit(1)

def is_xquartz_installed():
    result = run_command("brew list --cask | grep xquartz")
    return result.returncode == 0

def is_docker_image_built():
    result = run_command("docker image ls | grep xsddiagram")
    return result.returncode == 0

def install_and_configure_xquartz():
    if not is_xquartz_installed():
        print("Installing XQuartz...")
        run_command("brew install --cask xquartz")

    print("Configuring XQuartz...")
    run_command("defaults write org.xquartz.X11 nolisten_tcp -bool false")
    run_command("/opt/X11/bin/xhost +localhost")

def build_and_run_docker_image():
    if not is_docker_image_built():
        print("Building Docker image...")
        run_command("docker build --tag xsddiagram .")

    print("Running Docker container...")
    mount_path = os.path.expanduser("~")
    run_command(f"docker run --rm --volume {mount_path}:{mount_path} xsddiagram")

def main():
    if sys.platform != "darwin":
        print("This script is for macOS only.")
        sys.exit(1)

    install_and_configure_xquartz()
    build_and_run_docker_image()

if __name__ == "__main__":
    main()