srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/state/geometry.rs
AgeCommit message (Collapse)AuthorFilesLines
2025-03-10Fix border/content-mask sized for a CSD client's whole buffer, margin includedsrdusr1-15/+38
The previous fix for a stale border size (switching effective_frame_of from dwindow.geometry() to raw dwindow.bbox()) traded one bug for another. bbox() is the window's entire committed buffer; geometry() is that buffer intersected with the client's own xdg_surface:: set_window_geometry hint, which excludes any invisible CSD shadow margin the client reserves around its real visible content. The assumption behind the switch - that sync_geometry's unconditional tiled-state bits make every compliant client reserve no such margin, so nothing would be lost - was wrong: confirmed live via temporary diagnostic logging, Chrome reserves a real, correctly-current 10px margin on all four sides regardless of the tiled hint (Firefox, the window that exposed the original staleness bug, does not - the two disagree on this). Raw bbox() therefore handed the border/content mask Chrome's entire buffer, margin included - 20px wider and taller than its real visible chrome on each axis, with no compensating position shift - so the rounded border curve traced a rectangle Chrome's real content never reached, and its true, still-square corner poked straight through the curve instead of being hidden by it. Reported live as a border not lining up with a window's content and a hard block cutting through an otherwise-rounded corner. Fixed by keeping both properties at once: dwindow.geometry().loc as the margin - assumed symmetric (left == right, top == bottom), which holds for every real CSD shadow margin observed here, since it's a fixed design constant that doesn't scale with window size and so has no equivalent staleness window even while the hint's absolute size does - subtracted from the always-fresh bbox(). Current size, correct visible-content bounds, for a client that reserves a margin (Chrome) and one that doesn't (Firefox, whose hint .loc is always (0, 0), where this reduces to plain bbox()) alike.
2025-03-07Fix border/decoration stuck at a stale size after a passive tiling reflowsrdusr1-5/+40
effective_frame_of sized a window's border/shadow/titlebar from dwindow.geometry() - xdg_surface::set_window_geometry. Per smithay's own implementation that value is the client's cached hint intersected with bbox(), falling back to bbox() only if never set. Nothing in the protocol obliges a client to resend the hint on every resize, and intersection() can never return something larger than its smaller operand - so once a client's cached hint is smaller than its current real buffer, geometry() stays clamped there permanently. Confirmed live: after a passive tiling reflow (this window resized only as a side effect of a sibling window moving, no direct action on this window itself), Firefox's real content filled the correct, much larger area immediately, but its border/decoration stayed rendered at a small fraction of that - unchanged for several seconds, well past both animation settling and any reasonable commit-throttle window -- until an unrelated maximize/restore cycle happened to prompt Firefox into resending a fresh hint and self-correcting. Switched to bbox(): the real bounding box of the window's current surface tree, which updates on every commit unconditionally. This gives up excluding a CSD client's own invisible drop-shadow margin, but sync_geometry already unconditionally sends all four tiled state bits specifically so a compliant client (GTK4/Firefox) reserves no such margin at all, so a compliant client loses nothing. Both the decoration-bitmap sizing (redraw_decoration_buffer) and the render loops' own border/shadow/occlusion positioning funnel through this one function, so they stay consistent with each other - avoiding the out-of-bounds texture-crop regression a previous, different attempt at this same lag hit (see this function's own doc comment history).
2025-02-15Checkpoint: preserve all uncommitted rust-rewrite worktree worksrdusr1-18/+231
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.
2025-02-04Fix CSD windows rendering with a wallpaper-visible gap at their cornersrdusr1-1/+18
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.
2024-12-24Accumulate wayland-crate additions: capture rendering, focus/Space sync, VT ↵srdusr1-1/+34
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.
2024-08-20Send tiled xdg_toplevel state so GTK stops reserving its own shadowsrdusr1-0/+29
No configure this compositor ever sent set any xdg_toplevel::State bit at all - confirmed by grepping the whole crate, zero hits before this. GTK4 (Firefox concretely) reads the tiled bits to decide whether to reserve an invisible client-side shadow margin around its own content, independent of server- vs client-side decoration; with none ever sent it always assumed "floating, might need a shadow" and kept reserving one. That margin sits inside the committed buffer but is functionally invisible, so this compositor's own border - drawn at the full geometry, margin included, since nothing here knew the margin existed - ended up visibly offset from where the client's real chrome began. Root-caused from a live screenshot: Firefox's srdwm-drawn border sat clearly up-and-left of its actual toolbar, not framing it. Reported as "border is not with the window at start" and, more generally, borders never feeling like part of the window they're drawn around - which this is: decoration and content genuinely disagreeing about where the window's edge is. Sets all four Tiled* bits unconditionally on every xdg_toplevel configure - the same technique river/dwl use, telling every window it's flush against something and should skip its own shadow regardless of whether it's in a literal tiling layout, which is the outcome actually wanted here: this compositor draws the frame, nothing else should also be reserving room for one. Not visually verified against a live client yet - this needs an actual GTK app rendering under a restarted session to confirm the shadow margin is really gone, which no offline test can substitute for.
2024-07-30Split crates/wayland/src/state.rs (1276 lines) into state/srdusr1-0/+105
Pure reorganization, no behavior change - verified by diffing the function-name and struct-name sets before/after (both identical) plus a full cargo test pass. mod.rs keeps ClientState/OutputEntry/CompState/ WindowAnim/RepeatState's definitions, the key-repeat impl, and the output-lookup impl (all small and tightly coupled to the type definitions), plus mod declarations. The one large impl CompState block (previously ~600 lines) splits by concern: - lifecycle.rs: new_managed_window, set_decorated_from_mode, redraw_decoration_buffer, remove_window. - layers.rs: ensure_layer_initial_configure. - focus.rs: set_keyboard_focus, set_window_activated. - menu.rs: open/close/run_context_menu_action, is_double_click. - geometry.rs: raise_pinned, sync_geometry. - tick.rs: tick_dirty_broadcasts, tick_animations, resync_stacking_order. - toplevel.rs: the with_toplevel_title/app_id/sync_toplevel_metadata free functions. - tests.rs: unsplit, same reasoning as every other split this pass. CompState's fields were already pub(crate) (this crate's existing convention, unlike core's/config's plain-private), so no field- visibility changes were needed - only resync_stacking_order (called from geometry.rs, defined in tick.rs) needed bumping from private to pub(crate), matching that same convention.