| Age | Commit message (Collapse) | Author | Files | Lines |
|
Regression I introduced two commits ago, reported live: "I can click close
where the button would normally be and it does close, but it is still
invisible."
The gate that stops an empty frame being drawn before a client paints asked
the renderer, from inside the render loop, whether a window's surface had a
buffer attached right now - and treated "no" as "do not draw". That
question is only meaningful for a native xdg-shell toplevel. An XWayland
window's surface state does not describe it the same way, so the answer came
back no on every frame and the window was never drawn again, while srdwm's
own hit-testing carried on working perfectly: an invisible window that still
takes clicks, which is a worse failure than the empty frame it was meant to
prevent.
Inverted to the fail-safe direction. `new_managed_window` - the one path
that creates a native toplevel - puts the window into
`awaiting_first_buffer`, and `commit` takes it out on the first commit that
carries a buffer. The render and capture paths test that set and nothing
else. A window is now hidden only when srdwm itself put it there, so no
window whose plumbing works differently can be hidden by a lookup that did
not apply to it: the XWayland map path never touches the set, and neither
can anything else.
The buffer question still gets asked, but only in `commit`, about a surface
it was just handed, where it is the right question.
Verified both halves: an ordinary spawn still shows no frame before content
(26 captured frames with content, 0 without), and the only way into the set
is one line in one function.
|
|
Reported as "before a window spawns, the border corners look funny".
A toplevel is placed, sized and decorated the moment its role is created,
which is well before the client draws. srdwm was rendering it from that
moment, so what appeared first was an empty frame: border, titlebar and
shadow standing around bare desktop, at the guessed 800x600 placeholder
size, with nothing inside. When the real buffer arrived the frame snapped
to the real size.
Measured in a nested session, capturing a cold terminal's spawn with grim:
four consecutive captured frames spanning 540ms showed a complete red
border with zero client content inside it, at 642px outer height, which
then settled at 610 - a jump of exactly one TITLEBAR_HEIGHT. After this
change the same capture has no such frame at all: every frame that shows a
border shows content in it, and the height does not change afterward.
Two parts:
- Nothing is drawn for a window that has never committed a buffer. All
five paths that draw a frame agree on this - both udev render loops
(Pixman and GPU), the winit render loop, and both screencopy paths, so a
screenshot cannot show a frame the screen does not.
- The open-slide starts at the first commit that carries a buffer rather
than at role creation. A cold terminal took ~800ms to paint, long enough
for the whole tween to finish against the empty frame, so the window
simply appeared, already at rest, with no animation at all. It now
animates where it can actually be seen.
The answer latches once true (windows_shown_once), so a window that has
legitimately shown something is never hidden again by this however its
buffer state changes. A window that cannot be resolved to a surface counts
as drawable, deliberately: this hides a window only on positive evidence
that it has never drawn, so nothing whose surface plumbing works
differently - an XWayland window - can be hidden by a lookup that did
not apply to it.
Same shape, and the same reason, as sync_layer_visibility's own has_buffer
branch, which layer surfaces have had all along.
533 tests pass, clippy clean.
|
|
Two things, and the first is smaller than I told anyone.
WORKSPACE CAPTURE. I said off-screen workspace capture did not exist and
would need building. It already did: udev/capture.rs renders a workspace
that is not on screen, at the target monitor's native size, downscaled to a
requested size, wallpaper included. Verified on the live DRM session rather
than from the source - capturing the active workspace and a non-visible one
gave 320x180 images with mean luminance 0.067 and 0.137, so the second is
genuinely a different render and not a copy of what is presented.
The only thing missing was the container. It wrote PPM, which the shells
that want thumbnails cannot decode, so the file was written successfully,
returned successfully, and silently not drawn - the same failure class as a
capture pass that omits a tier. encode_capture now picks the format from the
destination's extension: .ppm still writes PPM so existing callers keep
working, .jpg/.jpeg write JPEG, anything else writes PNG. Four tests check
the actual magic bytes rather than trusting the call, plus the unfamiliar
extension fallback and a size-mismatch error.
LEFT-EDGE RESIZE. Reported as content resizing "from the right side even
when i resize from left". The window's origin moves the instant the pointer
does, but the client only commits a matching buffer some frames later, so
its still-old content was being placed at the new origin - which slides the
whole window rather than growing it, and leaves the edge that should be
nailed down drifting.
sync_geometry now derives the origin from the size the client has actually
committed when the drag is from a left or top edge, so the opposite edge
stays exactly where the drag started and the dragged edge catches up as
commits arrive. A right or bottom drag is untouched: its origin never moves.
533 tests pass, clippy clean.
|
|
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.
|
|
srdwm never read xdg_surface.set_window_geometry anywhere. A CSD
client (GTK4/Firefox) declares its real visible content as a sub-rect
inset within a larger buffer that also reserves an invisible shadow
margin - that margin stays reserved in the buffer even once the
tiled-state hint tells the client to stop drawing the shadow itself.
Every render path was positioning content at the client's raw buffer
origin instead of subtracting that declared offset, leaving the
margin's width/height as a gap with wallpaper visible through it at
the window's top-left corner. Confirmed by pixel-diffing the gap
against the real wallpaper at that exact screen position: an exact
match, ruling out "just the client's own dark theme."
Fixed in three places that have to move together: udev/render.rs and
winit/render.rs's content-positioning code, and sync_geometry's
space.map_element call. That last one matters as much as the other
two - it's what smithay's Space (and therefore click hit-testing)
reads, so a render-only fix would have traded a visible gap for an
invisible, same-size hit-test offset in the other direction. Also
applied to the new capture-workspace off-screen render for the same
reason.
This likely also explains real dropdown/context-menu misplacement (and
the clicks landing on the wrong spot) in CSD apps: popup positioning
anchors against the same window position this fix corrects.
|
|
resume, plumbing
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.
|