diff --git a/src/shell/mod.rs b/src/shell/mod.rs index e1a48567..061be6b4 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -50,10 +50,13 @@ use smithay::{ }, utils::{IsAlive, Logical, Point, Rectangle, Serial, Size}, wayland::{ - compositor::{SurfaceAttributes, with_states}, + compositor::{SurfaceAttributes, get_parent, with_states}, seat::WaylandFocus, session_lock::LockSurface, - shell::wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState}, + shell::{ + wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState}, + xdg::{XDG_POPUP_ROLE, XdgPopupSurfaceData}, + }, xdg_activation::XdgActivationState, xwayland_keyboard_grab::XWaylandKeyboardGrab, }, @@ -728,6 +731,81 @@ impl WorkspaceSet { self.post_remove_workspace(workspace_state, &previous_active_handle); prefers } + + pub fn surface_geometry_offset_from_toplevel( + &self, + surface: &WlSurface, + ) -> Option<(Rectangle, Point)> { + let mut root = surface.clone(); + loop { + while let Some(parent) = get_parent(&root) { + root = parent; + } + if smithay::wayland::compositor::get_role(&root) == Some(XDG_POPUP_ROLE) + && let Some(parent) = with_states(&root, |states| { + states + .data_map + .get::() + .and_then(|m| m.lock().unwrap().parent.as_ref().cloned()) + }) + { + root = parent; + continue; + } + break; + } + + self.sticky_layer + .mapped() + .find(|w| { + w.windows() + .any(|(w, _)| w.wl_surface().as_deref() == Some(&root)) + }) + .and_then(|w| { + w.surface_offset(surface).and_then(|offset| { + self.sticky_layer + .element_geometry(w) + .map(|geom| (geom, offset)) + }) + }) + .or_else(|| { + self.workspaces.iter().find_map(|workspace| { + workspace + .get_fullscreen() + .and_then(|fullscreen| { + (fullscreen.wl_surface().as_deref() == Some(&root)) + .then(|| { + fullscreen.surface_offset(surface).and_then(|offset| { + workspace.fullscreen_geometry().map(|geom| (geom, offset)) + }) + }) + .flatten() + }) + .or_else(|| { + workspace.mapped().find_map(|w| { + w.windows() + .any(|(w, _)| w.wl_surface().as_deref() == Some(&root)) + .then(|| { + w.surface_offset(surface).and_then(|offset| { + workspace.element_geometry(w).map(|geom| (geom, offset)) + }) + }) + .flatten() + }) + }) + }) + }) + .or_else(|| { + layer_map_for_output(&self.output).layers().find_map(|l| { + (l.wl_surface() == &root) + .then(|| { + CosmicSurface::surface_tree_offset(l.wl_surface(), surface) + .map(|offset| (l.geometry().as_local(), offset)) + }) + .flatten() + }) + }) + } } #[derive(Debug)]