shell: implement surface_offset and surface_tree_offset

This commit is contained in:
Skygrango 2026-05-06 00:26:00 +08:00 committed by Ian Douglas Scott
parent 22fe419747
commit 32b54cc31f
2 changed files with 74 additions and 1 deletions

View file

@ -254,6 +254,14 @@ impl CosmicMapped {
.any(|(w, _)| w.has_surface(surface, surface_type))
}
pub fn surface_offset(&self, surface: &WlSurface) -> Option<Point<i32, Logical>> {
self.windows().find_map(|(window, window_offset)| {
window
.surface_offset(surface)
.map(|offset| window_offset + offset)
})
}
/// Give the pointer target under a relative offset into this element.
///
/// Returns Target + Offset relative to the target

View file

@ -45,7 +45,10 @@ use smithay::{
IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, user_data::UserDataMap,
},
wayland::{
compositor::{SurfaceData, TraversalAction, with_states, with_surface_tree_downward},
compositor::{
SubsurfaceCachedState, SurfaceData, TraversalAction, with_states,
with_surface_tree_downward,
},
seat::WaylandFocus,
shell::xdg::{
SurfaceCachedState, ToplevelCachedState, ToplevelSurface, XdgToplevelSurfaceData,
@ -652,6 +655,68 @@ impl CosmicSurface {
}
}
pub fn surface_offset(&self, surface: &WlSurface) -> Option<Point<i32, Logical>> {
match self.0.underlying_surface() {
WindowSurface::Wayland(toplevel) => {
Self::surface_tree_offset(toplevel.wl_surface(), surface)
}
WindowSurface::X11(surface_x11) => {
if surface_x11.wl_surface().as_ref() == Some(surface) {
Some(Point::default())
} else {
None
}
}
}
}
pub fn surface_tree_offset(
root: &WlSurface,
surface: &WlSurface,
) -> Option<Point<i32, Logical>> {
if root == surface {
return Some(Point::default());
}
let found = AtomicBool::new(false);
let mut found_offset = Point::<i32, Logical>::default();
with_surface_tree_downward(
root,
Point::<i32, Logical>::default(),
|s, states, parent_offset| {
let mut offset = *parent_offset;
if s != root {
offset += states
.cached_state
.get::<SubsurfaceCachedState>()
.current()
.location;
}
TraversalAction::DoChildren(offset)
},
|s, _, offset| {
if s == surface {
found_offset = *offset;
found.store(true, Ordering::SeqCst);
}
},
|_, _, _| !found.load(Ordering::SeqCst),
);
if found.load(Ordering::SeqCst) {
return Some(found_offset);
}
for (popup, popup_offset) in PopupManager::popups_for_surface(root) {
if let Some(offset) = Self::surface_tree_offset(popup.wl_surface(), surface) {
return Some(popup_offset + offset);
}
}
None
}
pub fn focus_under(
&self,
relative_pos: Point<f64, Logical>,