<feed xmlns='http://www.w3.org/2005/Atom'>
<title>srdwm/crates/wayland/src/protocols.rs, branch main</title>
<subtitle>Cross-platform window manager written in Rust.
</subtitle>
<id>https://srdusr.com/git/srdwm/atom?h=main</id>
<link rel='self' href='https://srdusr.com/git/srdwm/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/'/>
<updated>2026-07-26T23:33:00+00:00</updated>
<entry>
<title>Reach GTK4's window buttons too, and speak the decoration protocol GTK knows</title>
<updated>2026-07-26T23:33:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2026-07-26T23:33:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=3c47912ae0a2b81d06e4e9101b5b4e2f1e2997d9'/>
<id>urn:sha1:3c47912ae0a2b81d06e4e9101b5b4e2f1e2997d9</id>
<content type='text'>
Two findings from reading what other projects do, and then measuring this
machine rather than trusting the reading.

GTK has never implemented xdg-decoration, so a compositor that advertises
only that protocol is invisible to every GTK client on the decoration
question. What GTK does implement is KDE's older
org_kde_kwin_server_decoration - confirmed by reading libgtk-4's own symbol
strings, where the manager, the mode enum and the default-mode handler are
all present, and absent from libgtk-3. That is the channel a KDE session
uses. srdwm now advertises it alongside xdg-decoration, with both answering
from the same policy (theme.default_decorated, theme.force_server_side) so a
client is told the same thing whichever it asks through.

Measured what that actually buys, with WAYLAND_DEBUG on a real GTK4 client:
it binds the manager and receives default_mode(2) = Server, and then never
creates a decoration object for its window. So it changes nothing for a GTK
application's own header bar, and it is kept because it is the correct thing
to advertise and because clients that do honour it - Qt and KDE's own --
now get server-side decoration from srdwm instead of nothing.

The second finding is the one that fixes what was reported. GTK3 and GTK4
put their window buttons under different CSS selectors, and the generated
stylesheet named only GTK3's. A diagnostic rule proved it both ways: a flat
colour reached Nemo (GTK3) through `headerbar button.titlebutton` and
gnome-calculator (GTK4) through `windowcontrols button`, and neither
selector reached the other toolkit. Every style is now written for both, so
a GTK4 application is styled rather than silently skipped. `headerbar`
itself works in both, so the titlebar block needed no split.

Verified on screen: gnome-calculator, a GTK4/libadwaita application, now
draws its header bar in srdwm's own titlebar colour with srdwm's text
colour, where before it kept its theme's.

Also worth writing down, because it bounds what any of this can achieve: an
application's header bar is its own widget. No protocol removes it. GTK_CSD=0
does not, the KDE protocol does not, and neither does forcing server-side
decoration - that only adds a second titlebar above the first. What a
compositor can do is make the two look like one, which is what this does.
</content>
</entry>
<entry>
<title>Checkpoint: preserve all uncommitted rust-rewrite worktree work</title>
<updated>2025-02-15T12:56:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2025-02-15T12:56:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=0a4c4b5941fe982ccb3d3175e26d9d83f0025ffd'/>
<id>urn:sha1:0a4c4b5941fe982ccb3d3175e26d9d83f0025ffd</id>
<content type='text'>
Safety commit before reconciling this worktree with main, which has
diverged with its own separate fixes today. Nothing here is reviewed
or curated yet - this exists purely so none of this work can be lost
to a git operation, disk issue, or worktree cleanup while that
reconciliation happens.
</content>
</entry>
<entry>
<title>Add temporary diagnostics for two live-reproduced bugs</title>
<updated>2025-02-11T12:00:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2025-02-11T12:00:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=b1d69a552cdcc7370c4befd42ef2111c8b367c46'/>
<id>urn:sha1:b1d69a552cdcc7370c4befd42ef2111c8b367c46</id>
<content type='text'>
1. A popup's xdg_popup.grab (Firefox's own right-click menu, concretely)
   receiving zero pointer input at all - no hover highlight, no click
   effect, not even dismiss-on-miss - logs whether grab_popup actually
   succeeds, since a silent failure there would explain exactly this.

2. srd dispatch activate_workspace returning {"ok":true} without ever
   changing the current workspace, confirmed via a raw socket request
   bypassing the CLI entirely. switch_workspace's own logic reads
   correct; logs its actual inputs/state to find out why the real
   process disagrees with it.

Remove once both are resolved.
</content>
</entry>
<entry>
<title>Fix layer surfaces spuriously hiding/re-showing on their own realization</title>
<updated>2025-02-06T07:28:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2025-02-06T07:28:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=ef2eff8f654884406c8989baf1ad345a2da43a58'/>
<id>urn:sha1:ef2eff8f654884406c8989baf1ad345a2da43a58</id>
<content type='text'>
sync_layer_visibility could not tell a real hide (null-buffer commit on
an already-visible surface) apart from a layer-shell client's ordinary
realization sequence (commit with no buffer -&gt; configure -&gt; ack-commit
with no buffer again -&gt; attach real content): both look like "committed,
no buffer" from has_buffer alone. Every layer surface's first realization
was spuriously unmapped and immediately remapped, doubling LayerMap
arrange() passes on every single popup open.

Live-reproduced via an AGS peer session: a full-monitor click-outside-to-
close popup surface came back from a hit-test with geometry wider than
the real output after several open/close cycles on a wl_surface GTK had
reused across role destroy/recreate, and sat in the Top layer above every
real window with no input region set - silently swallowing clicks meant
for windows, dropdowns, and CSD title bars alike.

layer_surfaces_shown_once now gates the hide path on a surface having
actually shown a buffer at least once, and is cleared in layer_destroyed
so a reused wl_surface's next role starts clean rather than inheriting
the previous role's flag.
</content>
</entry>
<entry>
<title>Accumulate wayland-crate additions: capture rendering, focus/Space sync, VT resume, plumbing</title>
<updated>2024-12-24T18:44:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2024-12-24T18:44:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=3d73ed0f057a555ded67ad58dbe02b36cd4d2d1f'/>
<id>urn:sha1:3d73ed0f057a555ded67ad58dbe02b36cd4d2d1f</id>
<content type='text'>
Bundles the remaining wayland-crate changes built up here,
touching both backends (udev and winit) and the shared input/rendering
code:
- udev/capture.rs: off-screen Pixman render of an arbitrary (not
  necessarily on-screen) workspace's window content to a PPM file --
  what crates/core's capture-request queue drives, for a workspace
  switcher's thumbnail previews. wlr-screencopy structurally can't do
  this (it can only see what an output is presenting), which is why
  this exists as a separate render path rather than reusing it.
- input::focus_window now also raises the window in smithay's own
  Space, not just core's stacking order - Space is what actually
  renders on top and what pointer hit-testing reads, so any focus path
  that skipped this (an IPC "focus" dispatch, concretely) left a
  window genuinely focused while still rendering, and receiving
  clicks, underneath whatever was already topmost. Both backends'
  poll loops now re-sync this after any IPC mutation.
- udev/session.rs's VT-switch resume fix (drains a stale pending page
  flip before reasserting CRTCs) already has its own earlier, cleanly
  isolated commit - not duplicated here.
- Assorted decoration/cursor/rounded-corners/output-management/
  screencopy/XWayland changes and their cross-backend wiring.

Coarser than the repo's usual one-purpose-per-commit convention,
deliberately - see the core-crate sweep commit's own message for why.
</content>
</entry>
<entry>
<title>Fix doc-comment file references left stale by today's six module splits</title>
<updated>2024-08-03T18:07:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2024-08-03T18:07:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=35a28a257644483495ac2bd6a5fb1e109e8c1f26'/>
<id>urn:sha1:35a28a257644483495ac2bd6a5fb1e109e8c1f26</id>
<content type='text'>
~17 comments across the codebase still pointed at udev.rs/winit.rs/
state.rs by their old flat-file names after those became udev/,
winit/, state/ directories - found while auditing what this work
rushed, since the split verification (function/struct-name diffing,
full test suite) checked structural correctness but never comment
accuracy. Updated each to either the specific new file (e.g. "see
state.rs's REPEAT_DELAY" -&gt; "see state/mod.rs's REPEAT_DELAY",
"udev.rs's monitors()" -&gt; "udev/platform.rs's monitors()") or the bare
module name where the reference was already generic ("the udev/winit
backends", not a specific location).
</content>
</entry>
<entry>
<title>Rounded corners on udev/Pixman backend, opt-in and off by default</title>
<updated>2024-07-09T12:43:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2024-07-09T12:43:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=d2952af18b907a5b18fccd26468a74aabe49bb2f'/>
<id>urn:sha1:d2952af18b907a5b18fccd26468a74aabe49bb2f</id>
<content type='text'>
CPU-side rounded corners for the software-only udev/Pixman renderer,
which has no shader stage to hook the existing GLES version into.
Reads a window's own committed wl_shm buffer, punches premultiplied-
alpha holes into the four corner regions, and hands the masked copy
to MemoryRenderBuffer - the same path already used for titlebar/
border/shadow bitmaps, so it composites through the ordinary unmasked
path and the corners genuinely disappear rather than being painted
over.

Cached per window, invalidated by a per-commit content_epoch counter
rather than rebuilt every frame, so an idle window costs nothing once
masked. general.rounded_corners now defaults per backend instead of
one global true: on for GLES/winit (a real GPU shader, no measurable
cost), off for udev/Pixman (an untested-on-real-hardware CPU cost for
constantly-repainting clients) - WindowManager.rounded_corners_enabled
is Option&lt;bool&gt; so the backend can tell "unset" from "explicitly off".
</content>
</entry>
<entry>
<title>layer-shell: recompute the exclusive-zone reservation on unmap, not just on commit</title>
<updated>2024-05-30T23:15:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2024-05-30T23:15:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=ae056d17d137463b70f34862b9e33a9813c4b381'/>
<id>urn:sha1:ae056d17d137463b70f34862b9e33a9813c4b381</id>
<content type='text'>
ensure_layer_initial_configure (state.rs) already recomputes the usable
monitor rect when a layer surface's exclusive zone changes, but only from
the commit pre-hook - a surface that goes away without a final commit
(zwlr_layer_surface_v1's destroy path, layer_destroyed here) never ran that
check. unmap_layer's own zone change went unnoticed.

Found live by the AGS peer session: unmapping the bar for fullscreen logged
visible=false immediately, but `srd monitors` kept reporting the bar's old
reserved_top for as long as fullscreen lasted. Harmless there only because
toggle_fullscreen targets full_geometry, which ignores the reservation
outright - but wrong for anything that reads the reserved/usable rect while
a bar is unmapped without a clean exit (a crash, not just AGS's cooperative
fullscreen hide). Same zone_before/zone_after diff ensure_layer_initial_
configure already uses, run around unmap_layer instead of arrange().

Verified: cargo build --workspace, cargo clippy -p srdwm-wayland (0 new
warnings), cargo test -p srdwm-core (111/111).
</content>
</entry>
<entry>
<title>Fix decoration drift during animated transitions; checkpoint IPC/global-menu/output-management work</title>
<updated>2024-05-30T14:10:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2024-05-30T14:10:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=1c175642d073689ca11b9252411ea5f8446007d0'/>
<id>urn:sha1:1c175642d073689ca11b9252411ea5f8446007d0</id>
<content type='text'>
Border/titlebar decoration was built from Window.geometry (the animation's
final target) in both wayland backends' render loops, while sync_geometry
already draws a window's actual content at window_anims' interpolated rect
during any maximize/fullscreen/open-slide tween. Border and content read two
different rectangles for the whole transition, so the border visibly
detached from the window it was outlining - reported as "borders aren't
flush." Both udev.rs and winit.rs now read the same animated rect for
titlebar placement, border-strip placement, and the occlusion test against
later windows in stacking order. Verified: cargo build --workspace, cargo
clippy (0 new warnings), cargo test -p srdwm-core (111/111).

Also checkpoints substantial protocol/IPC work from prior sessions that had
accumulated uncommitted: gtk-shell1 support (gtk_shell.rs, the vendored
gtk-shell.xml, xwayland.rs's X11-side mirror) backing the global app menu;
zwlr_foreign_toplevel_manager_v1 (foreign_toplevel.rs) broadcasting distinct
maximized/minimized/fullscreen/activated state per window; output_management
(ext-output-management + layer-shell exclusive-zone reservation tracking);
workspace.rs and context_menu.rs; a Unix-socket IPC crate (platform/src/
ipc.rs) and a `srd` control-CLI crate (crates/ctl); xkb_config.rs; and a
theme module (core/src/theme.rs). A peer session working the AGS shell
concurrently verified several of these live against a running srdwm: the
global menu rendering a real app's File/Edit menu over gtk-shell1, and
foreign-toplevel correctly reporting maximized and fullscreen as independent,
non-simultaneous states with the geometry each implies (maximize stops at a
reserved top bar and past a dock; fullscreen reaches the true monitor edge).
</content>
</entry>
<entry>
<title>Draw a cursor, handle the lid, and everything a real config needs</title>
<updated>2024-05-13T22:42:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2024-05-13T22:42:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/srdwm/commit/?id=dd31bf5ac2a692617d478478d36c733586b93cf8'/>
<id>urn:sha1:dd31bf5ac2a692617d478478d36c733586b93cf8</id>
<content type='text'>
Groundwork for actually daily-driving this: porting the user's Hyprland
config exposed what srdwm couldn't yet express, and testing on a bare TTY
exposed something worse.

A visible mouse cursor. Nothing drew a pointer at all - on a bare TTY the
mouse was simply invisible. It hid because the nested backend runs inside
another compositor, which draws a cursor over srdwm's window; only the DRM
backend, i.e. the actual session path, was affected. A built-in arrow is now
composited above everything on the output the pointer is on. It's a
reviewable ASCII bitmap rather than an XCursor theme: a cursor that is always
present beats a prettier one that sometimes isn't, the same reasoning as
decoration.rs's font fallback. Client-set cursor surfaces and named shapes
are still not rendered, so an app asking for an I-beam gets the arrow.

Lid switch. libinput switch events are handled and surfaced to config as
srd.on("lid_closed"/"lid_open", fn), so closing the lid can lock and suspend
instead of doing nothing.

Config-driven additions, each needed by a binding in the ported config and
none of which existed: fullscreen (Window.fullscreen was a dead field --
declared, never read or written), directional window move that swaps with
the neighbour and reorders the stack so tiling follows, focus cycling,
modifier+drag to move/resize anywhere in a window rather than only by the
titlebar, modifier+scroll to change workspace, and 8 XF86 media/power
keysyms taken from the system's own XF86keysym.h. The keysym tables are
hand-maintained in both directions and a key missing from either fails
silently, so a round-trip test now covers every one the configs bind.

Verified in the QEMU VM: a bare-TTY screendump shows a recognisable arrow at
the pointer position (113 white fill + 58 black outline pixels at screen
centre, where the pointer starts).
</content>
</entry>
</feed>
