One app, two servers, one screen
A jailbroken iOS device gives this stack no display server, no DRM/KMS path, and no background service that can own the screen. The design works around that by funneling desktop sessions through one ordinary app.
The full path
The bridge app
For the X11 and Wayland desktops, one app carries the whole thing: xiOS.app, which shows on the Home Screen as X11. It owns a CAMetalLayer and the UIKit input surface, and it renders none of its own content. At startup a display server creates an output IOSurface and passes its mach port to the app. The app adopts that surface, wraps it as a Metal texture, and draws it every frame. When a server redraws the desktop, the app shows the new contents without copying a single pixel.
Because the app holds the screen and the input, the servers never touch UIKit. That keeps them close to their upstream form, which is what makes cross-compiling them tractable. Native mode is the one exception: it presents through a separate per-window host app rather than this single desktop surface.
Two servers, one output contract
Both servers produce the same thing: an output IOSurface the app can present. From the app's side they are interchangeable, so you can switch between an X11 session and a Wayland session and the app never knows which is running.
- xiOS
- An Xvfb-derived X server whose device layer draws into an IOSurface. X11 clients connect over the ordinary protocol and render in software.
- iosc
- A clean-room
libwayland-servercompositor. It composites clients on the GPU, advertises the protocols real toolkits expect (xdg-shell, popups, subsurfaces, viewport, fractional-scale, clipboard), and routes input throughwl_seat.
A Wayland frame
- A GTK4 app renders with GLES through ANGLE into its own IOSurface.
- It hands that surface to iosc over a mach port, as an IOSurface
wl_buffer. - iosc adopts it as a Metal texture and composites it with every other window into the output IOSurface, on the GPU.
- xiOS.app presents that output IOSurface as a Metal texture on the screen.
No CPU copy happens between step one and step four. A window's pixels are drawn once by the GPU and scanned out by the same GPU.
Input, in reverse
A tap or keystroke enters UIKit inside the app. For an X11 session it becomes XTEST fed to the X server. For a Wayland session it crosses a small socket to iosc and turns into wl_pointer and wl_keyboard events for the focused window.
Hardware and POSIX bridges
Drawing pixels and routing input is only half the job. A desktop also expects a battery, a brightness slider, sound, Bluetooth, orientation, and a logged-in user. None of that exists in the Linux sense on iOS, so a set of small daemons translate each one, reading the real iOS API and republishing it as the D-Bus service, Wayland protocol, or sysfs file the desktop is looking for.
System integration walks through how each one works, from audio to Bluetooth.