The full path

Figure 01. Display and inputapp to A10

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-server compositor. It composites clients on the GPU, advertises the protocols real toolkits expect (xdg-shell, popups, subsurfaces, viewport, fractional-scale, clipboard), and routes input through wl_seat.

A Wayland frame

  1. A GTK4 app renders with GLES through ANGLE into its own IOSurface.
  2. It hands that surface to iosc over a mach port, as an IOSurface wl_buffer.
  3. iosc adopts it as a Metal texture and composites it with every other window into the output IOSurface, on the GPU.
  4. 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.