Documentation

RediWM Wiki

The complete guide to installing RediWM, using the desktop, configuring your theme, and scripting with IPC.

RediWM

RediWM is a wlroots compositor that draws its whole shell itself: taskbar, start menu, settings, lock and login screens, notifications, OSDs. One process, no waybar/greeter/launcher/notification daemon to wire up.

Pages

The binaries

Binary What it is
rediwm the compositor
rediwm-session supervises the compositor, restarts it after a crash
rediwm-msg IPC command line client
rediwm-dm optional login manager (only with --dm, never enabled for you)
rediwm-files file manager
rediwm-images image viewer
rediwm-pdf sandboxed PDF viewer
rediwm-editor text editor
rediwm-desktop desktop icons and wallpaper
rediwm-share-picker screen sharing picker
rediwm-accounts-helper root helper for account management, runs under pkexec

Other docs in the repo

  • SECURITY.md: security model
  • TESTING.md: how the tests run
  • AGENTS.md: implementation notes for contributors

Getting Started

Install

scripts/install.sh installs the prebuilt release for your distro (Arch, Debian, Ubuntu and Fedora on x86_64, and their derivatives). It brings the exact wlroots 0.20 RediWM was tested with, installs the runtime libraries through your package manager, checks the download's checksum and adds a RediWM session entry. Nothing is compiled. Pass --build to compile from source instead; that is also the fallback for other distros and CPUs, or if the release's libraries don't match yours. REDIWM_VERSION=<tag> installs a specific release.

curl -fsSL https://rediwm.redios.org/install.sh | sh -s -- --dm   # --dm also installs rediwm-dm

Installing never replaces your login manager. SDDM, GDM and friends keep working. rediwm-dm is only installed with --dm, and even then it isn't enabled.

Optional: foot, brightnessctl, gio/xdg-open, git (for Files repo status), paplay (event sounds). For screen sharing you want xdg-desktop-portal, xdg-desktop-portal-wlr and xdg-desktop-portal-gtk; the installer adds all three.

Build and run

Building needs Zig 0.16 and wlroots 0.20 (scripts/install.sh --build builds it into a private prefix on Debian/Ubuntu; REDIWM_PRIVATE_WLROOTS=1 does the same on Arch and Fedora), plus dev files for Wayland, wayland-protocols, xkbcommon, pixman, FreeType, HarfBuzz, Fontconfig, librsvg/GdkPixbuf, PangoCairo, libinput, PAM, libpulse, libpipewire-0.3, Poppler GLib, libseccomp, libjpeg and libpng.

zig build run -- foot                     # nested in your current Wayland session
zig build -Doptimize=ReleaseSafe          # for daily use and measurements
sh scripts/install-session.sh             # install and restart the running session
sh scripts/install-session.sh --no-restart --dm   # install only, plus rediwm-dm

From a checkout, scripts/install.sh does deps, build, then install-session.sh with whatever args you pass.

Installing adds a RediWM entry to /usr/share/wayland-sessions.

Nested sessions

Running inside another Wayland session is handy for hacking, but:

  • It's never sharper than the host. Use REDIWM_SCALE=1 to judge layout.
  • The Wayland backend never sets buffer scale, so don't judge sharpness there.

Crashes and recovery

rediwm-session restarts the compositor after a crash, at most 5 times a minute. If the session was locked when it crashed, it comes back locked. Logs go to $XDG_STATE_HOME/rediwm/session.log.

Stuck? Switch VTs with Ctrl+Alt+F1..F12 (works while locked), or:

pkill -u "$(id -u)" -x rediwm

Restarting over IPC (restart_shell) disconnects every app.

Using RediWM

Keys

Keys Action
Super+Space start menu
Super+T / E / B terminal / Files / browser
Super+Q, Super+F, Super+M close, fullscreen, maximize
Super+Shift+arrows tile halves and quarters
Super+arrows slide to the neighbouring desktop
Super+Ctrl+arrows focus the window in that direction
Alt+Tab window switcher
Super+1..5, Super+=/-/0 window zoom
Super+Shift+=/-/0 desktop zoom
Super+L lock
Ctrl+Shift+S, Print region / full-screen screenshot
Super+Z undo the last window move or resize
Super+Shift+E quit
Super+Escape take shortcuts back from a VM or remote desktop

Everything lives under [keybinds] in the config. Set a binding to "noop" to turn it off.

Mouse

  • Alt+drag moves a window, Alt+right-drag resizes.
  • Super+Alt+mouse or a middle-button drag pans the desktop.
  • Super+Alt+scroll zooms the desktop, Alt+scroll over a window zooms just that window. Scrolling on a titlebar does the same.
  • Drag a window to a screen edge to tile or maximize it (snap_to_edges).

The canvas

The desktop is one big canvas, canvas_columns x canvas_rows screens (3x3 by default). You pan around it and zoom out to see everything. Desktop zoom scales all windows together around the pointer, up to 100%, and doesn't change their world positions. Desktop icons and the taskbar stay fixed on screen by default. The mini map shows where you are and hides itself after a moment.

The volume/brightness OSD also shows the desktop zoom percentage.

Window switching zoom

Settings > Appearance, or [compositor] focus_zoom. Controls what Alt+Tab, directional focus and taskbar clicks do to the camera.

Mode What happens
boost (default) the selected floating window goes to 100% on-screen size, then goes back when you switch away. Saved zoom and position are untouched
keep just pans
camera zooms the desktop to the window's depth and fades windows that would grow past full size. Desktop zoom then steps through window depths

Reveals ease over 320 ms. Animation speed and reduced motion apply. You can override the pan with [animations.camera_reveal].

Window tabs

Settings > Appearance > Window tabs lets you pick apps that get tabs, using RediWM chrome (XDG, KDE or X11 decorations). Open the app once and it shows up in the list.

  • The + button opens another window as a tab in that frame. Normal launches stay separate.
  • Each tab has its own close button. The outer close button closes the whole group and respects app confirmation dialogs.
  • Arrow buttons or scrolling over the strip switch tabs. Alt+scroll still zooms the window.
  • The app needs a desktop entry with a usable launch command. Launches that only activate an existing window don't make a tab.
  • Saved in [compositor] window_tab_apps.

Settings

Start menu cog. It's a normal window covering display modes, scale, night light, input, audio, appearance, shortcuts and the desktop canvas. Changes are written to the config and your comments stay intact.

Locking

  • The lock screen covers every output. Escape clears the field and never unlocks.
  • Volume and brightness work behind the lock: the hardware keys, or the sliders at the bottom of the screen (click the speaker to mute). A slider appears only if there's a sound output or a backlight to control. The login screen has no sliders.
  • It engages before the system sleeps and waits until it's on screen first (lock_on_suspend, on by default). loginctl lock-session works too.
  • RediWM doesn't lock on idle by itself. Run swayidle from [[autostart]]: swayidle -w timeout 300 'swaylock -f'.
  • Lock-screen UI can't be driven by virtual input.

Games, VMs, X11

  • Games get pointer lock and relative motion.
  • Xwayland starts on the first X11 connection. With native scaling, X11 apps render at ceil(max output scale) and stay sharp on HiDPI.
  • Known limits from wlroots 0.20: X11 to Wayland drag and drop doesn't start, and X11 pointer input on a second output doesn't arrive.

Apps and Services

Files (rediwm-files)

The file manager. Space opens images, PDFs and text files.

  • Git: detects repos, subfolders and linked worktrees. The sidebar shows the branch and ahead/behind from what's known locally. Badges: M modified, A added, D deleted, R renamed, U conflict, ? untracked. Click the repo name to jump to its root. It never fetches or changes anything, and never runs a repo's own programs. A repo whose config names filter or Git LFS commands (think archives and USB sticks) is shown as a plain folder.
  • Archives: browse ZIP, TAR (gz, bz2, xz, zstd) and 7z like folders. They're read-only. Opening a member extracts just that file to private temp storage that's removed on exit. Context menu has Extract and Extract to.... Name clashes ask Skip/Rename/Cancel, nothing is overwritten, and paths outside the destination are rejected. No passworded archives, links or special files yet.
  • Thumbnails: JPEG and PNG are decoded without GdkPixbuf (it's slow and goes through sandboxed loaders). Shared freedesktop cache in $XDG_CACHE_HOME/thumbnails. REDIWM_FILES_THUMBNAILS=0 turns them off.
  • Devices: USB sticks and drives show up via UDisks2. Eject means unmount, the device stays listed, dimmed. REDIWM_FILES_DEVICES=0 disables it.
  • Pins: drop a folder on the PLACES sidebar to pin it. Stored one path per line in $XDG_STATE_HOME/rediwm/files-places.
  • Drag a file out and the window slides aside (dodge_file_drags).

Text editor (rediwm-editor [FILE ...])

Tabs, one window per display. UTF-8 files up to 4 GiB (they must fit in free memory), keeps BOM and line endings, asks before discarding changes. Only the lines on screen are ever laid out, so opening, scrolling and Find stay fast on huge files, and a single line of many megabytes is folded onto several rows. Editing near the start of a very large file moves the rest of the text, which costs a few milliseconds per 100 MB per keystroke.

Keys Action
Ctrl+N / O / S new tab / open / save
Ctrl+Shift+S save as
Ctrl+PageUp/Down switch tabs
Ctrl+W close tab
Ctrl+F, F3 find

Images (rediwm-images) and PDF (rediwm-pdf FILE)

Files, Images and the editor also run on other Wayland compositors.

The PDF viewer is sandboxed with Landlock (ABI 3 or newer) and needs a compositor with security-context-v1, which RediWM has. It refuses to parse a document if it can't isolate itself. Each PDF gets its own viewer. Web links copy their address instead of opening. Details in docs/pdf-security.md.

Desktop

Icons and wallpaper from ~/Desktop, on by default ([desktop] enabled). A .desktop launcher only runs if it's installed, owned by root and executable, or an exact copy of an installed entry. Anything else shows as a plain file until you pick Allow Launching in its menu. The wallpaper comes from wallpaper in the config, Settings, or set_wallpaper over IPC.

Notifications

RediWM is the notification daemon. Actions, images, do-not-disturb, history. Rules go in [[notification_rules]]. If you'd rather use dunst, set [notifications] daemon = "dunst" and restart. Inspect and drive them over IPC: notifications, set_dnd, dismiss_notification, invoke_notification_action.

Lock, login and polkit

  • Lock: see Using RediWM. Locks never unlock because of a crash: after a crash while locked, rediwm-session locks again before the backend even starts.
  • Greeter / rediwm-dm: the greeter is a lock that never unlocks, only rediwm-dm decides. It runs as an unprivileged user on its own VT. To use it: install with --dm, disable your current display manager, sudo systemctl enable rediwm-dm, reboot. Options in /etc/rediwm/dm.conf. It does no Xwayland, autostart, IPC, tray, portal or services.
  • Polkit: RediWM is a polkit agent ([polkit] enable). Capture and screen sharing are refused during a prompt.
  • Accounts: account management goes through rediwm-accounts-helper under pkexec. The compositor never runs as root.

Screen capture and sharing

wlr-screencopy and ext-image-copy-capture work (grim, wf-recorder, OBS, the portal). Any capture lights the taskbar Stop sharing indicator. It's refused while locked or during a polkit prompt. stop_all_capture over IPC ends everything. See docs/screen-sharing.md.

App scopes

On a real session each app you launch is moved into its own app-rediwm-<id>-<pid>.scope so systemd-oomd kills one runaway app and not your whole session. Off in nested and headless sessions unless REDIWM_APP_SCOPES=1.

Startup

The desktop renders before autostart runs, and audio and session environment setup never block frames or input. Autostart entries go in [[autostart]].

Configuration

The file is $XDG_CONFIG_HOME/rediwm/config.toml. REDIWM_CONFIG overrides the path. It's written with commented defaults on first run and reloads when you save. A parse error keeps the previous config. You can also reload with rediwm-msg reload, and check status with rediwm-msg config.

Sections

[theme], [input], [input_method], [compositor], [region], [animations.*], [idle], [night_light], [notifications], [desktop], [polkit], [ipc], [keybinds], [[outputs]], [[autostart]], [[window_rules]], [[notification_rules]], [[sandbox_allow]].

It's not full TOML

The parser reads a line-based subset. Don't run it through a generic TOML formatter. The rules:

  • One key = value per line. Arrays on one line too.
  • Strings use double quotes and are taken verbatim. No escape processing, so \n, \" and \u mean exactly those characters.
  • No single-quoted strings, no multiline strings or arrays, no inline tables, no arbitrary dotted keys, no dates.
  • # starts a comment outside double quotes.
app_id = ["firefox", "chromium"]   # fine

Theme

Colors, text sizes, corner radii and control styling belong in [theme]. See the complete theme reference for every supported key and its built-in default. Appearance preserves these overrides when it saves.

Region & Language

Settings → Region & Language lets you choose a personal language, regional formats and time zone. Empty choices inherit the login environment; system defaults are unchanged. RediWM's interface currently uses English.

Personal clock and calendar preferences apply immediately and are saved in [region]:

[region]
clock_24h = false
clock_show_seconds = false
clock_show_day = true
first_day_of_week = "sunday"

clock_24h applies to the taskbar, calendar and built-in lock screen. clock_show_seconds adds seconds to the taskbar time. clock_show_day shows the date line beneath it, using the selected regional format (formats, or the inherited locale). Both lines are centered; hiding the date centers the time vertically. These two options apply only to the taskbar clock. first_day_of_week accepts any lowercase weekday name, and changes both the weekday headings and date positions in the taskbar calendar. Existing configs keep 12-hour time and Sunday first until changed.

Handy [compositor] keys

Key Default Notes
allow_tearing false lets focused fullscreen clients request async presentation
window_tab_apps [] app IDs that get tabs
default_file_manager, default_terminal "" desktop IDs, empty means Files / auto terminal
taskbar_position "bottom" top or bottom
taskbar_items battery, network, volume, clock prefix a name with - to hide it
focus_follows_mouse false
canvas_columns, canvas_rows 3, 3 1 to 10
mini_map_enabled true
mini_map_position "bottom_right" bottom_left, bottom_center, bottom_right
mini_map_hide_ms 1500 500 to 10000
desktop_icons_fixed true
desktop_switch_ms 220 Super+arrow slide, 100 to 3000
zoom_steps [1.0, 0.85, 0.70, 0.55, 0.40]
camera_zoom_min, camera_zoom_max 0.25, 1.0
focus_zoom "boost" keep, boost, camera
window_gap 0 px between snapped windows
snap_to_edges true
dodge_file_drags true file manager slides aside while you drag a file out
switcher_opacity, inactive_opacity 1.0
border_radius 10 Legacy frame radius; [theme].radius_lg takes precedence.
xwayland true false means native only
xwayland_native_scaling false sharp X11 on fractional scales, restart needed
xwayland_scale 0 0 is automatic, 1.0 to 4.0 explicit, restart needed
dark_mode false live, goes through the Settings portal
placeholder_delay_ms 0 splash only if the app is this slow to show, 0 disables
wallpaper unset file in ~/.local/share/rediwm/wallpapers, or a path
lid_close "display_off" display_off, lock, suspend, ignore
lock_on_suspend true
sound_theme, sound_enabled, sound_disabled_events "freedesktop", true, [] event sounds, used by play_sound

Outputs

[[outputs]]
name = "DP-2"
x = -1920              # negative origin is only possible here
y = 0
scale = "auto"         # "auto" or 1 to 3
width = 1920           # optional mode
height = 1080
refresh_mhz = 60000    # omit for the highest at this size
enabled = true
primary = false
transform = "normal"   # normal, 90, 180, 270, flipped variants
night_light = false    # never tint this monitor
gamma = 1.0            # 0.5 to 2.0

Omit coordinates for automatic left-to-right placement. Scale and placement apply live. REDIWM_SCALE overrides every output. Changes from Settings, wlr-randr, kanshi or rediwm-msg output-config are all saved here.

Idle and night light

[idle]
blank_after_seconds = 600    # 0 disables
suspend_after_seconds = 0    # 0 disables

[night_light]
enabled = true
schedule = "always"          # "always", "fixed" or "sun"
temperature = 5000           # 1700 to 10000 K
# fixed: day_temperature, start, end, transition_minutes (0 to 180)
# sun:   latitude, longitude

Night light is on by default as a soft warm tint all day.

Window rules

Matched by glob. For each property the last matching rule wins.

[[window_rules]]
app_id = ["firefox", "chromium"]
title = "*Picture-in-Picture*"
opacity = 0.9
skip_taskbar = true
focus = false
  • Matchers: app_id, title, tag, x11_class, x11_instance, backend, dialog, and exclude_* versions.
  • Properties: output, x, y, center, width, height, maximized, fullscreen, focus, depth, opacity, decorations, skip_taskbar.

To debug a rule, ask the compositor:

rediwm-msg window-rules 12                       # what matched this window
rediwm-msg match-window-rules --app-id foo       # dry run

tag comes from the client (xdg-toplevel-tag), so it's metadata, not trusted identity.

[ipc]

[ipc]
automation = true   # synthetic input and screen capture. Restart required

Read once at startup. Details on IPC.

[polkit]

[polkit]
enable = true
helper_socket = "/run/polkit/agent-helper.socket"

[[autostart]]

[[autostart]]
cmd = "nm-applet"    # one entry per program

[[sandbox_allow]]

See Protocols and Sandboxing.

Theme reference

Put these keys in [theme] in $XDG_CONFIG_HOME/rediwm/config.toml. REDIWM_CONFIG selects another config file; REDIWM_THEME overlays another file's [theme] section. Omitted keys use the built-in defaults below. Appearance saves custom tokens along with its sliders and selectors. The bundled picker includes RediWM Dark, RediWM Light and Redi Blue. Redi Blue uses navy surfaces, cyan accents, 98% chrome opacity and a 30% selection tint. RediWM Light uses 75% window chrome opacity and teal selection accents. start_button_logo_color optionally tints the bundled R logo; Light uses a dark tint for contrast. Custom start-button icons retain their own colours.

Appearance also has a Taskbar theme picker under Theme, with the same presets plus "Same as theme". It gives the taskbar the preset's colours and leaves every other surface on the theme above. It is saved as a [taskbar_theme] section holding only these keys: taskbar_bg, taskbar_surface, taskbar_hover, taskbar_border, border_soft, surface_hover, window_fg, window_dim, danger, window_close_hover, start_button_hover, start_button_indicator, start_button_logo_color and the battery_* colours. Unlisted keys are ignored, so a whole theme file's body can be pasted under that header; keys it leaves out take the built-in defaults, not the main theme's. The section's presence selects the taskbar theme (an empty one is the built-in colours); without it the taskbar follows [theme]. Sizes, gaps and radii always come from [theme].

Colors accept "#rrggbb", "#rrggbbaa", or "rgba(r,g,b,a)" with RGB channels from 0 to 255 and alpha from 0 to 1. Numbers must be finite and nonnegative. Sizes are logical pixels. The tables describe appearance tokens; window placement, animation timing, cursor themes and sizes, blur, inactive opacity and frame radius also have settings in the other config sections.

[theme]
shell_accent = "#86bfff"
control_thumb = "#ffffff"
toggle_track = "rgba(120,140,170,0.25)"
slider_track_height = 6
app_text_size = 14
app_heading_size = 13
app_status_size = 12
desktop_selection = "rgba(80,140,220,0.2)"
desktop_selection_border = "#508cdc"
battery_full = "#40dca0"
image_checker_size = 16
pdf_search_match = "rgba(100,180,255,0.4)"

Palettes and reload

Shell surfaces use window_fg and window_dim. Their accent normally follows start_menu_selected_marker; shell_accent, shell_on_accent and shell_border_focus override that palette and its control/field focus rings. Settings uses settings_radius for controls. Text fields, carets and text selection have optional overrides that otherwise follow the accent of the surface displaying them.

Files' New, Sort and Filter buttons share the secondary-button palette: surface sets the background, surface_hover the hover fill, and border_soft the border. Their text and icons use window_fg. Active Filter and view-mode buttons use shell_accent (or start_menu_selected_marker when unset), tinted by button_selected_alpha. All of these values can be set in [theme]; Files follows edits while running.

Files' dialog bodies and context menus share app_toolbar as their background color. Changing it in [theme] updates both.

The compositor reloads the theme when the config changes. Files and Images follow saved colors and sizes; PDF and Editor load them when starting. The compositor's frame radius is the numeric [theme].radius_lg. The legacy [compositor].border_radius is used only when the theme omits radius_lg. Appearance's Radius presets write all numeric radius tokens: Default restores the current built-in radii, Sharp caps them at 4 px (the minimap's default), and Round uses 1.3 times the defaults. Individual theme radii remain editable. Cursor styling is [input].cursor_theme and [input].cursor_size; animation behavior belongs in [animations].

Set [theme].chrome_round_buttons = true for circular window controls and pill-shaped window tabs. Tab close, new-tab and overflow controls follow the same setting. It defaults to false, preserving the existing corner radii, and reloads live from the main config or the REDIWM_THEME file. Button sizes and hit targets stay the same; radius_lg still controls the window frame.

The lock's background always paints opaque, even if lock_bg supplies alpha; lock_wallpaper_opacity controls its wallpaper overlay. Actual image pixels, PDF paper/content, application-provided icons and fixed layout/hit-test geometry retain their content or structural dimensions.

Colors

Key Built-in default
window_bg "rgba(7.6,9,11,0.80)"
window_fg "rgba(245,245,245,1)"
window_dim "rgba(214,214,214,1)"
window_border "rgba(255,255,255,0.09)"
window_border_hover "rgba(255,255,255,0.13)"
window_divider "rgba(255,255,255,0.045)"
window_close_hover "rgba(237,27,46,1)"
text_secondary "rgba(214,214,214,1)"
app_bg "rgba(24,28,34,1)"
app_toolbar "rgba(29,34,41,1)"
app_sidebar "rgba(27,33,40,1)"
app_bar "rgba(35,42,51,1)"
app_item "rgba(34,40,46,1)"
app_item_hover "rgba(37,43,50,1)"
app_item_border "rgba(45,51,58,1)"
app_item_selected "rgba(78,37,46,1)"
app_nav_selected "rgba(91,36,46,1)"
app_divider "rgba(55,63,72,1)"
app_icon "rgba(214,214,214,1)"
scrollbar_thumb "rgba(89,98,110,1)"
scrollbar_thumb_active unset
bg "rgba(9,11,24,1)"
fg "rgba(245,245,245,1)"
dim "rgba(214,214,214,1)"
faint "rgba(160,160,160,1)"
accent "rgba(94,234,212,1)"
surface "rgba(255,255,255,0.05)"
border "rgba(255,255,255,0.09)"
accent_2 "rgba(167,139,250,1)"
accent_3 "rgba(244,114,182,1)"
danger "rgba(248,113,113,1)"
glass "rgba(15,19,38,0.56)"
glass_strong "rgba(12,15,30,0.74)"
taskbar_bg "rgba(24,28,34,0.96)"
border_soft "rgba(255,255,255,0.06)"
border_hover "rgba(255,255,255,0.22)"
surface_hover "rgba(255,255,255,0.08)"
taskbar_surface "rgba(255,255,255,0.025)"
taskbar_hover "rgba(255,255,255,0.05)"
taskbar_border "rgba(255,255,255,0.07)"
on_accent "rgba(8,33,28,1)"
border_focus "rgba(94,234,212,0.4)"
caret unset
selection unset
selection_fg unset
field_bg "rgba(21,26,31,1)"
field_border "rgba(63,70,77,1)"
field_border_focus unset
shadow "rgba(0,0,0,0.35)"
start_menu_bg "rgba(29,34,41,0.98)"
start_menu_border "rgba(255,255,255,0.12)"
start_menu_search_bg "rgba(21,26,31,1)"
start_menu_selected_bg "rgba(255,255,255,0.045)"
start_menu_selected_border "rgba(237,27,46,0.35)"
start_menu_selected_marker "rgba(237,27,46,1)"
toggle_track "rgba(255,255,255,0.12)"
control_thumb "rgba(255,255,255,1)"
slider_track "rgba(255,255,255,0.08)"
pill_bg "rgba(255,255,255,0.05)"
swatch_border "rgba(255,255,255,0.1)"
swatch_border_selected "rgba(255,255,255,0.6)"
settings_card_bg "rgba(255,255,255,0.025)"
lock_bg "rgba(4,5,7,1)"
lock_fg "rgba(247,247,250,1)"
lock_dim "rgba(168,173,186,1)"
lock_divider "rgba(76,82,92,0.6)"
lock_session_fg "rgba(219,222,230,1)"
switcher_bg "rgba(9,10,14,1)"
switcher_border "rgba(153,51,66,0.65)"
switcher_item_bg "rgba(23,26,31,1)"
switcher_item_border "rgba(255,255,255,0.13)"
switcher_fg "rgba(240,242,247,1)"
switcher_dim "rgba(153,158,168,1)"
switcher_icon_bg "rgba(26,28,33,1)"
switcher_selected_border "rgba(255,31,51,1)"
calendar_border "rgba(255,255,255,0.16)"
osd_border "rgba(255,255,255,0.12)"
screenshot_shade "rgba(0,0,0,0.36)"
screenshot_border "rgba(255,6,23,1)"
screenshot_fg "rgba(255,255,255,1)"
screenshot_label_bg "rgba(10,13,15,0.95)"
screenshot_label_border "rgba(255,255,255,0.2)"
battery_bg "rgba(5,10,10,0.28)"
battery_full "rgba(32,226,157,1)"
battery_low "rgba(250,204,65,1)"
battery_critical "rgba(245,75,85,1)"
battery_shimmer "rgba(110,255,200,1)"
desktop_fg "rgba(238,241,251,1)"
desktop_text_shadow "rgba(0,0,0,0.22)"
desktop_hover "rgba(255,255,255,0.06)"
desktop_selected "rgba(237,27,46,0.12)"
desktop_selection "rgba(237,27,46,0.15)"
desktop_selection_border "rgba(237,27,46,1)"
desktop_drop_border "rgba(237,27,46,0.8)"
desktop_dialog_bg "rgba(9,11,24,0.98)"
desktop_notice_bg "rgba(31,9,15,0.95)"
desktop_icon_start "rgba(64,166,168,1)"
desktop_icon_end "rgba(89,79,158,1)"
file_broken "rgba(239,68,68,1)"
file_folder_back "rgba(163,171,181,1)"
file_folder_front "rgba(184,191,201,1)"
file_document "rgba(148,163,184,1)"
file_document_lines "rgba(203,213,225,1)"
file_spinner "rgba(166,173,184,1)"
image_checker_dark "rgba(33,36,38,1)"
image_checker_light "rgba(43,46,48,1)"
image_crop_shade "rgba(0,0,0,0.58)"
image_crop_border "rgba(255,255,255,1)"
image_crop_grid "rgba(255,255,255,0.4)"
image_dialog_backdrop "rgba(0,0,0,0.65)"
pdf_page_shadow "rgba(0,0,0,0.35)"
pdf_page_border "rgba(0,0,0,0.15)"
pdf_loading "rgba(153,153,153,1)"
pdf_search_match "rgba(255,230,0,0.4)"
pdf_search_match_active "rgba(255,153,0,0.65)"
pdf_thumbnail_bg "rgba(242,245,250,1)"
pdf_thumbnail_shadow "rgba(0,0,0,0.3)"
pdf_search_shadow "rgba(0,0,0,0.4)"
pdf_dialog_backdrop "rgba(0,0,0,0.6)"
dialog_backdrop "rgba(0,0,0,0.18)"
shell_accent unset
shell_on_accent unset
shell_border_focus unset
window_close_fg "rgba(255,255,255,1)"
start_button_hover "rgba(255,255,255,0.035)"
start_button_indicator "rgba(255,255,255,0.5)"
polkit_backdrop "rgba(0,0,0,0.55)"
power_menu_backdrop "rgba(0,0,0,0.45)"

accent_2, accent_3, glass_strong and border_focus are compatibility keys retained by the reader and saver; current painters use the specific surface and control tokens above. scrollbar_thumb_active now overrides the hover/drag color; omitted, it follows the surface accent.

Sizes and styling

Numeric tokens accept 0–4096 unless constrained below. Fractions ending in _alpha or _opacity, and dialog_glyph_lift, accept 0–1.

Key Built-in default
font_size 13.0
radius 5.0
radius_md 7.0
radius_lg 10.0
title_size 13.5
chrome_height 46.0
chrome_control_gap 4.0
taskbar_title_size 12.5
taskbar_size 48.0
chip_gap 4.0
chip_width 220.0
start_button_gap 4.0
start_button_icon_size 42.0
button_font_size 12.5
caret_width 1.5
scrollbar_width 8.0
selection_alpha 0.35
field_radius 8.0
shadow_size 24.0
shadow_offset_y 8.0
start_menu_width 560.0
start_menu_max_height 600.0
start_menu_radius 14.0
start_menu_left_pad 2.0
start_menu_bottom_pad 6.0
start_menu_icon_left_pad 2.0
start_menu_icon_bottom_pad 6.0
settings_radius 8
settings_sidebar_radius 10
settings_card_radius 9
checkbox_radius 4
toggle_radius 5
toggle_thumb_radius 4
slider_track_height 5.5
slider_settings_track_height 11
slider_thumb_size 12
slider_settings_thumb_height 20
slider_thumb_radius 4
slider_track_grow 0.25
slider_track_tint_alpha 0.45
slider_fill_alpha 0.6
pill_active_alpha 0.16
pill_border_active_alpha 0.55
segmented_selected_alpha 0.15
swatch_radius 6
swatch_glow_alpha 0.8
dialog_badge_radius 16
dialog_badge_alpha 0.18
dialog_glyph_lift 0.3
dialog_title_size 26
dialog_subtitle_size 15
dialog_inset_radius 12
scrollbar_radius 3
scrollbar_rest_width 0.75
scrollbar_active_width 1.125
switcher_radius 24
switcher_item_radius 12
switcher_icon_radius 10
switcher_selection_radius 15
switcher_title_size 15
switcher_app_size 12
calendar_radius 9
calendar_opacity 0.98
osd_radius 10
osd_opacity 0.97
lock_wallpaper_opacity 0.24
image_checker_size 12
start_button_radius 6
mini_map_bg_opacity 0.91
mini_map_grid_alpha 0.065
mini_map_border_alpha 0.12
mini_map_window_alpha 0.55
mini_map_marker_alpha 0.12
mini_map_marker_border_alpha 0.85
mini_map_radius 4
app_text_size 13
app_heading_size 12
app_status_size 11.5
desktop_text_size 11.5
window_close_hover_alpha 0.85
button_disabled_alpha 0.5
button_hover_brightness 1.08
button_selected_alpha 0.6
button_selected_hover_alpha 0.7
Additional constraint Range
chrome_height 28–84
chrome_control_gap 0–24
chip_width 64–400
scrollbar_width 4–24
scrollbar_rest_width, scrollbar_active_width 0.25–1.125 times the configured width
image_checker_size 1–128

taskbar_height is an alias for taskbar_size. Layouts cap some dimensions to fit their available space. The scrollbar reserves room for its maximum width; slider_* keys control slider geometry while sharing the scrollbar feedback.

Strings

Key Built-in default Meaning
font "Manrope" Compositor's preferred proportional font family
mono_font "JetBrains Mono" Compositor's preferred monospace font family
start_button_icon "" Bundled Redi logo; otherwise an absolute image path

In Settings → Appearance → Start menu, Choose file… selects a PNG or SVG for the Start button logo and applies it immediately. Reset to default restores the bundled R logo. Both choices are saved with the theme.

IPC

RediWM has a JSON IPC over a Unix socket. Use it to script the compositor, inspect state, or drive it from tests. rediwm-msg is the friendly client, see rediwm-msg. Every command is in IPC Commands.

The socket

$XDG_RUNTIME_DIR/rediwm-<WAYLAND_DISPLAY>.sock, or whatever REDIWM_SOCKET says. It lives in a private directory (owned by you, no group/other access) and is created with umask 0177. If the directory isn't private the server refuses to start the IPC.

Wire format

UTF-8 JSON, one request per line, one response per line.

{"version":1,"id":1,"command":"windows"}
{"version":1,"id":2,"command":"move_cursor","params":{"x":100,"y":200}}
Field Rules
version required, the integer 1
command required, case-sensitive snake_case
params optional object
id optional, a non-negative integer or a string up to 256 bytes. Echoed back once the request parses. Parse errors have no id

Anything else is rejected: extra envelope fields, duplicate JSON keys, bare strings, {"query":...} / {"action":...} envelopes, PascalCase names and CLI aliases. There's no separate "query" vs "action" on the wire, both are just command.

Responses:

{"id":1,"Ok":{"Windows":[]}}
{"id":1,"Err":"InvalidRequest"}

Response tags are case-sensitive and different from command names. Clients should ignore unknown response fields. New commands show up in capabilities, and a breaking change would mean a new protocol version.

Try it with no tools at all:

echo '{"version":1,"command":"version"}' | socat - UNIX-CONNECT:$XDG_RUNTIME_DIR/rediwm-wayland-1.sock

Discovering things

rediwm-msg capabilities    # canonical command names
rediwm-msg describe        # params, kinds, protocol version

describe_ipc is the source of truth for parameter schemas. The code reference is src/ipc/protocol.zig and src/ipc/commands.zig.

Queries vs actions

Queries read state. Actions change something. Both use the same envelope. The split only matters in rediwm-msg (rediwm-msg action focus-window ... for actions that don't have a top-level subcommand).

Events

event_stream turns the connection into a feed. You get an acknowledgement, then newline-delimited tagged events until you disconnect.

rediwm-msg event-stream
rediwm-msg event-stream --events window_opened,window_closed
rediwm-msg event-stream --window 12
rediwm-msg event-stream --output DP-1

Raw params: {"window_id"?: n, "output"?: "name", "events"?: ["..."]}.

Events you can filter on:

Group Events
Windows window_opened, window_closed, window_changed, window_focused, window_moved, window_urgency_changed
Outputs output_added, output_changed, output_removed
Camera camera_changed
Input keyboard_layouts_changed, keyboard_layout_switched
Config config_loaded
Polkit polkit_prompt_opened, polkit_prompt_closed
Notifications notification_shown, notification_closed, notification_action
Launching launch_started, launch_matched, launch_timeout
UI widget_changed

state_snapshot is always delivered, whatever you filter. A window_id filter only affects window events. Event subscriptions are re-checked against the lock state, so you get nothing while the session is locked.

Waiting instead of sleeping

If you're scripting, don't sleep. Use the wait commands.

rediwm-msg wait window_mapped --timeout 5000
rediwm-msg wait window_closed --id 12
rediwm-msg wait-frame --output DP-1

wait_for takes a condition and a timeout (default 5000 ms) and returns the condition, elapsed ms and state. Raw example:

{"version":1,"command":"wait_for","params":{"condition":{"window_mapped":{"app_id":"foot"}},"timeout_ms":5000}}

Conditions:

Condition Params
menu_opened, menu_closed none
control_center_opened, control_center_closed none
power_menu_opened, power_menu_closed none
window_mapped optional id, app_id, title
window_closed id
window_focused optional id
window_geometry_settled id
output_frame optional output
catalog_published, wallpaper_presented none
notification_count optional count, app_name, summary
notification_closed id
notification_action id, optional action_key
launch_started, launch_matched, launch_timeout optional desktop_id (and window_id for matched)
widget_present, widget_absent path
widget_state path, field, equals
panel_settled panel

wait_for_frame blocks until the next frame commit on an output and returns the output, frame_seq and elapsed time. The CLI's wait takes a condition name plus --id/--output/--timeout. For conditions with richer params (app_id, title, path, ...), use --raw.

Automation (synthetic input and pixels)

Off by default. These commands are refused unless automation is on:

move_cursor, move_cursor_relative, pointer_button, click, scroll, key, key_press, type_text, drag, screenshot, dump_buffer, sample_pixels, pinch, swipe, click_widget, hover_widget.

Turn it on:

[ipc]
automation = true

or start with REDIWM_IPC_AUTOMATION=1. It's read once at startup, so you need a restart. When it's on, the compositor logs a warning, because any client of the socket can then type and take screenshots.

Security rules

  • Everything is refused with SessionLocked while the session is locked.
  • Sandboxed callers (Flatpak and friends, detected via SO_PEERPIDFD and .flatpak-info) need an explicit [[sandbox_allow]] with the ipc group. They fail closed, and the check is redone on config reload. Synthetic input and capture additionally need the automation group.
  • The socket is only reachable by your uid.
  • Virtual input never reaches the lock or auth UI.

Writing a client

Python is the easiest. This is basically what tests/ipc_client.py does:

import json, os, socket

path = f"{os.environ['XDG_RUNTIME_DIR']}/rediwm-{os.environ['WAYLAND_DISPLAY']}.sock"
s = socket.socket(socket.AF_UNIX)
s.connect(path)
f = s.makefile("rw")

def call(command, params=None, id=1):
    req = {"version": 1, "id": id, "command": command}
    if params is not None:
        req["params"] = params
    f.write(json.dumps(req) + "\n"); f.flush()
    resp = json.loads(f.readline())
    if "Err" in resp:
        raise RuntimeError(resp["Err"])
    return resp["Ok"]

print(call("windows"))
call("focus_window", {"id": 3})

For events, open a second connection, send event_stream, then keep calling readline().

Tips:

  • Use get_state when you need windows, outputs, camera and shell to agree. Separate queries can race.
  • Coordinates are layout coordinates, not per-output pixels.
  • Set a socket timeout. wait_for can take up to its own timeout to answer.
  • restart_shell drops your connection and every app. That's expected.

IPC Commands

Names are the wire names ("command": "..."). The CLI column is the rediwm-msg spelling. Run rediwm-msg describe for exact params. [auto] means it needs automation. "Action" in the CLI column means rediwm-msg action <name>.

Info

Command CLI What it does
version version build version
capabilities capabilities supported command names
describe_ipc describe protocol version, kinds, parameter schemas
get_runtime_info runtime compositor, wlroots, backend, renderer
get_config_status config effective config and reload status
reload_config reload reload the config file
get_performance_stats perf commit, paint and error counters
reset_performance_stats perf-reset zero them
get_panel_stats / reset_panel_stats Action panel paint and allocation counters
get_animations none live animations: site, value, velocity, target, settled, curve
set_anim_time Action --ms <N\|null> override animation time, null clears it

Windows

Command CLI Params
windows windows list toplevels
focused_window focused-window
get_window_debug window-debug <id> geometry, decoration, serials
get_window_rules window-rules <id> matched rules and effective properties
match_window_rules match-window-rules dry run: app_id, title, x11_class, x11_instance, backend, dialog
focus_window Action focus-window --id
close_window Action close-window [--id] no id closes the focused window
move_window_to Action move-window-to --id --x --y or --output
maximize_window maximize <id>
minimize_window minimize <id>
restore_window restore <id>
fullscreen_window fullscreen <id> [--output]
set_window_size none id, width, height, requests a client resize
set_window_zoom set-zoom <id> <pct>
undo none undo the last move, resize, zoom, pan or focus change
spawn Action spawn [--] CMD ARGS... argument vector, no shell
launch_app launch <desktop_id> by desktop file ID
stop_xwayland none disconnects the compositor-owned Xwayland

Outputs, camera, workspaces

Command CLI What it does
outputs outputs list outputs
set_output_config output-config <out> ... mode, transform, position, scale, enable. Applied and saved
workspaces workspaces there's one, the canvas (workspace_id = 1)
get_camera none position, bounds, zoom
set_camera / reset_camera none set_camera takes integer x, y
set_zoom none camera zoom, percent (a supported step)
get_state state atomic snapshot of windows, outputs, camera, shell

output-config flags: --width --height --refresh-mhz --x --y, --scale <1..3|auto>, --position auto, --transform <normal|90|180|270|flipped|flipped_90|flipped_180|flipped_270>, --enabled/--disabled, --primary/--no-primary. auto clears the override.

Inspecting the shell and scene

Command CLI What it does
get_shell_state shell-state [--output] panels, progress, taskbars
list_panels panels registered panels and open state
get_widget_tree widget-tree <panel> semantic widget tree of an open panel
get_input_state input-state pointer, focus, keys, buttons, grabs
hit_test hit-test <x> <y> [--output] what's at those layout coordinates
get_scene_tree scene-tree [--max-depth] scene node hierarchy
get_layer_surfaces layers layer-shell surfaces
get_text_input text-input input-method state and candidate placement, never the text
get_capture_state none active screen capture sessions
get_idle_state none idle state, deadlines, inhibitors

Panels and menus

Command CLI
open_start_menu Action open-start-menu
open_control_center Action open-control-center
open_power_menu Action open-power-menu
open_appearance none
close_panel close-panel <panel>
[auto] click_widget none, path, optional button, at
[auto] hover_widget none, path, optional at

Input

Command CLI Notes
[auto] move_cursor Action move-cursor --x --y [--output]
[auto] move_cursor_relative Action move-cursor-relative --dx --dy
[auto] pointer_button Action pointer-button --button --pressed Linux button codes
[auto] click Action click [--button] left by default
[auto] scroll Action scroll --dx --dy
[auto] key Action key --keycode --pressed Linux keycodes
[auto] key_press Action key-press --key named key or chord
[auto] type_text Action type-text --text
[auto] drag Action drag --from-x --from-y --to-x --to-y [--button]
[auto] pinch none phase begin/update/end, scale, dx, dy, rotation, fingers, cancelled
[auto] swipe none phase, dx, dy, fingers, cancelled
get_keyboard_layouts keyboard-layouts zero-based active index
switch_layout switch-layout <next\|prev\|index>

Screenshots and pixels

Command CLI Notes
[auto] screenshot Action screenshot --output, --window, --mode, --include-cursor, --path, --save. Raw params also take crop and crop_space (logical or device)
[auto] dump_buffer dump-buffer <target> targets: titlebar, skirt, start_menu, control_center, power_menu, taskbar. --id, --output
[auto] sample_pixels sample-pixels <x> <y> <w> <h> raw framebuffer pixels
stop_all_capture none ends every screen capture session

Prefer screenshot and dump_buffer over host grim when debugging. Host tools show host scaling and any window covering yours.

Waiting

wait_for (wait) and wait_for_frame (wait-frame). See IPC for the condition list.

Audio

Command CLI
get_audio_state Action get-audio-state
set_master_volume Action set-master-volume --volume 0..1
toggle_mute Action toggle-mute
set_app_volume Action set-app-volume --index N --volume 0..1
set_app_mute Action set-app-mute --index N --muted true\|false

Volumes are clamped to 0..1.

Notifications

Command What it does
get_notifications (notifications) active toasts, history, DND status
dismiss_notification id, optional reason
invoke_notification_action id, action_key
set_dnd enabled
clear_notifications clears closed history

Night light and idle

Command What it does
get_night_light (night-light) status and colour curves
set_night_light enabled and/or temperature (1700 to 10000), at least one
set_night_light_clock unix_seconds, override the clock (testing)
set_idle_config enabled, blank_after_seconds, suspend_after_seconds
advance_idle_time seconds, move the idle clock (testing)

Settings and appearance

These work without opening Settings.

Command Params and behaviour
get_services system services, raw systemd state, activation_us, total boot_us. First calls may say loading/analyzing, unknown times are null
set_service_mode service, mode: on, disabled, on-demand. Changes boot policy only, doesn't start or stop the unit. on-demand needs an existing activation trigger and disables boot enablement. deferred returns UnsupportedServiceMode. Static and masked units are read-only
get_sounds theme and events, with enabled/available flags and resolved files
play_sound event from get_sounds. Plays with /usr/bin/paplay, returns the PID, not "finished"
get_wallpaper selection, resolved and displayed paths, dimensions, loading and fallback status
set_wallpaper path: a wallpaper name or a file, "" restores the default. Decoding is async, poll get_wallpaper
get_theme theme tokens, theme file path (null if inline), dark mode. Colours are straight RGBA, 0 to 1
set_accent_color color: #RRGGBB or #RRGGBBAA
get_processes window-owning app processes grouped by PID, with window IDs, RSS and CPU sampled for about 200 ms. 100% is one logical CPU. Gone processes have null usage

set_wallpaper, set_accent_color and set_night_light save to the config by default. Pass "persist": false for a session-only change. If saving fails you get the error before anything changes live.

Service changes use systemd's interactive authorization and only return "accepted". Watch get_services.action_pending, raw state and status for the result.

Session

Command Notes
restart_shell restarts the compositor in place, disconnects all apps

Examples

rediwm-msg --raw '{"version":1,"command":"get_theme"}'
rediwm-msg --raw '{"version":1,"command":"set_accent_color","params":{"color":"#e05a47"}}'
rediwm-msg --raw '{"version":1,"command":"set_night_light","params":{"enabled":true,"temperature":4000,"persist":false}}'

rediwm-msg

Command line client for the IPC. It turns friendly subcommands into v1 JSON, sends them, and pretty prints the reply.

rediwm-msg [options] <command>
Option What it does
-s, --socket <PATH> socket path (default: REDIWM_SOCKET, else $XDG_RUNTIME_DIR/rediwm-$WAYLAND_DISPLAY.sock)
-t, --timeout <MS> request/response timeout
--raw [JSON] send a v1 JSON payload unchanged, from the arg or stdin
--json print the JSON reply instead of the readable version
-h, --help the full command list, always up to date

rediwm-msg raw [JSON|-] does the same as --raw.

Two kinds of subcommand

Most queries and a few actions are top level: rediwm-msg windows, rediwm-msg maximize 12. The rest are under action: rediwm-msg action focus-window --id 12. --help shows which is which. Wire-name aliases like get-state, get-perf, list-panels also work.

doctor

rediwm-msg doctor

Checks the socket and the environment and tells you what's off. Run this first when nothing works. It runs even without a compositor to talk to.

Recipes

See what's open

rediwm-msg windows
rediwm-msg focused-window
rediwm-msg state --json | jq '.Ok'

Window management

rediwm-msg action focus-window --id 12
rediwm-msg action move-window-to --id 12 --x 200 --y 100
rediwm-msg action move-window-to --id 12 --output DP-2
rediwm-msg fullscreen 12
rediwm-msg set-zoom 12 80
rediwm-msg action close-window            # focused one

Launch things

rediwm-msg launch org.gnome.Nautilus.desktop
rediwm-msg action spawn -- foot -e htop

Displays

rediwm-msg outputs
rediwm-msg output-config DP-1 --scale 1.5
rediwm-msg output-config DP-1 --width 2560 --height 1440 --refresh-mhz 144000
rediwm-msg output-config DP-2 --x -1920 --y 0
rediwm-msg output-config DP-2 --disabled
rediwm-msg output-config DP-1 --scale auto --position auto

Debug a window rule

rediwm-msg window-rules 12
rediwm-msg match-window-rules --app-id firefox --title "Picture-in-Picture"

Watch events

rediwm-msg event-stream --events window_opened,window_focused

Scripted tests (needs automation on)

rediwm-msg action spawn -- foot
rediwm-msg wait window_mapped --timeout 5000
rediwm-msg action key-press --key ctrl+shift+t
rediwm-msg action type-text --text "hello"
rediwm-msg wait-frame
rediwm-msg action screenshot --save /tmp/shot.png
rediwm-msg sample-pixels 100 100 1 1

Poke at the UI

rediwm-msg action open-start-menu
rediwm-msg panels
rediwm-msg widget-tree start_menu
rediwm-msg dump-buffer taskbar
rediwm-msg close-panel start_menu

Audio and keyboard

rediwm-msg action set-master-volume --volume 0.4
rediwm-msg action toggle-mute
rediwm-msg switch-layout next

Anything without a subcommand

rediwm-msg --raw '{"version":1,"command":"get_theme"}'
echo '{"version":1,"command":"set_dnd","params":{"enabled":true}}' | rediwm-msg --raw

Exit behaviour

Bad arguments print an error and exit 1. A compositor Err is printed and the exit code is nonzero. With no socket it tells you to set REDIWM_SOCKET or XDG_RUNTIME_DIR and WAYLAND_DISPLAY.

Protocols and Sandboxing

Wayland protocols

On top of xdg-shell, layer-shell and Xwayland:

Area Protocols Works with
Displays wlr-output-management-v1, xdg-output-v1 wlr-randr, kanshi, nwg-displays
Window lists wlr-foreign-toplevel-management-v1, ext-foreign-toplevel-list-v1 docks, waybar, rofi/fuzzel, wlrctl
Capture wlr-screencopy-v1, ext-image-copy-capture-v1 grim, wf-recorder, OBS, xdg-desktop-portal-wlr
Locking and idle ext-session-lock-v1, ext-idle-notify-v1, idle-inhibit-v1 swaylock, gtklock, swayidle
Remote input virtual-pointer-v1, virtual-keyboard-v1 wayvnc, KDE Connect, wtype
Clipboard wlr-data-control-v1, ext-data-control-v1, primary selection wl-clipboard
Input text-input-v3, input-method-v2, relative-pointer-v1, pointer-constraints-v1, keyboard-shortcuts-inhibit-v1, pointer-gestures-v1, cursor-shape-v1 fcitx5, IBus, games, virt-manager
Workspace ext-workspace-v1 one canvas workspace shared by all outputs
Window metadata xdg-toplevel-tag-v1, content-type-v1, xdg-activation-v1 window rules, content hints, activation
Colour color-management-v1, color-representation-v1 whatever the renderer supports
Presentation tearing-control-v1, drm-lease-v1 opt-in fullscreen tearing, VR headsets
Rendering fractional-scale-v1, viewporter, single-pixel-buffer-v1, linux-dmabuf-v1, linux-drm-syncobj-v1, presentation-time

Things worth knowing

  • Output changes from clients (wlr-randr, kanshi) are saved just like ones made in Settings.
  • Workspace: the canvas is advertised as one workspace. You can't create, remove or switch workspaces through the protocol. Window IPC reports workspace_id = 1, plus tag, description and content_type when the client sets them. [[window_rules]] can match tag with the same globs as app_id.
  • Content type hints (photo, video, game) don't change idle or focus policy.
  • Colour: follows the renderer. Pixman gives colour feedback without parametric image creation, GPU renderers advertise what wlroots can convert. Output stays SDR. No HDR modes or ICC loading.
  • Tearing: [compositor] allow_tearing = true honours async hints from focused fullscreen clients. If an output can't do it, that output falls back to synchronized presentation until it's recreated. Suppressed while locked.
  • DRM leases: DRM backends only, physical non-desktop outputs only. Revoked on lock or auth. Private capture outputs are never offered.
  • Session lock clients: a client ext-session-lock is treated as a real lock. If the client dies the session stays locked.
  • Remote input: virtual pointer and keyboard can't touch the lock or auth UI.
  • Pointer lock: active only when the client has both pointer and keyboard focus.
  • Shortcut inhibit (VMs, remote desktops) blocks the switcher and screenshot shortcuts. Hardware keys, VT switching and open panels still win. Super+Escape takes shortcuts back.

Sandboxed apps

Clients connecting through wp_security_context_v1 (Flatpak etc.) only see the safe Wayland globals. Privileged ones are hidden, and guessing the name of a hidden global is a protocol error. Nested security contexts are fatal.

Grant access per app in the config:

[[sandbox_allow]]
app_id = "com.obsproject.Studio"   # exact match on the security-context app id
engine = "org.flatpak"             # optional, default matches any engine
allow  = ["capture"]

Groups:

Group Unlocks
capture screencopy and image capture
windows foreign toplevel lists, workspace
clipboard data control
input virtual pointer and keyboard
input_method input method
outputs output management, DRM leasing
lock session lock
layer_shell layer shell
idle idle notify
ipc the IPC socket
automation synthetic input and pixel reads over IPC

On reload, Wayland grants apply to new connections only (already bound globals stay bound until the app reconnects). IPC grants apply immediately. The greeter hides all of these.