Screen sharing#
carrot is its own xdg-desktop-portal ScreenCast backend (interface version 4), and the video reaches PipeWire through carrot's built-in pure-Rust client. If an app speaks the portal, it can cast; OBS and browser video calls both go through it.
What you can cast#
Any monitor, a single toplevel (X11 or Wayland), or an entire workspace as one stream. The workspace option is a carrot extra, reachable through the picker.
Sources keep streaming when hidden. A window on another workspace, or a workspace that is not on any monitor, composes off-screen for the cast instead of freezing. A workspace cast keeps showing the settled layout while a switch animation plays on glass.
Keeping windows private#
A window rule with no-capture blacks that window out of every capture path: portal casts, screenshots, and recordings all see an opaque black box in its place while your own screen shows it normally. The blackout covers the close-animation replay too, so pixels never leave the compositor.
Consent#
When an app asks to cast, one of three things happens, in order:
- A restore token from an earlier session skips consent entirely. The portal's permission store keeps tokens on disk, and carrot re-finds the granted source across its own restarts by the app and window it approved, so the approval outlives both sides.
- Your picker runs, if you configured one (see below).
- With no picker, the next left click chooses whatever the pointer is on.
Escapeor any other button cancels.
Bring your own picker#
The screencast { picker } key in config names a command that carrot runs for consent, so your launcher of choice can be the dialog. The contract:
- Candidates arrive as ndjson on stdin, one JSON object per line. Outputs look like
{"kind":"output","id":"o:DP-3","name":"DP-3","width":2560,"height":1440,"x":0,"y":0}; windows and workspaces carryw:andws:ids. - The picker prints one chosen id on stdout:
o:DP-3,w:42, orws:2. - Empty output or EOF cancels the request.
- A picker that never answers is killed after 120 seconds, whole process group included, and the request cancels cleanly.
A fuzzel picker is a few lines of shell: read the lines, format labels, print the chosen id.
Testing it#
carrot portal-probe runs the portal backend standalone, and carrot pw-probe checks the PipeWire connection. Every install channel registers the portal files (carrot install writes them), so xdg-desktop-portal routes ScreenCast to carrot automatically.