diff options
| author | srdusr <[email protected]> | 2026-04-20 00:48:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2026-04-20 00:48:00 +0200 |
| commit | 436d42da6ef61a5ea20d5102c4baed7bf0993606 (patch) | |
| tree | 5b013ae1877d81bfb67e422fdf56896d761076ed /crates/wayland/src/protocols/xdg_shell.rs | |
| parent | 1f708f8aa09bf8bbce82314a76b7f34def90b798 (diff) | |
| download | srdwm-436d42da6ef61a5ea20d5102c4baed7bf0993606.tar.gz srdwm-436d42da6ef61a5ea20d5102c4baed7bf0993606.zip | |
Confirm Nemo's popup works; fix the two bugs that hid it, and shadow bleed across a monitor seam
Nemo's right-click context menu was the last open punch-list item, parked
twice as untestable. It works: verified end to end in a throwaway nested
compositor, menu and submenu both, at the correct position and stacking.
The popup path itself needed no fix, so the POPUP-GEOM-DIAG/POPUP-GRAB-DIAG
diagnostics are removed.
Two real bugs turned up in the way of testing it.
zwlr_virtual_pointer was a silent no-op on the winit backend. Every
Motion/MotionAbsolute handler read UdevState::bounds() behind an early
return when state.udev was None, and that field is Some only for the DRM
backend. The protocol advertised its global, accepted create_virtual_pointer
and accepted every request, then discarded all motion with no error and no
log. That is the backend a nested instance runs on, so the only safe way to
drive a throwaway compositor - a Wayland client of that compositor, which
cannot reach any other session, unlike ydotool's /dev/uinput writes - did
not work at all. Bounds now come from WindowManager::monitors() when udev is
absent; both backends fill that list from Platform::monitors().
The winit backend's screencopy pass rendered no popups and no shadows. It
re-renders the scene offscreen, and that second scene was missing tiers, so
grim on a nested instance reported the opposite of the truth: a menu drawing
perfectly on screen photographed as absent. The DRM backend never had this,
since it serves screencopy from the on-screen frame it just drew. Border
strips are still missing from that pass, called out in the code rather than
left silent.
Also fixed, from the "windows show a bit in the other monitor" report:
shadow_rect expanded by SHADOW_SIZE on every side with no monitor-boundary
awareness, so a window flush against a seam put its 24px shadow strip on the
neighbouring screen. shadow_rect_clipped clips to the bounding box of the
monitors the window's geometry actually touches - not just its assigned
one, since a window straddling a seam really does occupy both and clipping
there would cut its shadow off mid-body. The bitmap's own extent stays
unclipped, because the src rectangle indexes into it; only the fragment list
is clipped. Six tests on the incident's own numbers. Not confirmed on
screen: the nested backend cannot produce a second monitor.
New tool: tools/virtual-pointer-click, a scriptable virtual-pointer driver
that acknowledges each command after its round-trip, so a test script can
put a screenshot between a move and the click that follows it.
489 tests pass, clippy clean.
Diffstat (limited to 'crates/wayland/src/protocols/xdg_shell.rs')
| -rw-r--r-- | crates/wayland/src/protocols/xdg_shell.rs | 28 |
1 files changed, 3 insertions, 25 deletions
diff --git a/crates/wayland/src/protocols/xdg_shell.rs b/crates/wayland/src/protocols/xdg_shell.rs index 4fe0f6f..0236736 100644 --- a/crates/wayland/src/protocols/xdg_shell.rs +++ b/crates/wayland/src/protocols/xdg_shell.rs @@ -8,7 +8,6 @@ use smithay::input::pointer::Focus; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::reexports::wayland_server::protocol::wl_output::WlOutput; use smithay::reexports::wayland_server::protocol::wl_seat; -use smithay::reexports::wayland_server::Resource; use smithay::utils::Serial; use smithay::wayland::shell::xdg::{PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState}; @@ -185,22 +184,11 @@ impl XdgShellHandler for CompState { /// real follow-up, not this fix); an occasional popup placed near a /// screen edge may render partly off it, which is cosmetic, not a hang. fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) { - // Temporary: live report is that Nemo's right-click context menu - // never appears at all (not mispositioned - entirely invisible), - // while the exact same xdg_popup mechanism works for Firefox. Logs - // the unconstrained geometry this popup gets so a live repro tells - // us whether it's landing off-screen/degenerate (the known gap this - // function's own doc comment already flags) or something else - // entirely. Remove once resolved. - let geom = positioner.get_geometry(); - let parent = surface.get_parent_surface(); - log::warn!("POPUP-GEOM-DIAG geometry={geom:?} parent={:?}", parent.as_ref().map(|s| s.id())); surface.with_pending_state(|state| { - state.geometry = geom; + state.geometry = positioner.get_geometry(); state.positioner = positioner; }); if surface.send_configure().is_err() { - log::warn!("POPUP-GEOM-DIAG send_configure failed"); return; } let _ = self.popups.track_popup(smithay::desktop::PopupKind::Xdg(surface)); @@ -223,19 +211,9 @@ impl XdgShellHandler for CompState { /// `resize_request` already ignore the same parameter. fn grab(&mut self, surface: PopupSurface, _seat: wl_seat::WlSeat, serial: Serial) { let popup = PopupKind::Xdg(surface); - let Ok(root) = find_popup_root_surface(&popup) else { - log::warn!("POPUP-GRAB-DIAG find_popup_root_surface failed"); - return; - }; + let Ok(root) = find_popup_root_surface(&popup) else { return }; let seat = self.seat.clone(); - let grab = match self.popups.grab_popup(root, popup, &seat, serial) { - Ok(g) => g, - Err(e) => { - log::warn!("POPUP-GRAB-DIAG grab_popup failed: {e:?}"); - return; - } - }; - log::warn!("POPUP-GRAB-DIAG grab established, has_pointer={} has_keyboard={}", seat.get_pointer().is_some(), seat.get_keyboard().is_some()); + let Ok(grab) = self.popups.grab_popup(root, popup, &seat, serial) else { return }; if let Some(keyboard) = seat.get_keyboard() { keyboard.set_grab(self, PopupKeyboardGrab::new(&grab), serial); } |