use crate::{ backend::renderer::utils::SurfaceState, utils::{Logical, Point, Rectangle, Size}, wayland::compositor::{ with_surface_tree_downward, with_surface_tree_upward, Damage, SubsurfaceCachedState, SurfaceAttributes, TraversalAction, }, }; use wayland_server::protocol::wl_surface; use std::cell::RefCell; impl SurfaceState { /// Returns the size of the surface. pub fn size(&self) -> Option> { self.buffer_dimensions .map(|dims| dims.to_logical(self.buffer_scale)) } fn contains_point(&self, attrs: &SurfaceAttributes, point: Point) -> bool { let size = match self.size() { None => return false, // If the surface has no size, it can't have an input region. Some(size) => size, }; let rect = Rectangle { loc: (0, 0).into(), size, } .to_f64(); // The input region is always within the surface itself, so if the surface itself doesn't contain the // point we can return false. if !rect.contains(point) { return false; } // If there's no input region, we're done. if attrs.input_region.is_none() { return true; } attrs .input_region .as_ref() .unwrap() .contains(point.to_i32_floor()) } } pub fn bbox_from_surface_tree

(surface: &wl_surface::WlSurface, location: P) -> Rectangle where P: Into>, { let location = location.into(); let mut bounding_box = Rectangle::from_loc_and_size(location, (0, 0)); with_surface_tree_downward( surface, location, |_, states, loc: &Point| { let mut loc = *loc; let data = states.data_map.get::>(); if let Some(size) = data.and_then(|d| d.borrow().size()) { if states.role == Some("subsurface") { let current = states.cached_state.current::(); loc += current.location; } // Update the bounding box. bounding_box = bounding_box.merge(Rectangle::from_loc_and_size(loc, size)); TraversalAction::DoChildren(loc) } else { // If the parent surface is unmapped, then the child surfaces are hidden as // well, no need to consider them here. TraversalAction::SkipChildren } }, |_, _, _| {}, |_, _, _| true, ); bounding_box } pub fn damage_from_surface_tree

( surface: &wl_surface::WlSurface, location: P, ) -> Vec> where P: Into>, { let mut damage = Vec::new(); with_surface_tree_upward( surface, location.into(), |_surface, states, location| { let mut location = *location; if let Some(data) = states.data_map.get::>() { let data = data.borrow(); if data.texture.is_none() { if states.role == Some("subsurface") { let current = states.cached_state.current::(); location += current.location; } } } TraversalAction::DoChildren(location) }, |_surface, states, location| { let mut location = *location; if let Some(data) = states.data_map.get::>() { let data = data.borrow(); let attributes = states.cached_state.current::(); if data.texture.is_none() { if states.role == Some("subsurface") { let current = states.cached_state.current::(); location += current.location; } damage.extend(attributes.damage.iter().map(|dmg| { let mut rect = match dmg { Damage::Buffer(rect) => rect.to_logical(attributes.buffer_scale), Damage::Surface(rect) => *rect, }; rect.loc += location; rect })); } } }, |_, _, _| true, ); damage } pub fn under_from_surface_tree

( surface: &wl_surface::WlSurface, point: Point, location: P, ) -> Option<(wl_surface::WlSurface, Point)> where P: Into>, { let found = RefCell::new(None); with_surface_tree_downward( surface, location.into(), |wl_surface, states, location: &Point| { let mut location = *location; let data = states.data_map.get::>(); if states.role == Some("subsurface") { let current = states.cached_state.current::(); location += current.location; } let contains_the_point = data .map(|data| { data.borrow() .contains_point(&*states.cached_state.current(), point - location.to_f64()) }) .unwrap_or(false); if contains_the_point { *found.borrow_mut() = Some((wl_surface.clone(), location)); } TraversalAction::DoChildren(location) }, |_, _, _| {}, |_, _, _| { // only continue if the point is not found found.borrow().is_none() }, ); found.into_inner() } pub fn send_frames_surface_tree(surface: &wl_surface::WlSurface, time: u32) { with_surface_tree_downward( surface, (), |_, _, &()| TraversalAction::DoChildren(()), |_surf, states, &()| { // the surface may not have any user_data if it is a subsurface and has not // yet been commited for callback in states .cached_state .current::() .frame_callbacks .drain(..) { callback.done(time); } }, |_, _, &()| true, ); }