Skip to content

kawa: support layer shell surfaces - #17

Merged
DeedleFake merged 5 commits into
fix-tile-bgscale-xwaylandfrom
layer-shell
Oct 1, 2026
Merged

DeedleFake merged 5 commits into
fix-tile-bgscale-xwaylandfrom
layer-shell

Conversation

@DeedleFake

@DeedleFake DeedleFake commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Why

kawa advertises zwlr_layer_shell_v1, but onNewLayerSurface was a panic("Not implemented."), so the first panel, wallpaper, notification daemon or launcher to connect took the whole session down. swaybg alone did it: it sent set_exclusive_zone(-1) and commit(), and kawa died with panic: Not implemented. at layers.go:20.

Scope

Each output keeps its layer surfaces in Output.Layers, one list per layer, and caches the area they leave for windows in Output.usable. Arrangement follows wlroots' scene helper and sway. It starts from the output minus kawa's status bar strip and places surfaces with an exclusive zone first, from overlay down to background, before the rest. Each mapped surface takes its zone off the remaining area. Tiling, centering, the New box and toplevel popups now stay inside that area. The wallpaper from -bg still fills everything below the bar.

Layer surfaces are drawn background, bottom, windows, top, overlay, then every layer popup, then the status bar. Hit testing uses the same order. Layer popups are unconstrained to the output minus the bar. A surface with no output goes on the output under the cursor. When its output is removed, the surface is closed.

Keyboard: a mapped exclusive surface in top or overlay takes the keyboard and keeps it until it unmaps or gives it up. on_demand surfaces get the keyboard when clicked, and clicking a window takes it back. Afterwards, focus returns to the window that had it, or the topmost window if that one is gone. If there is no window, focus is cleared.

This uses the bindings from DeedleFake/wlr#12, which is merged, and pins wlr to master at 8832710.

Tradeoffs

  • kawa's own status bar is drawn above every layer, overlay included, and keeps its strip. Layer zones are taken off what's left, so a top panel like waybar sits just below the bar. Clicks on the bar still open kawa's menus.
  • Layer popups are held to the visible area rather than the usable area. Otherwise a panel's menu, which sits inside the panel's own exclusive zone, would have nowhere to go.
  • The protocol only lets top and overlay surfaces take the keyboard exclusively. An exclusive surface in bottom or background is treated as on_demand.
  • Popups still have no grabs, the same as window popups today.

Blast Radius

The change is limited to layer surfaces, the usable area and focus handoff. With no layer clients, usable is the same as the old tiling bounds, so window placement doesn't change. focusView returns early only while an exclusive layer surface is mapped.

Verification

go build ./... and go vet ./... pass on every commit against wlroots 0.20.2. I ran each client against the new build in a nested X11 session and checked its WAYLAND_DEBUG log and a screenshot:

  • swaybg got configure(1, 1024, 768).
  • waybar asked for set_exclusive_zone(30) and got configure(3, 1024, 30). Tiled windows moved down to y=70, and after waybar was killed they moved back to y=40.
  • waybar's GTK menu got xdg_popup.configure(31, 16, 138, 86) and was drawn above the panel. Clicking an item worked.
  • mako, started with a nil output, was placed and drawn above a window.
  • fuzzel (set_keyboard_interactivity(1)) got wl_keyboard.enter and kept the keys even after a click on the terminal. After Escape, typing reached the terminal again.
  • On two outputs, a gtk-layer-shell bottom panel got focus on click and gave it back when the window was clicked. Its combo popup was drawn above the window. A toplevel menu flipped to stay above the panel's zone.
  • Destroying an output sent closed() to its layer surfaces, and kawa stayed up.

The verify-kawa core flow also passed: boot, the registry, the main menu, New, Tile, both status bar menus and -bg.

@DeedleFake
DeedleFake added this pull request to stack #15 October 1, 2026 19:30
@DeedleFake
DeedleFake merged commit 8b657a2 into master Oct 1, 2026
2 checks passed
@DeedleFake
DeedleFake deleted the layer-shell branch October 1, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant