Introducing xdg-desktop-portal-generic: The portal backend for the compositors that never had one

On many Wayland compositors, the portal backend that lets apps screen-share, inject input, and read the clipboard is only half there. I built the missing half.

On a Wayland desktop, the program that lets an app take a screenshot, share your screen, inject a keystroke, or read the clipboard is usually not the app, and it isn't the compositor either. It's a quiet middleman called a desktop portal. On a surprising number of Wayland compositors, that middleman is only half there.

I built the missing half. It's called xdg-desktop-portal-generic, and it's a portal backend that runs on any Wayland compositor that speaks the standard protocols, with no changes to the compositor itself. It's the reason a sandboxed Flatpak app, or a remote desktop server, can do real work on compositors that never shipped a portal backend of their own. Here's what a portal is, why the gap exists, and why I lean on this one as one of three screen-capture routes in my own RDP server.

Source and releases: github.com/lamco-admin/xdg-desktop-portal-generic. Crate and docs: crates.io/crates/xdg-desktop-portal-generic, docs.rs/xdg-desktop-portal-generic.

What a desktop portal actually is

A portal is the safe doorway between an application and the parts of your desktop the application isn't allowed to touch directly. On Wayland that isolation is the whole point: An app can't just grab the screen or read another window's clipboard the way it could under X11. So the freedesktop project defined xdg-desktop-portal, a D-Bus API with interfaces for the things apps legitimately need, like ScreenCast, RemoteDesktop, Clipboard, Screenshot, and Settings.

That API has two halves. The frontend is a single daemon that every desktop runs the same way. The backend is the half that does the real work, and it's specific to your desktop, because only your desktop knows how to actually capture a frame or paste into a window. GNOME ships its backend, xdg-desktop-portal-gnome. KDE ships xdg-desktop-portal-kde. When a Flatpak app asks to share your screen, the request travels app to frontend to backend, and the backend is the part that has to exist.

That's the catch. If your compositor doesn't ship a backend, the doorway leads nowhere.

The gap: capable compositors with no backend behind the door

A large and growing family of Wayland compositors has no portal backend of its own. The wlroots-based ones, the Smithay-based ones, COSMIC, niri, Jay, and the smaller tiling compositors people actually daily-drive. They're excellent at being compositors. They simply never took on the separate job of implementing a D-Bus portal backend.

There's been one partial answer, xdg-desktop-portal-wlr, and it's genuinely useful, but it covers ScreenCast and Screenshot and stops there. There's no RemoteDesktop interface, so nothing can inject a keystroke or move the pointer through the portal. There's no Clipboard interface either. The practical result is that screen sharing in a browser might work on one of these desktops, while anything that needs input injection or clipboard access through the portal just can't happen. For a remote desktop server, which needs all three at once, that's the difference between supporting a compositor and not.

So the choice was to ask every one of those compositor projects to write and maintain its own backend, or to write one backend that doesn't care which compositor it's talking to. I went with the second.

The premise: a backend that's just a Wayland client

The design idea is small, and it's the whole thing: A portal backend doesn't have to live inside the compositor. It can be an ordinary Wayland client that connects from the outside and uses the standard protocols the compositor already exposes.

That's what xdg-desktop-portal-generic is. It connects as a standalone Wayland client, with no compositor-side code and no custom traits to implement, and it answers portal requests by driving the protocols a modern Wayland compositor already speaks. It captures the screen with ext-image-copy-capture-v1, falling back to wlr-screencopy. It injects input through the EIS (libei) bridge, falling back to the virtual-pointer and virtual-keyboard protocols. It moves clipboard data with ext-data-control-v1, falling back to wlr-data-control. It all auto-detects at startup, and it prefers the modern ext- protocols over their older wlr- equivalents whenever the compositor offers them.

The upshot is that one binary covers five portal interfaces across a whole category of compositors, and a compositor maintainer has to do nothing to opt in beyond shipping the standard protocols they probably already ship.

It started life under the name xdg-desktop-portal-smithay, back when I was aiming it at Smithay-based compositors specifically. The name didn't survive contact with the design, because the thing never actually depends on Smithay, or on any one compositor. "Generic" is the accurate word: It's the backend for whoever needs one.

What it implements, concretely

It's written in Rust, currently at version 0.5.0, and dual-licensed MIT or Apache-2.0. Here are the five portal interfaces and how each one is served:

Portal interface Version Primary protocol Fallback
RemoteDesktop v2 EIS (libei) bridge mode wlr-virtual-pointer + zwp-virtual-keyboard
ScreenCast v6 ext-image-copy-capture-v1 wlr-screencopy-v1
Clipboard v1 ext-data-control-v1 wlr-data-control-v1
Settings v2 Environment-variable config GTK_THEME detection
Screenshot v2 Single-frame capture to PNG none

Under the hood it runs three threads with clear jobs: A Tokio async runtime owns the D-Bus service and the portal logic, a dedicated Wayland event loop owns protocol dispatch and frame capture, and a PipeWire thread owns stream management and buffer delivery. Frames reach the requesting app over PipeWire, the same transport the GNOME and KDE backends use, so a normal screen-sharing app doesn't know or care that a different backend answered.

It's designed for the compositors that don't ship their own backend: COSMIC, niri, Jay, and any Smithay-based compositor, and it works with any compositor that implements the ext- or wlr- protocols it relies on.

Why I needed it: the third capture route in lamco-rdp-server

I didn't build this as an abstract good deed. I needed it, because lamco-rdp-server is a native-Wayland RDP server, and a native-Wayland RDP server has to capture the screen, inject input, and sync the clipboard on whatever desktop the user is running. There's no single way to do that across the Wayland world. There are three.

On GNOME, the server talks to Mutter's own remote-desktop D-Bus API directly, because GNOME exposes one and it's the cleanest path there. On KDE and the other desktops that ship a complete portal backend, the server goes through the standard portal, and the desktop's own backend does the capture and injection. And on the wlroots and Smithay compositors, the ones with no complete backend, the server has historically had nowhere to go for input and clipboard at all.

xdg-desktop-portal-generic is that third route. It turns "this compositor has no portal backend" into "this compositor has a portal backend, and it's a Wayland client I can ship." It's why the server can offer the same screen, input, and clipboard story on COSMIC or niri that it offers on GNOME and KDE, instead of degrading to view-only the moment it meets a compositor that wlroots-portal couldn't fully serve.

That it's also a clean, reusable thing in its own right is the nice part. Any Flatpak app that wants real portal support on these compositors gets it from the same binary, not just my server.

Who it's for, and who doesn't need it

It's for people running COSMIC, niri, Jay, Sway, or another wlroots- or Smithay-based compositor who want screen capture, input injection, and clipboard to work through the standard portal that Flatpak and Snap apps expect. It's for compositor authors who'd rather point users at a working backend than write and maintain one. And it's for anyone building a screen-sharing or remote-desktop tool who's tired of a compositor falling off the support matrix because its portal story was incomplete.

It's just as worth saying who doesn't need it. If you're on GNOME or KDE, your desktop already ships a full portal backend, and you should keep using it; this isn't a replacement for those, and it isn't trying to be. It also can't conjure capabilities out of nothing: It needs a compositor that actually implements the ext- or wlr- protocols it drives, so a compositor that exposes none of them is still out of reach. And it covers the five portal interfaces above, not the entire portal surface.

The point of it

A Wayland compositor shouldn't have to choose between being small and focused and letting its users screen-share, run a remote desktop, or paste between sandboxed apps. The portal design already separated the doorway from the desktop behind it. xdg-desktop-portal-generic just takes that separation at its word, and supplies the backend as a plain Wayland client that any capable compositor can borrow.

If you're on one of the compositors that never had a backend, the GitHub repository and the crate on crates.io are where to start, and the project page lays out the install. If you came here from the remote-desktop side, lamco-rdp-server is the tool this backend quietly holds up on a third of the compositors it runs on.

GL
Greg Lamberson

Founder of Lamco Development LLC. Building Linux infrastructure: a Wayland-native RDP server, a memory-safe UEFI bootloader, and open-source Rust and Kotlin libraries.

More about Greg ›