diff options
Diffstat (limited to 'crates/wayland/src/udev')
| -rw-r--r-- | crates/wayland/src/udev/capture.rs | 7 | ||||
| -rw-r--r-- | crates/wayland/src/udev/render.rs | 25 |
2 files changed, 30 insertions, 2 deletions
diff --git a/crates/wayland/src/udev/capture.rs b/crates/wayland/src/udev/capture.rs index 0f87d27..bcf2aa4 100644 --- a/crates/wayland/src/udev/capture.rs +++ b/crates/wayland/src/udev/capture.rs @@ -62,7 +62,12 @@ impl CompState { let Some(w) = self.id_to_window.get(&id) else { continue }; let Some(surface) = crate::input::dwindow_wl_surface(w) else { continue }; let Some(geom) = self.wm.borrow().window(id).map(|w| w.geometry) else { continue }; - let loc = (geom.x - origin.0, geom.y - origin.1); + // Same `set_window_geometry` offset every other render path + // subtracts (see `udev/render.rs`'s matching fix) - without + // it, a CSD window's invisible shadow margin would show up as + // a gap in the capture too. + let content_offset = w.geometry().loc; + let loc = (geom.x - origin.0 - content_offset.x, geom.y - origin.1 - content_offset.y); elements.extend(render_elements_from_surface_tree(&mut udev.renderer, &surface, loc, 1.0, 1.0, Kind::Unspecified)); } diff --git a/crates/wayland/src/udev/render.rs b/crates/wayland/src/udev/render.rs index 9642603..6c9c7d2 100644 --- a/crates/wayland/src/udev/render.rs +++ b/crates/wayland/src/udev/render.rs @@ -329,7 +329,30 @@ impl CompState { if let Some(dwindow) = self.id_to_window.get(&id) { if let Some(surface) = crate::elements::window_wl_surface(dwindow) { let band = if w.decorated { srdwm_core::TITLEBAR_HEIGHT as i32 } else { 0 }; - let pos = (geom.x - origin.x, geom.y + band - origin.y); + // `dwindow.geometry().loc` is the client's own + // `xdg_surface.set_window_geometry` offset -- + // GTK4 CSD clients (Firefox concretely) declare + // their real visible content as a sub-rect + // inset within a larger buffer that also holds + // an invisible shadow-reservation margin, even + // once the tiled-state hint (`sync_geometry`, + // `xdg_toplevel::State::Tiled*`) has told them + // to skip drawing that shadow - the margin + // itself, not just its decoration, stays + // reserved in the buffer. Never subtracting + // this meant every such client's buffer origin + // (0,0) - the *outer* edge of that invisible + // margin - landed exactly at `geom.x,geom.y`, + // leaving the margin's width/height of genuine + // gap (wallpaper visible through it) between + // the border this compositor draws and where + // the client's actual visible content begins. + // Reported live as "an extra layer or border + // over each window" - confirmed by diffing a + // corner crop against the real wallpaper at + // that exact screen position, pixel for pixel. + let content_offset = dwindow.geometry().loc; + let pos = (geom.x - origin.x - content_offset.x, geom.y + band - origin.y - content_offset.y); let mut rounded_elem = None; if rounded_corners_enabled { let epoch = self.content_epoch.get(&id).copied().unwrap_or(0); |