RealVNC Server 7.17.0 introduced hidden support for Wayland compositors. It generally works well, but there are some compositor-specific and some implementation issues.
This is nice since their proprietary UDP-based RTP/SCTP-wrapped RFB protocol performs much better than wayvnc, especially over non-local networks. I did spend some time a while ago reversing the protocol and was able to figure out everything but the handshake and a few encodings, but the custom handshake for their proprietary auth mechanism makes it annoying to implement (even the unencrypted one still signs packets using HMAC with a negotiated key).
Now that they have basic Wayland support, I figured shimming or patching the bugs or compatibility issues would be the best way forward.
Note
I have another solution to make RealVNC run on Wayland, and it's currently more stable and robust than vncagent-wlr, at the cost of ~1.5x CPU usage. See xwlrvnc.
You may also be interested in my fixes and patches for the RealVNC Android app, including an invisible menu (instead of the gigantic floating toolbar which gets in the way), dark mode support, key repeat support, and a fix for clicks randomly not working on high-frequency touchscreens (e.g., on a Pixel 9 or later).
If anyone from RealVNC is reading this:
- You should implement an additional
vncagent-xdgvariant using xdg-desktop-portal for KDE and GNOME support. - You should switch to
ext_image_copy_capture_v1as the primary capture mode, only falling back to screencopy if it isn't supported. This has a better API and will also let you support client-side cursors. - You need to make
vncserver-x11-coreforward clipboard events to the agent if it'svncagent-wlr. Xwayland clipboard syncing doesn't really work and needs separate tools. - You need to flush after sending input events (or anything, really). This isn't expensive, and the reason you didn't have to do it for X11 is because
XTESTdoes it implicitly for each event. - Multi-monitor support shouldn't be too hard (it's easier than X11), so I assume you're already working on it.
- I love RealVNC and strongly recommend it to people!!!
For 7.17.0, you'll need:
- A Wayland compositor supporting:
zwlr_screencopy_manager_v1zwlr_virtual_pointer_v1zwp_virtual_keyboard_v1zwlr_data_control_manager_v1
- If your compositor is now sway (especially if it's Smithay-based), you'll want wl-uinput-proxy to fix the virtual pointer/keyboard.
- If you use this, you need write access to
/dev/uinput. - The commands below assume you build it into
/usr/local/bin/wl-uinput-proxy. - If you don't use this, just remove it from the commands.
- If you use this, you need write access to
- The force-input-flush.so shim.
- The commands below assume you build it into
/usr/local/lib64/vnc/force-input-flush.so.
- The commands below assume you build it into
- Bubblewrap.
This will work well for basic single-monitor usage, except for client-to-server clipboard and missing client-side cursor support.
To build the shims:
# wl-uinput-proxy
cargo install --root /tmp --force wl-uinput-proxy@0.0.2
sudo install -Dm755 /tmp/bin/wl-uinput-proxy /usr/local/bin/
# force-input-flush
gcc -Wall -Wextra -shared -fPIC -O2 -o /tmp/force-input-flush.so ./input-flush/force-input-flush.c -ldl
sudo install -Dm644 /tmp/force-input-flush.so /usr/local/lib64/vnc/You can start the server with:
bwrap \
--bind / / \
--dev-bind /dev/uinput /dev/uinput \
--setenv LD_PRELOAD /usr/local/lib64/vnc/force-input-flush.so \
--bind /usr/bin/vncagent-wlr /usr/bin/vncagent-x11 \
/usr/local/bin/wl-uinput-proxy \
/usr/bin/vncserver-x11Or as a systemd user unit:
[Unit]
PartOf=graphical-session.target
After=graphical-session.target
Requisite=graphical-session.target
[Service]
ExecStart=/usr/bin/bwrap --bind / / --dev-bind /dev/uinput /dev/uinput --setenv LD_PRELOAD /usr/local/lib64/vnc/force-input-flush.so --bind /usr/bin/vncagent-wlr /usr/bin/vncagent-x11 /usr/local/bin/wl-uinput-proxy /usr/bin/vncserver-x11
Restart=always
RestartSec=10s
RestartSteps=4
RestartMaxDelaySec=160s
[Install]
WantedBy=niri.serviceSmithay-based compositors, including niri, have broken (niri-wm/niri#403, Smithay/smithay#1903) virtual keyboard/pointer implementations. Sway works fine.
I wrote a Wayland proxy which implements the zwlr_virtual_pointer_v1 and zwp_virtual_keyboard_v1 protocols using uinput. It works for other things too, not just RealVNC.
This works pretty well, with the only real limitation being that it emulates a system input device, so it can't be bound to a specific Wayland seat, and it needs permission to write to /dev/uinput.
See wl-uinput-proxy.
RealVNC's vncagent-wlr implmentation currently has a bug where it does not explicitly flush input events. As a result, they only get flushed in the screen capture loop, every ~60ms, causing the events to be delivered in bursts.
I write a shim which forces these to get flushed immediately, similar to how it works with vncagent-x11 and XTEST.
See force-input-flush.
Based on testing and static anaysis.
The GUI runs in Xwayland, vncagent-wlr is native.
It doesn't detect Wayland automatically, so you need to replace vncagent-x11 with vncagent-wlr.
The following Wayland protocols are used:
- core
wl_shm, assuming the compositor implements the protocols correctly (e.g., sway)wl_shm_poolwl_bufferwl_seatwl_output
- screen capture
zwlr_screencopy_manager_v1zwlr_screencopy_frame_v1
- input
zwlr_virtual_pointer_manager_v1zwlr_virtual_pointer_v1zwp_virtual_keyboard_manager_v1zwp_virtual_keyboard_v1
- clipboard
zwlr_data_control_manager_v1zwlr_data_control_device_v1zwlr_data_control_source_v1zwlr_data_control_offer_v1
Things that work:
- The user-mode server.
- The UI, including config and connection notifications.
- Basic single-display usage, assuming the compositor implements the protocols correctly (e.g., sway).
- Mouse (absolute).
- Keyboard.
- Screen capture.
- The server-to-client clipboard.
- Running in a nested compositor (provided that DISPLAY and WAYLAND_DISPLAY are set correctly).
- Pausing for idle clients.
- Audio.
Thinks that don't:
- Multi-monitor doesn't work at all.
- It only displays one monitor.
- Pointer input is mapped across all monitors, making it misaligned.
- Display scaling doesn't work properly.
- The client-to-server clipboard (i.e., pasting) doesn't work.
- Based on some preliminary static analysis, I think this is because
vncserverui(which is running in Xwayland) gets the IPC messages sincevncserver-x11-coreseems to be hardcoded to send them there (this makes sense given how system-mode VNC works on X11). The agent has an internalEnableClipboardoption to have it handle the clipboard itself, which makes server-to-client work, but the client-to-server IPC messages still don't get delivered to the agent.
- Based on some preliminary static analysis, I think this is because
- Client-side cursor doesn't work.
- This would require
vncagent-wlrto supportext_image_copy_capture_cursor_session_v1(which also lacks wide compositor support).
- This would require
- Damage tracking isn't used.
- The screen is polled with a fixed interval of 60ms (~16.6 Hz)
- For comparison,
vncagent-x11polls at 20Hz is XDAMAGE is not used. - The overhead isn't too bad though, and it performs well overall, so this is mostly a non-issue.
- The system-mode and virtual-mode servers obviously don't work.
- The tray icon doesn't work (but who needs that anyways).
- The cursor is jittery, and keyboard/mouse events arrive in bursts (see my notes in the section about the virtual input flush fix above).
Compositor compatibility issues:
- Smithay-based compositors (e.g., niri) have broken virtual keyboard support (niri-wm/niri#403, Smithay/smithay#1903). The keymap handling is wrong, and compositor keybinds don't work.
- GNOME and KDE use
libeiviaxdg-desktop-portaland also don't implement screencopy. - The
ext_image_copy_capture_v1is intended to replacescreencopy
I didn't test most of the proprietary extensions like file transfer, chat, relative mouse position, and audio since I have other solutions for that on machines I need it for (e.g., spicy-kvm).
I also didn't test advanced features like input blocking and screen blanking.