Skip to content

feat: GNOME support via a transparent click-through overlay backend - #17

Merged
dahui merged 2 commits into
mainfrom
fix/gnome-overlay-backend
Aug 5, 2026
Merged

feat: GNOME support via a transparent click-through overlay backend#17
dahui merged 2 commits into
mainfrom
fix/gnome-overlay-backend

Conversation

@dahui

@dahui dahui commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #16 — on GNOME the drawer came up as a small unusable box in the middle of
the screen.

The drawer anchors itself with the layer-shell protocol (zwlr_layer_shell_v1),
which is a wlroots extension, not part of wayland-protocols. KWin, Hyprland
and Sway implement it; GNOME's Mutter never has. We called InitForWindow
without a support check, and the failure is silent: the library logs one
G_LOG_LEVEL_WARNING and returns, then every SetLayer/SetAnchor/SetMargin/
SetMonitor/SetKeyboardMode warns once and no-ops. Nothing aborts. Since the
top+bottom anchors were the only thing supplying a height, the window collapsed.

This is not a library-version problem and not a "GNOME doesn't support Wayland"
problem, and no package can fix it — gtk4-layer-shell is the client side and
is already a package dependency; the protocol has to come from the compositor.

Adds a third backend selected automatically when layer-shell is unavailable: a
fullscreen transparent window with the drawer against the right edge, its input
region restricted to the drawer so everything outside is click-through and the
rest of the desktop stays usable. Core Wayland gives a client no way to position
its own window, so fullscreen is what makes edge placement possible at all.

Changes

  • internal/gui/overlay — new backend (fullscreen, transparent,
    click-through) implementing the existing 5-method Backend interface.
  • internal/panelgeom — new pure package for the panel rectangle and slide
    interpolation, with invariant tests. Picked up automatically by PURE_PKGS.
  • gui.go — three-branch backend selection. layerShellUsable() checks the
    GDK backend before calling IsSupported(), which asserts on a non-Wayland
    display and would otherwise log assertion 'GDK_IS_WAYLAND_DISPLAY' failed at
    CRITICAL in every X11 session.
  • layershell.go — stop logging backend mode=layer-shell unconditionally.
    It reported success even when init had failed, which is the single most
    misleading line in the diagnostic path and why Creates a small window at the center of the screen that cannot be interacted with. #16 looked like a rendering bug.
  • controls.go / tdp.go — three identical ScrolledWindow setups replaced
    by one newDrawerScroll() with SetMinContentHeight. A GtkScrolledWindow
    reports a minimum height of 0 and SetVExpand only distributes surplus, so
    with nothing sizing the window from outside the drawer collapses. Deliberately
    not SetPropagateNaturalHeight(true) — that trades no default size for a bad
    one (the custom view would request more than the screen height).
  • Docs — a GNOME support section (why the workaround exists, how it works,
    what is degraded), plus troubleshooting for journalctl --user: ours is a
    systemd user unit, and sudo journalctl -u z13gui prints -- No entries --,
    which reads as though the program never ran. That is what sent the reporter
    down the wrong path.
  • CLAUDE.md — records the "never call into gtk4-layer-shell without checking
    IsSupported()" rule and the new backend.

Testing

make build, make fmt-check, make lint (0 issues), make test (11 packages),
make race all pass.

Verified on hardware (KDE, using GDK_BACKEND=x11 to force the same
"no layer surface" path GNOME takes):

  • Backend selection both ways: GDK_BACKEND=x11backend mode=overlay;
    native Wayland → backend mode=layer-shell protocolVersion=4, unchanged.
  • Geometry panel={Y:80 H:1440} on a 2560x1600 output — 5% margins, full height.
  • Positioning fix confirmed by measurement. GtkFixed allocates children
    their natural size and SetSizeRequest is only a minimum, so the panel came
    out 343px wide against a 320px request (CSS border/padding) and hung 23px past
    the screen edge, clipping the second column of every row. Positioning now
    derives from the allocated width: x=2217 w=343 → right edge exactly 2560.
  • Focus-loss dismiss fired on its own (overlay: dismissing on focus loss).
  • No new GTK warnings: the two GtkGizmo slider warnings appear identically on a
    pre-change baseline binary, so they are pre-existing.
  • The panelgeom tests fail when the width clamp is mutated, i.e. not vacuous.
  • mkdocs build --strict passes; verified id="gnome-support" exists in the
    generated HTML and all five cross-links resolve.

Not verified — needs a real GNOME session. KWin is not Mutter:

  • Click-through. The call succeeds without error, but xdotool getmouselocation
    resolves to a compositor container under XWayland and xwininfo does not expose
    the input shape, so neither could confirm it.
  • Whether Mutter hides the top bar while the drawer is open, and whether it
    appears in Alt-Tab. Both are documented as "may". If the top bar behaviour is
    objectionable the fallback is a monitor-sized non-fullscreen window — at exactly
    monitor size the compositor's own placement lands it correctly, so positioning
    is still not needed. One-line change.
  • Scaling. Under GDK_BACKEND=x11 GTK reports scale 1, so the drawer renders at
    343 physical px and looks small; on GNOME Wayland it should get the compositor
    scale natively.

Checklist

  • make build passes
  • make lint passes
  • go test ./internal/theme/ -v passes
  • Documentation updated if needed

@dahui
dahui merged commit 1021de3 into main Aug 5, 2026
2 checks passed
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.

Creates a small window at the center of the screen that cannot be interacted with.

1 participant