desktop: Track surface enter/leave for outputs
This commit is contained in:
parent
44829d8fba
commit
2c0ae025de
|
@ -1,8 +1,11 @@
|
||||||
use super::{draw_window, Window};
|
use super::{draw_window, SurfaceState, Window};
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::renderer::{Frame, ImportAll, Renderer, Transform},
|
backend::renderer::{Frame, ImportAll, Renderer, Transform},
|
||||||
utils::{Logical, Point, Rectangle},
|
utils::{Logical, Point, Rectangle},
|
||||||
wayland::output::Output,
|
wayland::{
|
||||||
|
compositor::{with_surface_tree_downward, SubsurfaceCachedState, TraversalAction},
|
||||||
|
output::Output,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -13,7 +16,7 @@ use std::{
|
||||||
Mutex,
|
Mutex,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use wayland_server::protocol::wl_surface;
|
use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
|
|
||||||
static SPACE_ID: AtomicUsize = AtomicUsize::new(0);
|
static SPACE_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
|
@ -56,9 +59,13 @@ fn window_state(space: usize, w: &Window) -> RefMut<'_, WindowState> {
|
||||||
struct OutputState {
|
struct OutputState {
|
||||||
location: Point<i32, Logical>,
|
location: Point<i32, Logical>,
|
||||||
render_scale: f64,
|
render_scale: f64,
|
||||||
// damage and last_state in space coordinate space
|
|
||||||
|
// damage and last_state are in space coordinate space
|
||||||
old_damage: VecDeque<Vec<Rectangle<i32, Logical>>>,
|
old_damage: VecDeque<Vec<Rectangle<i32, Logical>>>,
|
||||||
last_state: IndexMap<usize, Rectangle<i32, Logical>>,
|
last_state: IndexMap<usize, Rectangle<i32, Logical>>,
|
||||||
|
|
||||||
|
// surfaces for tracking enter and leave events
|
||||||
|
surfaces: Vec<WlSurface>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutputUserdata = RefCell<HashMap<usize, OutputState>>;
|
type OutputUserdata = RefCell<HashMap<usize, OutputState>>;
|
||||||
|
@ -153,7 +160,7 @@ impl Space {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_for_surface(&self, surface: &wl_surface::WlSurface) -> Option<&Window> {
|
pub fn window_for_surface(&self, surface: &WlSurface) -> Option<&Window> {
|
||||||
if !surface.as_ref().is_alive() {
|
if !surface.as_ref().is_alive() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -234,8 +241,124 @@ impl Space {
|
||||||
self.outputs.get(0).cloned()
|
self.outputs.get(0).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cleanup(&mut self) {
|
pub fn refresh(&mut self) {
|
||||||
self.windows.retain(|w| w.toplevel().alive());
|
self.windows.retain(|w| w.toplevel().alive());
|
||||||
|
|
||||||
|
for output in &mut self.outputs {
|
||||||
|
output_state(self.id, output)
|
||||||
|
.surfaces
|
||||||
|
.retain(|s| s.as_ref().is_alive());
|
||||||
|
}
|
||||||
|
|
||||||
|
for window in &self.windows {
|
||||||
|
let bbox = window_rect(window, &self.id);
|
||||||
|
let kind = window.toplevel();
|
||||||
|
|
||||||
|
for output in &self.outputs {
|
||||||
|
let output_geometry = self
|
||||||
|
.output_geometry(output)
|
||||||
|
.unwrap_or_else(|| Rectangle::from_loc_and_size((0, 0), (0, 0)));
|
||||||
|
let mut output_state = output_state(self.id, output);
|
||||||
|
|
||||||
|
// Check if the bounding box of the toplevel intersects with
|
||||||
|
// the output, if not no surface in the tree can intersect with
|
||||||
|
// the output.
|
||||||
|
if !output_geometry.overlaps(bbox) {
|
||||||
|
if let Some(surface) = kind.get_surface() {
|
||||||
|
with_surface_tree_downward(
|
||||||
|
surface,
|
||||||
|
(),
|
||||||
|
|_, _, _| TraversalAction::DoChildren(()),
|
||||||
|
|wl_surface, _, _| {
|
||||||
|
if output_state.surfaces.contains(wl_surface) {
|
||||||
|
slog::trace!(
|
||||||
|
self.logger,
|
||||||
|
"surface ({:?}) leaving output {:?}",
|
||||||
|
wl_surface,
|
||||||
|
output.name()
|
||||||
|
);
|
||||||
|
output.leave(wl_surface);
|
||||||
|
output_state.surfaces.retain(|s| s != wl_surface);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|_, _, _| true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(surface) = kind.get_surface() {
|
||||||
|
with_surface_tree_downward(
|
||||||
|
surface,
|
||||||
|
window_loc(window, &self.id),
|
||||||
|
|_, states, location| {
|
||||||
|
let mut location = *location;
|
||||||
|
let data = states.data_map.get::<RefCell<SurfaceState>>();
|
||||||
|
|
||||||
|
if data.is_some() {
|
||||||
|
if states.role == Some("subsurface") {
|
||||||
|
let current = states.cached_state.current::<SubsurfaceCachedState>();
|
||||||
|
location += current.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraversalAction::DoChildren(location)
|
||||||
|
} else {
|
||||||
|
// If the parent surface is unmapped, then the child surfaces are hidden as
|
||||||
|
// well, no need to consider them here.
|
||||||
|
TraversalAction::SkipChildren
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|wl_surface, states, &loc| {
|
||||||
|
let data = states.data_map.get::<RefCell<SurfaceState>>();
|
||||||
|
|
||||||
|
if let Some(size) = data.and_then(|d| d.borrow().size()) {
|
||||||
|
let surface_rectangle = Rectangle { loc, size };
|
||||||
|
|
||||||
|
if output_geometry.overlaps(surface_rectangle) {
|
||||||
|
// We found a matching output, check if we already sent enter
|
||||||
|
if !output_state.surfaces.contains(wl_surface) {
|
||||||
|
slog::trace!(
|
||||||
|
self.logger,
|
||||||
|
"surface ({:?}) entering output {:?}",
|
||||||
|
wl_surface,
|
||||||
|
output.name()
|
||||||
|
);
|
||||||
|
output.enter(wl_surface);
|
||||||
|
output_state.surfaces.push(wl_surface.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Surface does not match output, if we sent enter earlier
|
||||||
|
// we should now send leave
|
||||||
|
if output_state.surfaces.contains(wl_surface) {
|
||||||
|
slog::trace!(
|
||||||
|
self.logger,
|
||||||
|
"surface ({:?}) leaving output {:?}",
|
||||||
|
wl_surface,
|
||||||
|
output.name()
|
||||||
|
);
|
||||||
|
output.leave(wl_surface);
|
||||||
|
output_state.surfaces.retain(|s| s != wl_surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Maybe the the surface got unmapped, send leave on output
|
||||||
|
if output_state.surfaces.contains(wl_surface) {
|
||||||
|
slog::trace!(
|
||||||
|
self.logger,
|
||||||
|
"surface ({:?}) leaving output {:?}",
|
||||||
|
wl_surface,
|
||||||
|
output.name()
|
||||||
|
);
|
||||||
|
output.leave(wl_surface);
|
||||||
|
output_state.surfaces.retain(|s| s != wl_surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|_, _, _| true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_output<R>(
|
pub fn render_output<R>(
|
||||||
|
|
|
@ -99,7 +99,7 @@ impl Kind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct SurfaceState {
|
pub(super) struct SurfaceState {
|
||||||
buffer_dimensions: Option<Size<i32, Physical>>,
|
buffer_dimensions: Option<Size<i32, Physical>>,
|
||||||
buffer_scale: i32,
|
buffer_scale: i32,
|
||||||
buffer: Option<wl_buffer::WlBuffer>,
|
buffer: Option<wl_buffer::WlBuffer>,
|
||||||
|
|
Loading…
Reference in New Issue