| Age | Commit message (Collapse) | Author | Files | Lines |
|
Same fix as the udev backend's matching content-position code: a real
CSD shadow margin (dwindow.geometry().loc) is never negative, but a
live Firefox window was observed reporting loc = (-10, -10) despite
sync_geometry's tiled-state hint telling it to reserve no margin at
all. This path (rounded_content_element, a live GLES shader rendering
the client's own texture directly, not a separate pre-shifted buffer)
doesn't have the udev backend's double-application bug, but it shares
the same single-subtraction call and so needed the same clamp.
|
|
apply_geometry and restore - the Platform callbacks core's toggle_
maximize/apply_snap_zone/restore_window drive for a pure geometry
change - only called sync_geometry, never redraw_decoration_buffer.
The cached border-strip/titlebar bitmaps (self.border_top_decorations,
self.border_bottom_decorations, self.decorations) size themselves from
effective_frame, which can differ from w.geometry alone once a CSD
client's own invisible shadow margin is involved (see that function's
own doc comment) - but nothing here rebuilt them right when this
callback changed w.geometry. The next rebuild only happened whenever
this window's client next committed a frame or some other, unrelated
trigger reached redraw_decoration_buffer, not reliably right away.
Confirmed live: maximizing then restoring a Chrome window left its
border strips sized for the maximized frame while its real content had
already settled back to the smaller restored size, immediately and
permanently until some later trigger happened to catch it up - a
real, visible gap between content and border on the far (east/south)
edges, a different bug from the half-pixel corner seam fixed
separately in blend_corner_pixel.
Both apply_geometry and restore now also call redraw_decoration_buffer
right after sync_geometry, in both the udev and winit backends.
|
|
VT-switch resume: reasserting the CRTC's mode-setting state was never
enough on its own - display power (DPMS) is separate KMS state, and
nothing here ever touched it after a real switch-away-and-back. Page
flips kept succeeding with zero errors logged for the rest of a real
30+ minute session while the panel itself simply stayed dark, which is
what actually explains a user report of the screen and keyboard input
never recovering after one VT switch. Sets DPMS-on unconditionally on
every resume now, the same property zwlr_output_power_v1 already
writes for an explicit client request.
Corner rendering: both backends' side-strip crop (the fix that keeps a
window's flat left/right border strips from poking a solid-coloured
square through the top/bottom strip's own rounded curve) only ever
activated for `w.decorated` windows. An undecorated/CSD window's crop
depends on its *content* actually getting masked to match - the
winit backend never checked that at all, so every CSD window with a
nonzero border_width got the uncropped, "staircase" artifact
unconditionally, confirmed live via a highlighted border colour and
raw pixel sampling. Ported the udev backend's own `border_curve_is_safe`
check (decorated OR content-will-be-masked) into winit, using the
cheap "does this surface have subsurface children" test both content-
masking code paths already gate success on, rather than duplicating
either one's real (comparatively expensive) rendering work just to
probe it.
Full workspace build + clippy -D warnings + test suite (378 tests) green.
|
|
Pre-existing issues in the uncommitted rust-rewrite work (unused
imports, over-arity glyph-drawing functions, a couple of complex inline
types, or_insert_with(T::default) instead of or_default(), and one
unsimplified test-only arithmetic expression), plus two imports left
unused by switching to or_default(). None of these are behavior
changes. Full workspace build + clippy -D warnings + test suite (378
tests) all green after this.
|
|
# Conflicts:
# crates/config/src/engine/general.rs
# crates/wayland/src/udev/drm.rs
# crates/wayland/src/udev/mod.rs
# crates/wayland/src/udev/render.rs
# crates/wayland/src/winit/render.rs
|
|
Fixes a live-reproduced VT-switch busy loop (failed page_flip retried
with no backoff), shadow rendering bleeding onto occluding windows
unclipped, and a winit-backend buffer-age correctness bug that left
stale cross-window pixels on screen. Committing before merging in the
much larger uncommitted rust-rewrite worktree, which independently
touches several of the same files - this is the pre-merge baseline to
diff against, not a claim that these are the final versions of these
fixes.
|
|
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.
|
|
Every pointer motion event re-ran the same popup/layer/content hit-test
from scratch and delivered focus to whatever it found right now - there
was no notion of "a button is held, keep delivering to the surface that
received the press" at all, which is standard, expected Wayland
compositor behavior (every real compositor does this; it's how dragging,
text selection, and scrollbar-thumb dragging all stay coherent even when
the pointer briefly leaves the widget's bounds mid-gesture).
Without it, a real human's hand drifting even slightly outside the
pressed surface mid-drag - trivially easy during a fast, non-perfectly-
straight mouse motion - sent that client an unrequested `leave` event in
the middle of its own gesture. GTK's drag recognizers (a GtkHeaderBar's
move-the-window gesture, concretely) treat a mid-gesture leave as "this
isn't coherent, abort," which reads as "dragging this window by its
title bar does nothing at all" - live-reproduced this work on Nemo,
and consistent with move_request never having fired once all session
despite real attempts.
pointer_button_grab captures the (surface, origin) resolved on a button
press once the held-button count goes from 0 to 1, and every event under
the grab - motion or button, this press's or a later one overlapping
it - is delivered there instead of wherever a fresh hit-test lands,
until every held button is back up.
|
|
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 -> configure -> ack-commit
with no buffer again -> 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.
|
|
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.
|
|
MISSING.md listed the border frame's bottom/left/right strips as
staying square while the top one (and the titlebar above it) rounds --
"unrelated to client content rounding... not attempted." The left/
right strips genuinely can't participate (border_strips' geometry has
them span only the height between the top and bottom strips, no
corner to round), but the bottom strip is exactly the same shape as
the top one and had no reason left to stay square.
decoration::render_border_bottom mirrors render_border_top exactly
(round_bottom_corners mirrors round_top_corners), cached the same way
in a new border_bottom_decorations map, and drawn in both render loops
via the same all-or-nothing occlusion check the top strip already
uses - pulled out of the left/right strips' per-fragment occlusion
splitting into its own dedicated bitmap path, matching top's existing
trade-off (cropping a rounded bitmap's source rect per fragment is
real extra work for a strip this thin) rather than inventing a new one.
One real bug caught before it shipped: round_bottom_corners' corner-
centre math (height - r - 1) panics on unsigned underflow whenever the
radius clamp lands on the strip's own full height (a real, common case
- a 2px-thick test strip hits it immediately). Fixed by computing the
centre as a signed offset instead, mirroring how the existing dx/dy
distance math already avoids the same class of issue.
|
|
Platform::close only ever called w.toplevel(), which is None for an
XWayland window - closing one (the WM's own close binding, or `srd
dispatch close`) silently did nothing at all, on both udev and winit.
Found live: a leftover untitled fullscreen window wouldn't close via
srd dispatch close even after several seconds, tracing back to this.
Fixed by falling back to X11Surface::close() when there's no xdg
toplevel - it already handles both cases smithay-side (a polite
WM_DELETE_WINDOW for a cooperating client, outright destroy_window for
one that doesn't support it), so no new logic was needed, just calling
it.
|
|
~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" -> "see state/mod.rs's REPEAT_DELAY",
"udev.rs's monitors()" -> "udev/platform.rs's monitors()") or the bare
module name where the reference was already generic ("the udev/winit
backends", not a specific location).
|
|
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 the module doc comment, imports,
WaylandPlatform's struct definition, and TARGET_FRAME_TIME, plus mod
declarations. The rest splits by concern:
- connect.rs: connect(), the ~200-line setup/init function.
- run.rs: accept_clients, pump_winit - the small per-poll pair.
- render.rs: render_frame, the per-frame render loop (left as one
intact ~330-line function, same reasoning as udev's render.rs: its
structure is deliberate and already documented inline, not a target
for further decomposition in a pure reorganization pass).
- capture.rs: capture_offscreen, the screencopy path.
- events.rs: handle_winit_event.
- platform.rs: `impl Platform for WaylandPlatform`.
No tests module existed in the original file, so none was split out.
A handful of methods/functions (accept_clients, pump_winit,
render_frame, capture_offscreen, handle_winit_event) went from private
to pub(super): called across what are now sibling submodules, which
Rust's privacy model doesn't let see each other's private items.
|