diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index 73b210e..266fb6d 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -1,7 +1,7 @@ use super::{CompositorHandler, Damage, Handler as UserHandler, Rectangle, RectangleKind, SubsurfaceAttributes}; use super::region::RegionData; -use super::tree::SurfaceData; +use super::tree::{Location, SurfaceData}; use wayland_server::{Client, Destroy, EventLoopHandle, Resource}; use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor, wl_subsurface, wl_surface}; @@ -227,31 +227,43 @@ unsafe fn with_subsurface_attributes(subsurface: &wl_subsurface::WlSubsurf } impl wl_subsurface::Handler for CompositorHandler { - fn set_position(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_subsurface::WlSubsurface, - x: i32, y: i32) { + fn set_position(&mut self, _: &mut EventLoopHandle, _: &Client, + subsurface: &wl_subsurface::WlSubsurface, x: i32, y: i32) { unsafe { - with_subsurface_attributes::(resource, |attrs| { + with_subsurface_attributes::(subsurface, |attrs| { attrs.x = x; attrs.y = y; }); } } - fn place_above(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_subsurface::WlSubsurface, - sibling: &wl_surface::WlSurface) { - unimplemented!() - } - fn place_below(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_subsurface::WlSubsurface, - sibling: &wl_surface::WlSurface) { - unimplemented!() - } - fn set_sync(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_subsurface::WlSubsurface) { + fn place_above(&mut self, _: &mut EventLoopHandle, _: &Client, + subsurface: &wl_subsurface::WlSubsurface, sibling: &wl_surface::WlSurface) { unsafe { - with_subsurface_attributes::(resource, |attrs| { attrs.sync = true; }); + let ptr = subsurface.get_user_data(); + let surface = &*(ptr as *mut wl_surface::WlSurface); + if let Err(()) = SurfaceData::::reorder(surface, Location::After, sibling) { + subsurface.post_error(wl_subsurface::Error::BadSurface as u32, "Provided surface is not a sibling or parent.".into()); + } } } - fn set_desync(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_subsurface::WlSubsurface) { + fn place_below(&mut self, _: &mut EventLoopHandle, _: &Client, + subsurface: &wl_subsurface::WlSubsurface, sibling: &wl_surface::WlSurface) { unsafe { - with_subsurface_attributes::(resource, |attrs| { attrs.sync = false; }); + let ptr = subsurface.get_user_data(); + let surface = &*(ptr as *mut wl_surface::WlSurface); + if let Err(()) = SurfaceData::::reorder(surface, Location::Before, sibling) { + subsurface.post_error(wl_subsurface::Error::BadSurface as u32, "Provided surface is not a sibling or parent.".into()); + } + } + } + fn set_sync(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface) { + unsafe { + with_subsurface_attributes::(subsurface, |attrs| { attrs.sync = true; }); + } + } + fn set_desync(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface) { + unsafe { + with_subsurface_attributes::(subsurface, |attrs| { attrs.sync = false; }); } } } diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 2af9f44..084330c 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -192,7 +192,8 @@ impl CompositorToken { /// Access the data of a surface tree /// /// The provided closure is called successively on the surface and all its child subsurfaces, - /// in a depth-first order. + /// in a depth-first order. This matches the order in which the surfaces are supposed to be + /// drawn: top-most last. /// /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). diff --git a/src/compositor/tree.rs b/src/compositor/tree.rs index 24f2896..2bca930 100644 --- a/src/compositor/tree.rs +++ b/src/compositor/tree.rs @@ -43,6 +43,11 @@ pub enum RoleStatus { HasRole, } +pub enum Location { + Before, + After, +} + impl SurfaceData { fn new() -> SurfaceData { SurfaceData { @@ -191,6 +196,54 @@ impl SurfaceData { child_guard.parent.as_ref().map(|p| p.clone_unchecked()) } + /// Reorders a surface relative to one of its sibling + /// + /// Fails if `relative_to` is not a sibling or parent of `surface`. + pub unsafe fn reorder(surface: &wl_surface::WlSurface, to: Location, + relative_to: &wl_surface::WlSurface) + -> Result<(), ()> { + let parent = { + let data_mutex = Self::get_data(surface); + let data_guard = data_mutex.lock().unwrap(); + data_guard + .parent + .as_ref() + .map(|p| p.clone_unchecked()) + .unwrap() + }; + if parent.equals(relative_to) { + // TODO: handle positioning relative to parent + return Ok(()); + } + + fn index_of(surface: &wl_surface::WlSurface, slice: &[wl_surface::WlSurface]) -> Option { + for (i, s) in slice.iter().enumerate() { + if s.equals(surface) { + return Some(i); + } + } + None + } + + let parent_mutex = Self::get_data(&parent); + let mut parent_guard = parent_mutex.lock().unwrap(); + let my_index = index_of(surface, &parent_guard.children).unwrap(); + let mut other_index = match index_of(surface, &parent_guard.children) { + Some(idx) => idx, + None => return Err(()), + }; + let me = parent_guard.children.remove(my_index); + if my_index < other_index { + other_index -= 1; + } + let new_index = match to { + Location::Before => other_index, + Location::After => other_index + 1, + }; + parent_guard.children.insert(new_index, me); + Ok(()) + } + /// Access the attributes associated with a surface /// /// Note that an internal lock is taken during access of this data,