| Age | Commit message (Collapse) | Author | Files | Lines |
|
Reported twice, as two complaints: windows do not remember their size or
position across a close or a reboot, and windows spawn stacked on one side
with no smart placement. One bug.
`add_window` looks the store up by app_id. A Wayland toplevel role exists
before its client sends set_app_id, so at the moment srdwm placed a window
the app_id was the empty string, every lookup missed, and every window fell
through to the cascade - which is exactly what "they all open on top of
each other" looks like. The store was being written correctly the whole
time and read at the one moment it could not match.
The lookup now runs again the instant a real app_id arrives, which is still
before the client's first buffer, so nothing is drawn in the wrong place
first. It only moves a window still sitting where the cascade put it: a
rule's explicit geometry, a maximize, a dialog's centring and a client's own
committed size are each more specific than "wherever I last left this app",
and a test asserts none of them is overridden.
A second bug sat underneath the first and only appeared once it was fixed:
the position came back and the size did not, which is stranger than nothing
being restored. The backend keeps its own copy of "this size is only a
guess" (provisional_size) and adopt_provisional_size reads that one rather
than the core flag, so the client's next commit overwrote the size that had
just been restored. Cleared with the same call.
Verified end to end in a nested compositor, driving a real edge-drag with
the virtual-pointer tool:
seeded store 400,300 500x400 -> opened at exactly 400,300 500x400
dragged the right edge -> 646 wide, store rewritten to 646 on release
closed and reopened -> 400,300 646x400
Before this the same first step opened at 30,30 800x600.
Also: window_memory::save_all's nested guard now allows a write when the
instance was given its own state directory (SRDWM_STATE_PATH or
XDG_STATE_HOME). The blanket refusal added earlier kept the owner's store
safe but made the feature impossible to test without pointing a test
compositor at the real desktop, which is how this went unverified in the
first place.
|
|
The guard added earlier tonight asked "is WAYLAND_DISPLAY or DISPLAY set".
Both Wayland backends call set_var("WAYLAND_DISPLAY", ...) on themselves the
moment they bind their own socket, so after startup that question answers
"yes" for a real udev session too. Every publish on the config-reload path
runs after that point, which means a live session that reloaded its config
would have stopped publishing its own GTK settings - the exact opposite of
what the guard is for. It also treated srdwm-x as nested, because an X11
session naturally has DISPLAY set, even though srdwm is that display's
window manager and not a client of anything.
Nestedness is now read once, at startup, before any backend is up, and
only the Wayland backend can be nested. A test pins the second half.
The same reasoning applies to window_memory::save_all, which had no guard
at all: a nested instance shares HOME with the session it runs inside, so
dragging a test window would overwrite where that application opens in the
real session - a 1280x800 test window's position applied to a 3840x1080
desktop. Loading stays unconditional and deliberate: honouring what a real
session remembered is right, writing back over it is not. That side reads
srdwm_wayland::running_nested, recorded by connect at the moment it picks
the winit backend, since the environment can no longer be asked afterward.
Verified: a nested run with a scratch config left both the stylesheet and
window-memory.json untouched (md5 before and after, and no test window's
app-id in the store).
|
|
An earlier cleanup deleted five of them from window-memory.json by hand and
they came back within minutes. The reason is that a running compositor holds
the whole table in memory and save_all writes all of it back on the next
window close, so a hand-edited file cannot survive a running session.
Filtering on load is the only point where the fix sticks.
remove_window already refuses to record a size the client never chose, so
nothing new is captured this way; this clears what was written before that
landed. Those entries are self-perpetuating - a remembered size makes the
next launch non-provisional, which forces the client to that size rather
than asking it to pick, which writes the same value back on close - so an
affected app can never escape on its own.
A window genuinely sized exactly 800x632 loses its remembered size once and
gets it back at the next real resize or close. Two tests cover the exact
match and that sharing only one dimension is not enough.
531 tests pass, clippy clean.
|
|
XWayland stability, GPU rendering, and multi-cursor Phase 2
The bulk of a multi-session shift's real work landed in crates/wayland.
Full root-cause/verification narrative for every item below lives in
docs/TODO.md (each has its own dated entry); this is the summary:
Desktop shell:
- Real desktop icons v2 (state/desktop_icons.rs, desktop_icons.rs):
fixed origin-baked-before-the-bar-connects, fixed-icon sort order, and
a proper Rename/Delete-to-Trash menu (window_memory.rs backs the
rename-persistence side). Rubber-band marquee multi-select.
- icon_theme.rs: real freedesktop icon-theme lookup (inherits chain,
hicolor fallback) rendering actual theme SVGs via resvg/tiny-skia,
replacing the hand-drawn placeholder glyphs.
- Context/desktop menus (decoration.rs, desktop_menu.rs, state/menu.rs)
rebuilt to match the project's own AGS panel styling: rounded floating
panel, tinted-fill row highlight, real separators, a much fuller
titlebar window-menu action set.
Layer-shell / multi-monitor:
- Layer-shell hit-testing and render positioning (input/pointer.rs,
udev/render.rs's element placement) now correctly convert LayerMap's
logical geometry into physical pixels on a fractionally-scaled output
- root cause of a bottom-anchored dock being unclickable and
unpainted while a top-anchored bar on the same output worked.
udev/outputs.rs's relayout_outputs gained the same physical/logical
split for cross-output positioning, now backed by a real unit test
(next_logical_x) built from the original measured incident numbers.
- state/geometry.rs: a window's border/decoration no longer briefly
clips when moved between differently-scaled monitors mid-drag.
XWayland / stability:
- xwayland.rs, udev/session.rs, udev/platform.rs: fixed a 100%-
reproducible cold-start XKEYBOARD crash-loop (XWayland's own stdin
inherited a real, already-owned VT; env passthrough and idle-callback
spawn timing were both real, independent gaps) that had silently taken
down all X11-app support and the global-menu registrar every session.
- state/toplevel.rs, state/lifecycle.rs: XWayland dialog detection via
WM_TRANSIENT_FOR, not just a native xdg_toplevel parent.
Rendering:
- udev/render.rs, decoration.rs: real GPU (GBM+EGL+DrmCompositor)
window-content and cursor rendering on the udev backend, falling back
to the untouched Pixman path automatically on any init failure.
- decoration/tests.rs, state/mod.rs: rounded-corner/border fixes for
interactive resize lag and cross-monitor moves.
Multi-cursor Phase 2 (virtual_pointer.rs, new; state/mod.rs, udev/
platform.rs, winit/nested_platform.rs): pins a zwlr_virtual_pointer_
unstable_v1 object to a specific window, bypassing the shared seat/
focus/pointer_pos path entirely via hand-rolled wl_pointer.enter/motion/
button/frame/leave against every WlPointer the target client has bound
(PointerHandle::client_pointers). Lets an agent operate one window while
a human uses another, genuinely simultaneously, with zero client
cooperation and no second wl_seat (confirmed a dead end: real clients
only ever bind the first seat advertised).
Full workspace build/test/clippy clean.
|