From 0e88a6d28b4229f381e2d84a001429c2921915c7 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 4 Jun 2017 17:47:15 +0200 Subject: [PATCH 01/24] gitignore rustfmt's .bk files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a9d37c5..afc9901 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target Cargo.lock +*.bk From 13d047926499487f969ea25e27d0d497901cdd31 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 4 Jun 2017 17:47:37 +0200 Subject: [PATCH 02/24] First draft of compositor global. --- .rustfmt.toml | 1 - src/compositor/global.rs | 58 ++++++++ src/compositor/handlers.rs | 278 +++++++++++++++++++++++++++++++++++++ src/compositor/mod.rs | 276 ++++++++++++++++++++++++++++++++++++ src/compositor/region.rs | 42 ++++++ src/compositor/tree.rs | 252 +++++++++++++++++++++++++++++++++ src/lib.rs | 4 +- 7 files changed, 909 insertions(+), 2 deletions(-) create mode 100644 src/compositor/global.rs create mode 100644 src/compositor/handlers.rs create mode 100644 src/compositor/mod.rs create mode 100644 src/compositor/region.rs create mode 100644 src/compositor/tree.rs diff --git a/.rustfmt.toml b/.rustfmt.toml index 82fb65d..0409b3d 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -6,6 +6,5 @@ reorder_imports = true reorder_imported_names = true report_todo = "Never" report_fixme = "Never" -normalize_comments = true use_try_shorthand = true max_width = 110 diff --git a/src/compositor/global.rs b/src/compositor/global.rs new file mode 100644 index 0000000..96864bf --- /dev/null +++ b/src/compositor/global.rs @@ -0,0 +1,58 @@ +use super::CompositorToken; +use super::handlers::CompositorHandler; + +use wayland_server::{Client, EventLoopHandle, GlobalHandler, Init}; +use wayland_server::protocol::{wl_compositor, wl_subcompositor}; + +pub struct CompositorGlobal { + handler_id: Option, + log: ::slog::Logger, + _data: ::std::marker::PhantomData<*mut U>, +} + +impl CompositorGlobal { + pub fn new(logger: L) -> CompositorGlobal + where L: Into> + { + let log = ::slog_or_stdlog(logger); + CompositorGlobal { + handler_id: None, + log: log.new(o!("smithay_module" => "wompositor_handler")), + _data: ::std::marker::PhantomData, + } + } + + pub fn get_token(&self) -> CompositorToken { + super::make_token(self.handler_id + .expect("CompositorGlobal was not initialized.")) + } +} + +impl Init for CompositorGlobal + where U: Send + Sync + 'static +{ + fn init(&mut self, evlh: &mut EventLoopHandle, _index: usize) { + let id = evlh.add_handler_with_init(CompositorHandler::::new(self.log.clone())); + self.handler_id = Some(id); + } +} + +impl GlobalHandler for CompositorGlobal + where U: Send + Sync + 'static +{ + fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_compositor::WlCompositor) { + let hid = self.handler_id + .expect("CompositorGlobal was not initialized."); + evlh.register::<_, CompositorHandler>(&global, hid); + } +} + +impl GlobalHandler for CompositorGlobal + where U: Send + Sync + 'static +{ + fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_subcompositor::WlSubcompositor) { + let hid = self.handler_id + .expect("CompositorGlobal was not initialized."); + evlh.register::<_, CompositorHandler>(&global, hid); + } +} diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs new file mode 100644 index 0000000..e8b017b --- /dev/null +++ b/src/compositor/handlers.rs @@ -0,0 +1,278 @@ +use super::{Rectangle, RectangleKind, SubsurfaceAttributes, Damage}; +use super::region::RegionData; +use super::tree::SurfaceData; +use wayland_server::{Client, Destroy, EventLoopHandle, Init, Resource}; +use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, + wl_subcompositor, wl_subsurface, wl_surface}; + +pub struct CompositorHandler { + my_id: usize, + log: ::slog::Logger, + _data: ::std::marker::PhantomData, +} + +struct CompositorDestructor { + _t: ::std::marker::PhantomData, +} + +impl Init for CompositorHandler { + fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) { + self.my_id = index; + debug!(self.log, "Init finished") + } +} + +impl CompositorHandler { + pub fn new(log: ::slog::Logger) -> CompositorHandler { + CompositorHandler { + my_id: ::std::usize::MAX, + log: log, + _data: ::std::marker::PhantomData::, + } + } +} + +/* + * wl_compositor + */ + +impl wl_compositor::Handler for CompositorHandler { + fn create_surface(&mut self, evqh: &mut EventLoopHandle, _: &Client, + _: &wl_compositor::WlCompositor, id: wl_surface::WlSurface) { + unsafe { SurfaceData::::init(&id) }; + evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); + } + fn create_region(&mut self, evqh: &mut EventLoopHandle, _: &Client, + _: &wl_compositor::WlCompositor, id: wl_region::WlRegion) { + unsafe { RegionData::init(&id) }; + evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); + } +} + +unsafe impl ::wayland_server::Handler + for CompositorHandler { + unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, + resource: &wl_compositor::WlCompositor, opcode: u32, + args: *const ::wayland_server::sys::wl_argument) + -> Result<(), ()> { + as ::wayland_server::protocol::wl_compositor::Handler>::__message(self, evq, client, resource, opcode, args) + } +} + +/* + * wl_surface + */ + +impl wl_surface::Handler for CompositorHandler { + fn attach(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, + buffer: Option<&wl_buffer::WlBuffer>, x: i32, y: i32) { + unsafe { + SurfaceData::::with_data(surface, + |d| d.buffer = Some(buffer.map(|b| (b.clone_unchecked(), (x, y))))); + } + } + fn damage(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32, + y: i32, width: i32, height: i32) { + unsafe { + SurfaceData::::with_data(surface, + |d| d.damage = Damage::Surface(Rectangle { x, y, width, height })); + } + } + fn frame(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, + callback: wl_callback::WlCallback) { + unimplemented!() + } + fn set_opaque_region(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, + region: Option<&wl_region::WlRegion>) { + unsafe { + let attributes = region.map(|r| RegionData::get_attributes(r)); + SurfaceData::::with_data(surface, |d| d.opaque_region = attributes); + } + } + fn set_input_region(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, + region: Option<&wl_region::WlRegion>) { + unsafe { + let attributes = region.map(|r| RegionData::get_attributes(r)); + SurfaceData::::with_data(surface, |d| d.input_region = attributes); + } + } + fn commit(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface) { + unimplemented!() + } + fn set_buffer_transform(&mut self, _: &mut EventLoopHandle, _: &Client, + surface: &wl_surface::WlSurface, transform: wl_output::Transform) { + unsafe { + SurfaceData::::with_data(surface, |d| d.buffer_transform = transform); + } + } + fn set_buffer_scale(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, + scale: i32) { + unsafe { + SurfaceData::::with_data(surface, |d| d.buffer_scale = scale); + } + } + fn damage_buffer(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, + x: i32, y: i32, width: i32, height: i32) { + unsafe { + SurfaceData::::with_data(surface, + |d| d.damage = Damage::Buffer(Rectangle { x, y, width, height })); + } + } +} + +unsafe impl ::wayland_server::Handler for CompositorHandler { + unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, + resource: &wl_surface::WlSurface, opcode: u32, + args: *const ::wayland_server::sys::wl_argument) + -> Result<(), ()> { + as ::wayland_server::protocol::wl_surface::Handler>::__message(self, evq, client, resource, opcode, args) + } +} + +impl Destroy for CompositorDestructor { + fn destroy(surface: &wl_surface::WlSurface) { + unsafe { SurfaceData::::cleanup(surface) } + } +} + +/* + * wl_region + */ + +impl wl_region::Handler for CompositorHandler { + fn add(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32, y: i32, + width: i32, height: i32) { + unsafe { + RegionData::add_rectangle(region, RectangleKind::Add, + Rectangle { + x, + y, + width, + height, + }) + }; + } + fn subtract(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32, + y: i32, width: i32, height: i32) { + unsafe { + RegionData::add_rectangle(region, RectangleKind::Subtract, + Rectangle { + x, + y, + width, + height, + }) + }; + } +} + +unsafe impl ::wayland_server::Handler for CompositorHandler { + unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, + resource: &wl_region::WlRegion, opcode: u32, + args: *const ::wayland_server::sys::wl_argument) + -> Result<(), ()> { + as ::wayland_server::protocol::wl_region::Handler>::__message(self, evq, client, resource, opcode, args) + } +} + +impl Destroy for CompositorDestructor { + fn destroy(region: &wl_region::WlRegion) { + unsafe { RegionData::cleanup(region) }; + } +} + +/* + * wl_subcompositor + */ + +impl wl_subcompositor::Handler for CompositorHandler { + fn get_subsurface(&mut self, evqh: &mut EventLoopHandle, _: &Client, + resource: &wl_subcompositor::WlSubcompositor, id: wl_subsurface::WlSubsurface, + surface: &wl_surface::WlSurface, parent: &wl_surface::WlSurface) { + if let Err(()) = unsafe { SurfaceData::::set_parent(surface, parent) } { + resource.post_error(wl_subcompositor::Error::BadSurface as u32, "Surface already has a role.".into()); + return + } + id.set_user_data(Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _); + unsafe { + SurfaceData::::with_data(surface, + |d| d.subsurface_attributes = Some(Default::default())); + } + evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); + } +} + +unsafe impl ::wayland_server::Handler + for CompositorHandler { + unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, + resource: &wl_subcompositor::WlSubcompositor, opcode: u32, + args: *const ::wayland_server::sys::wl_argument) + -> Result<(), ()> { + as ::wayland_server::protocol::wl_subcompositor::Handler>::__message(self, evq, client, resource, opcode, args) + } +} + +/* + * wl_subsurface + */ + +unsafe fn with_subsurface_attributes(subsurface: &wl_subsurface::WlSubsurface, f: F) + where F: FnOnce(&mut SubsurfaceAttributes) +{ + let ptr = subsurface.get_user_data(); + let surface = &*(ptr as *mut wl_surface::WlSurface); + SurfaceData::::with_data(surface, |d| f(d.subsurface_attributes.as_mut().unwrap())); +} + +impl wl_subsurface::Handler for CompositorHandler { + fn set_position(&mut self, _: &mut EventLoopHandle, _: &Client, + resource: &wl_subsurface::WlSubsurface, x: i32, y: i32) { + unsafe { + with_subsurface_attributes::(resource, |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) { + unsafe { + with_subsurface_attributes::(resource, |attrs| { attrs.sync = true; }); + } + } + fn set_desync(&mut self, _: &mut EventLoopHandle, _: &Client, + resource: &wl_subsurface::WlSubsurface) { + unsafe { + with_subsurface_attributes::(resource, |attrs| { attrs.sync = false; }); + } + } +} + +unsafe impl ::wayland_server::Handler for CompositorHandler { + unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, + resource: &wl_subsurface::WlSubsurface, opcode: u32, + args: *const ::wayland_server::sys::wl_argument) + -> Result<(), ()> { + as ::wayland_server::protocol::wl_subsurface::Handler>::__message(self, evq, client, resource, opcode, args) + } +} + +impl Destroy for CompositorDestructor { + fn destroy(subsurface: &wl_subsurface::WlSubsurface) { + let ptr = subsurface.get_user_data(); + subsurface.set_user_data(::std::ptr::null_mut()); + unsafe { + let surface = Box::from_raw(ptr as *mut wl_surface::WlSurface); + SurfaceData::::with_data(&*surface, |d| d.subsurface_attributes = None); + SurfaceData::::unset_parent(&surface); + } + } +} diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs new file mode 100644 index 0000000..064afbd --- /dev/null +++ b/src/compositor/mod.rs @@ -0,0 +1,276 @@ +mod global; +mod handlers; +mod tree; +mod region; + +pub use self::global::CompositorGlobal; +use self::handlers::CompositorHandler; +pub use self::tree::RoleStatus; +use self::tree::SurfaceData; + +use wayland_server::protocol::{wl_buffer, wl_output, wl_surface}; +use wayland_server::resource_is_registered; + +/// Description of which part of a surface +/// should be considered damaged and needs to be redrawn +pub enum Damage { + /// The whole surface must be considered damaged (this is the default) + Full, + /// A rectangle containing the damaged zone, in surface coordinates + Surface(Rectangle), + /// A rectangle containing the smaazed zone, in buffer coordinates + /// + /// Note: Buffer scaling must be taken into consideration + Buffer(Rectangle) +} + +/// Data associated with a surface, aggreged by the handlers +/// +/// Most of the fields of this struct represent a double-buffered state, which +/// should only be applied once a `commit` request is received from the surface. +/// +/// You are responsible for setting those values as you see fit to avoid +/// processing them two times. +pub struct SurfaceAttributes { + /// Buffer defining the contents of the surface + /// + /// The tuple represent the coordinates of this buffer + /// relative to the location of the current buffer. + /// + /// If set to `Some(None)`, it means the user specifically asked for the + /// surface to be unmapped. + /// + /// You are free to set this field to `None` to avoid processing it several + /// times. It'll be set to `Some(...)` if the user attaches a buffer (or NULL) to + /// the surface. + pub buffer: Option>, + /// Scale of the contents of the buffer, for higher-resolution contents. + /// + /// If it matches the one of the output displaying this surface, no change + /// is necessary. + pub buffer_scale: i32, + /// Transform under which interpret the contents of the buffer + /// + /// If it matches the one of the output displaying this surface, no change + /// is necessary. + pub buffer_transform: wl_output::Transform, + /// Region of the surface that is guaranteed to be opaque + /// + /// By default the whole surface is potentially transparent + pub opaque_region: Option, + /// Region of the surface that is sensitive to user input + /// + /// By default the whole surface should be sensitive + pub input_region: Option, + /// Damage rectangle + /// + /// Hint provided by the client to suggest that only this part + /// of the surface was changed and needs to be redrawn + pub damage: Damage, + /// Subsurface-related attribute + /// + /// Is `Some` if this surface is a sub-surface + /// + /// **Warning:** Changing this field by yourself can cause panics. + pub subsurface_attributes: Option, + /// User-controlled data + /// + /// This is your field to host whatever you need. + pub user_data: U, +} + +impl Default for SurfaceAttributes { + fn default() -> SurfaceAttributes { + SurfaceAttributes { + buffer: None, + buffer_scale: 1, + buffer_transform: wl_output::Transform::Normal, + opaque_region: None, + input_region: None, + damage: Damage::Full, + subsurface_attributes: None, + user_data: Default::default(), + } + } +} + +/// Attributes defining the behaviour of a sub-surface relative to its parent +pub struct SubsurfaceAttributes { + /// Horizontal location of the top-left corner of this sub-surface relative to + /// the top-left corner of its parent + pub x: i32, + /// Vertical location of the top-left corner of this sub-surface relative to + /// the top-left corner of its parent + pub y: i32, + /// Sync status of this sub-surface + /// + /// If `true`, this surface should be repainted synchronously with its parent + /// if `false`, it should be considered independant of its parent regarding + /// repaint timings. + pub sync: bool, +} + +impl Default for SubsurfaceAttributes { + fn default() -> SubsurfaceAttributes { + SubsurfaceAttributes { + x: 0, + y: 0, + sync: true, + } + } +} + +/// Kind of a rectangle part of a region +#[derive(Copy,Clone)] +pub enum RectangleKind { + /// This rectangle should be added to the region + Add, + /// The intersection of this rectangle with the region should + /// be removed from the region + Subtract, +} + +/// A rectangle defined by its top-left corner and dimensions +#[derive(Copy,Clone)] +pub struct Rectangle { + /// horizontal position of the top-leftcorner of the rectangle, in surface coordinates + pub x: i32, + /// vertical position of the top-leftcorner of the rectangle, in surface coordinates + pub y: i32, + /// width of the rectangle + pub width: i32, + /// height of the rectangle + pub height: i32, +} + +/// Description of the contents of a region +/// +/// A region is defined as an union and difference of rectangle. +/// +/// This struct contains an ordered Vec containing the rectangles defining +/// a region. They should be added or substracted in this order to compute the +/// actual contents of the region. +#[derive(Clone)] +pub struct RegionAttributes { + /// List of rectangle part of this region + pub rects: Vec<(RectangleKind, Rectangle)>, +} + +impl Default for RegionAttributes { + fn default() -> RegionAttributes { + RegionAttributes { rects: Vec::new() } + } +} + +/// A Compositor global token +/// +/// This token can be cloned at will, and is the entry-point to +/// access data associated with the wl_surface and wl_region managed +/// by the `CompositorGlobal` that provided it. +#[derive(Copy,Clone)] +pub struct CompositorToken { + hid: usize, + _data: ::std::marker::PhantomData<*mut U>, +} + +fn make_token(hid: usize) -> CompositorToken { + CompositorToken { + hid: hid, + _data: ::std::marker::PhantomData, + } +} + +impl CompositorToken { + /// Access the data of a surface + /// + /// The closure will be called with the contents of the data associated with this surface. + /// + /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn with_surface_data(&self, surface: &wl_surface::WlSurface, f: F) + where F: FnOnce(&mut SurfaceAttributes) + { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported."); + unsafe { + SurfaceData::::with_data(surface, f); + } + } + + /// 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. + /// + /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn with_surface_tree(&self, surface: &wl_surface::WlSurface, f: F) -> Result<(), ()> + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported."); + unsafe { + SurfaceData::::map_tree(surface, f); + } + Ok(()) + } + + /// Retrieve the parent of this surface + /// + /// Returns `None` is this surface is a root surface + /// + /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn get_parent(&self, surface: &wl_surface::WlSurface) -> Option { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported."); + unsafe { + SurfaceData::::get_parent(surface) + } + } + + /// Retrieve the role status this surface + /// + /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn role_status(&self, surface: &wl_surface::WlSurface) -> RoleStatus { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported."); + unsafe { + SurfaceData::::role_status(surface) + } + } + + /// Register that this surface has a role + /// + /// This makes this surface impossible to become a subsurface, as + /// a surface can only have a single role at a time. + /// + /// Fails if the surface already has a role. + /// + /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn give_role(&self, surface: &wl_surface::WlSurface) -> Result<(),()> { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported."); + unsafe { + SurfaceData::::give_role(surface) + } + } + + /// Register that this surface has no role + /// + /// It is a noop if this surface already didn't have one, but fails if + /// the role was "subsurface". This role is automatically managed and as such + /// cannot be removed manually. + /// + /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn remove_role(&self, surface: &wl_surface::WlSurface) -> Result<(),()> { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported."); + unsafe { + SurfaceData::::remove_role(surface) + } + } +} diff --git a/src/compositor/region.rs b/src/compositor/region.rs new file mode 100644 index 0000000..ff9ebd7 --- /dev/null +++ b/src/compositor/region.rs @@ -0,0 +1,42 @@ +use super::{Rectangle, RegionAttributes, RectangleKind}; + +use std::sync::Mutex; +use wayland_server::Resource; + +use wayland_server::protocol::wl_region; + +#[derive(Default)] +pub struct RegionData { + attributes: RegionAttributes, +} + +impl RegionData { + /// Initialize the user_data of a region, must be called right when the surface is created + pub unsafe fn init(region: &wl_region::WlRegion) { + region.set_user_data(Box::into_raw(Box::new(Mutex::new(RegionData::default()))) as *mut _) + } + + /// Cleans the user_data of that surface, must be called when it is destroyed + pub unsafe fn cleanup(region: &wl_region::WlRegion) { + let ptr = region.get_user_data(); + region.set_user_data(::std::ptr::null_mut()); + let _my_data_mutex: Box> = Box::from_raw(ptr as *mut _); + } + + unsafe fn get_data(region: &wl_region::WlRegion) -> &Mutex { + let ptr = region.get_user_data(); + &*(ptr as *mut _) + } + + pub unsafe fn get_attributes(region: &wl_region::WlRegion) -> RegionAttributes { + let data_mutex = Self::get_data(region); + let data_guard = data_mutex.lock().unwrap(); + data_guard.attributes.clone() + } + + pub unsafe fn add_rectangle(region: &wl_region::WlRegion, kind: RectangleKind, rect: Rectangle) { + let data_mutex = Self::get_data(region); + let mut data_guard = data_mutex.lock().unwrap(); + data_guard.attributes.rects.push((kind, rect)); + } +} diff --git a/src/compositor/tree.rs b/src/compositor/tree.rs new file mode 100644 index 0000000..24f2896 --- /dev/null +++ b/src/compositor/tree.rs @@ -0,0 +1,252 @@ +use super::SurfaceAttributes; +use std::sync::Mutex; + +use wayland_server::{Liveness, Resource}; +use wayland_server::protocol::wl_surface; + +/// Node of a subsurface tree, holding some user specified data type U +/// at each node +/// +/// This type is internal to Smithay, and should not appear in the +/// public API +/// +/// It is a bidirectionnal tree, meaning we can move along it in both +/// direction (top-bottom or bottom-up). We are taking advantage of the +/// fact that lifetime of objects are decided by wayland-server to ensure +/// the cleanup will be done properly, and we won't leak anything. +/// +/// This implementation is not strictly a tree, but rather a directed graph +/// with the constraint that node can have at most one incoming edge. Aka like +/// a tree, but with loops allowed. This is because the wayland protocol does not +/// have a failure case to forbid this. Note that if any node in such a graph does not +/// have a parent, then the graph is a tree and this node is its root. +/// +/// All the methods here are unsafe, because they assume the provided wl_surface object +/// is correctly initialized regarding its user_data. +pub struct SurfaceData { + parent: Option, + children: Vec, + has_role: bool, + attributes: SurfaceAttributes, +} + +/// Status of a surface regarding its role +pub enum RoleStatus { + /// This surface does not have any role + NoRole, + /// This surface is a subsurface + Sursurface, + /// This surface has a role other than subsurface + /// + /// It is thus the root of a subsurface tree that will + /// have to be displayed + HasRole, +} + +impl SurfaceData { + fn new() -> SurfaceData { + SurfaceData { + parent: None, + children: Vec::new(), + has_role: false, + attributes: Default::default(), + } + } + + /// Initialize the user_data of a surface, must be called right when the surface is created + pub unsafe fn init(surface: &wl_surface::WlSurface) { + surface.set_user_data(Box::into_raw(Box::new(Mutex::new(SurfaceData::::new()))) as *mut _) + } +} + +impl SurfaceData { + unsafe fn get_data(surface: &wl_surface::WlSurface) -> &Mutex> { + let ptr = surface.get_user_data(); + &*(ptr as *mut _) + } + + /// Cleans the user_data of that surface, must be called when it is destroyed + pub unsafe fn cleanup(surface: &wl_surface::WlSurface) { + let ptr = surface.get_user_data(); + surface.set_user_data(::std::ptr::null_mut()); + let my_data_mutex: Box>> = Box::from_raw(ptr as *mut _); + let mut my_data = my_data_mutex.into_inner().unwrap(); + if let Some(old_parent) = my_data.parent.take() { + if !old_parent.equals(surface) { + // We had a parent that is not ourselves, lets unregister ourselves from it + let old_parent_mutex = Self::get_data(&old_parent); + let mut old_parent_guard = old_parent_mutex.lock().unwrap(); + old_parent_guard.children.retain(|c| !c.equals(surface)); + } + } + // orphan all our children + for child in &my_data.children { + // don't do anything if this child is ourselves + if child.equals(surface) { + continue; + } + let child_mutex = Self::get_data(child); + let mut child_guard = child_mutex.lock().unwrap(); + child_guard.parent = None; + } + } + + /// Retrieve the current role status of this surface + pub unsafe fn role_status(surface: &wl_surface::WlSurface) -> RoleStatus { + debug_assert!(surface.status() == Liveness::Alive); + let data_mutex = Self::get_data(surface); + let data_guard = data_mutex.lock().unwrap(); + match (data_guard.has_role, data_guard.parent.is_some()) { + (true, true) => RoleStatus::Sursurface, + (true, false) => RoleStatus::HasRole, + (false, false) => RoleStatus::NoRole, + (false, true) => unreachable!(), + } + } + + /// Register that this surface has a role, fails if it already has one + pub unsafe fn give_role(surface: &wl_surface::WlSurface) -> Result<(), ()> { + debug_assert!(surface.status() == Liveness::Alive); + let data_mutex = Self::get_data(surface); + let mut data_guard = data_mutex.lock().unwrap(); + if data_guard.has_role { + return Err(()); + } + data_guard.has_role = true; + Ok(()) + } + + /// Register that this surface has no role + /// + /// It is a noop if this surface already didn't have one, but fails if + /// the role was "subsurface", it must be removed by the `unset_parent` method. + pub unsafe fn remove_role(surface: &wl_surface::WlSurface) -> Result<(), ()> { + debug_assert!(surface.status() == Liveness::Alive); + let data_mutex = Self::get_data(surface); + let mut data_guard = data_mutex.lock().unwrap(); + if data_guard.has_role && data_guard.parent.is_some() { + return Err(()); + } + data_guard.has_role = false; + Ok(()) + } + + /// Sets the parent of a surface + /// if this surface already has a role, does nothing and fails, otherwise + /// its role is now to be a subsurface + pub unsafe fn set_parent(child: &wl_surface::WlSurface, parent: &wl_surface::WlSurface) + -> Result<(), ()> { + debug_assert!(child.status() == Liveness::Alive); + debug_assert!(parent.status() == Liveness::Alive); + + // change child's parent + { + let child_mutex = Self::get_data(child); + let mut child_guard = child_mutex.lock().unwrap(); + // if surface already has a role, it cannot be a subsurface + if child_guard.has_role { + return Err(()); + } + debug_assert!(child_guard.parent.is_none()); + child_guard.parent = Some(parent.clone_unchecked()); + child_guard.has_role = true; + } + // register child to new parent + // double scoping is to be robust to have a child be its own parent + { + let parent_mutex = Self::get_data(parent); + let mut parent_guard = parent_mutex.lock().unwrap(); + parent_guard.children.push(child.clone_unchecked()) + } + Ok(()) + } + + /// Remove a pre-existing parent of this child + /// + /// Does nothing if it has no parent + pub unsafe fn unset_parent(child: &wl_surface::WlSurface) { + debug_assert!(child.status() == Liveness::Alive); + let old_parent = { + let child_mutex = Self::get_data(child); + let mut child_guard = child_mutex.lock().unwrap(); + let old_parent = child_guard.parent.take(); + if old_parent.is_some() { + // We had a parent, so this does not have a role any more + child_guard.has_role = false; + } + old_parent + }; + // unregister from our parent + if let Some(old_parent) = old_parent { + let parent_mutex = Self::get_data(&old_parent); + let mut parent_guard = parent_mutex.lock().unwrap(); + parent_guard.children.retain(|c| !c.equals(child)); + } + } + + /// Retrieve the parent surface (if any) of this surface + pub unsafe fn get_parent(child: &wl_surface::WlSurface) -> Option { + let child_mutex = Self::get_data(child); + let child_guard = child_mutex.lock().unwrap(); + child_guard.parent.as_ref().map(|p| p.clone_unchecked()) + } + + /// Access the attributes associated with a surface + /// + /// Note that an internal lock is taken during access of this data, + /// so the tree cannot be manipulated at the same time + pub unsafe fn with_data(surface: &wl_surface::WlSurface, f: F) + where F: FnOnce(&mut SurfaceAttributes) + { + let data_mutex = Self::get_data(surface); + let mut data_guard = data_mutex.lock().unwrap(); + f(&mut data_guard.attributes) + } + + /// Access sequentially the attributes associated with a surface tree, + /// in a depth-first order + /// + /// Note that an internal lock is taken during access of this data, + /// so the tree cannot be manipulated at the same time. + /// + /// The callback returns wether the traversal should continue or not. Returning + /// false will cause an early-stopping. + pub unsafe fn map_tree(root: &wl_surface::WlSurface, mut f: F) + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + { + // helper function for recursion + unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, f: &mut F) -> bool + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + { + // stop if we met the root, so to not deadlock/inifinte loop + if surface.equals(root) { + return true; + } + + let data_mutex = SurfaceData::::get_data(surface); + let mut data_guard = data_mutex.lock().unwrap(); + // call the callback on ourselves + if f(surface, &mut data_guard.attributes) { + // loop over children + for c in &data_guard.children { + if !map(c, root, f) { + return false; + } + } + } + true + } + + let data_mutex = Self::get_data(root); + let mut data_guard = data_mutex.lock().unwrap(); + // call the callback on ourselves + if f(root, &mut data_guard.attributes) { + // loop over children + for c in &data_guard.children { + if !map::(c, root, &mut f) { + break; + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 3bfd660..4422bd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,8 +32,10 @@ extern crate glium; extern crate slog; extern crate slog_stdlog; -pub mod shm; pub mod backend; + +pub mod compositor; +pub mod shm; pub mod keyboard; fn slog_or_stdlog(logger: L) -> ::slog::Logger From 8809f182b5a589aa8c000aeb9d56240f63a0c996 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 4 Jun 2017 21:36:18 +0200 Subject: [PATCH 03/24] Fuse CompositorGlobal and CompositorHandler --- src/compositor/global.rs | 48 ++++---------------------------------- src/compositor/handlers.rs | 26 ++------------------- src/compositor/mod.rs | 44 ++++++++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 77 deletions(-) diff --git a/src/compositor/global.rs b/src/compositor/global.rs index 96864bf..788e12e 100644 --- a/src/compositor/global.rs +++ b/src/compositor/global.rs @@ -1,58 +1,20 @@ -use super::CompositorToken; -use super::handlers::CompositorHandler; +use super::CompositorHandler; use wayland_server::{Client, EventLoopHandle, GlobalHandler, Init}; use wayland_server::protocol::{wl_compositor, wl_subcompositor}; -pub struct CompositorGlobal { - handler_id: Option, - log: ::slog::Logger, - _data: ::std::marker::PhantomData<*mut U>, -} - -impl CompositorGlobal { - pub fn new(logger: L) -> CompositorGlobal - where L: Into> - { - let log = ::slog_or_stdlog(logger); - CompositorGlobal { - handler_id: None, - log: log.new(o!("smithay_module" => "wompositor_handler")), - _data: ::std::marker::PhantomData, - } - } - - pub fn get_token(&self) -> CompositorToken { - super::make_token(self.handler_id - .expect("CompositorGlobal was not initialized.")) - } -} - -impl Init for CompositorGlobal - where U: Send + Sync + 'static -{ - fn init(&mut self, evlh: &mut EventLoopHandle, _index: usize) { - let id = evlh.add_handler_with_init(CompositorHandler::::new(self.log.clone())); - self.handler_id = Some(id); - } -} - -impl GlobalHandler for CompositorGlobal +impl GlobalHandler for CompositorHandler where U: Send + Sync + 'static { fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_compositor::WlCompositor) { - let hid = self.handler_id - .expect("CompositorGlobal was not initialized."); - evlh.register::<_, CompositorHandler>(&global, hid); + evlh.register::<_, CompositorHandler>(&global, self.my_id); } } -impl GlobalHandler for CompositorGlobal +impl GlobalHandler for CompositorHandler where U: Send + Sync + 'static { fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_subcompositor::WlSubcompositor) { - let hid = self.handler_id - .expect("CompositorGlobal was not initialized."); - evlh.register::<_, CompositorHandler>(&global, hid); + evlh.register::<_, CompositorHandler>(&global, self.my_id); } } diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index e8b017b..b52d76f 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -1,37 +1,15 @@ -use super::{Rectangle, RectangleKind, SubsurfaceAttributes, Damage}; +use super::{Rectangle, RectangleKind, SubsurfaceAttributes, Damage, CompositorHandler}; use super::region::RegionData; use super::tree::SurfaceData; +use super::CompositorToken; use wayland_server::{Client, Destroy, EventLoopHandle, Init, Resource}; use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor, wl_subsurface, wl_surface}; -pub struct CompositorHandler { - my_id: usize, - log: ::slog::Logger, - _data: ::std::marker::PhantomData, -} - struct CompositorDestructor { _t: ::std::marker::PhantomData, } -impl Init for CompositorHandler { - fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) { - self.my_id = index; - debug!(self.log, "Init finished") - } -} - -impl CompositorHandler { - pub fn new(log: ::slog::Logger) -> CompositorHandler { - CompositorHandler { - my_id: ::std::usize::MAX, - log: log, - _data: ::std::marker::PhantomData::, - } - } -} - /* * wl_compositor */ diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 064afbd..bd245e6 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -3,13 +3,11 @@ mod handlers; mod tree; mod region; -pub use self::global::CompositorGlobal; -use self::handlers::CompositorHandler; pub use self::tree::RoleStatus; use self::tree::SurfaceData; use wayland_server::protocol::{wl_buffer, wl_output, wl_surface}; -use wayland_server::resource_is_registered; +use wayland_server::{EventLoopHandle, resource_is_registered, Init}; /// Description of which part of a surface /// should be considered damaged and needs to be redrawn @@ -173,13 +171,6 @@ pub struct CompositorToken { _data: ::std::marker::PhantomData<*mut U>, } -fn make_token(hid: usize) -> CompositorToken { - CompositorToken { - hid: hid, - _data: ::std::marker::PhantomData, - } -} - impl CompositorToken { /// Access the data of a surface /// @@ -274,3 +265,36 @@ impl CompositorToken { } } } + +pub struct CompositorHandler { + my_id: usize, + log: ::slog::Logger, + _data: ::std::marker::PhantomData, +} + +impl Init for CompositorHandler { + fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) { + self.my_id = index; + debug!(self.log, "Init finished") + } +} + +impl CompositorHandler { + pub fn new(logger: L) -> CompositorHandler + where L: Into> + { + let log = ::slog_or_stdlog(logger); + CompositorHandler { + my_id: ::std::usize::MAX, + log: log.new(o!("smithay_module" => "compositor_handler")), + _data: ::std::marker::PhantomData, + } + } + + pub fn get_token(&self) -> CompositorToken { + CompositorToken { + hid: self.my_id, + _data: ::std::marker::PhantomData, + } + } +} From 1e960af5f27039bc39dba44eeb0149e45dc0fcf4 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 4 Jun 2017 22:12:22 +0200 Subject: [PATCH 04/24] Add subhandler for wl_surface.{commit,frame} --- src/compositor/global.rs | 18 +++--- src/compositor/handlers.rs | 116 ++++++++++++++++++++++--------------- src/compositor/mod.rs | 80 +++++++++++++++---------- src/compositor/region.rs | 2 +- 4 files changed, 129 insertions(+), 87 deletions(-) diff --git a/src/compositor/global.rs b/src/compositor/global.rs index 788e12e..a5cd9c9 100644 --- a/src/compositor/global.rs +++ b/src/compositor/global.rs @@ -1,20 +1,22 @@ -use super::CompositorHandler; +use super::{CompositorHandler, Handler as UserHandler}; -use wayland_server::{Client, EventLoopHandle, GlobalHandler, Init}; +use wayland_server::{Client, EventLoopHandle, GlobalHandler}; use wayland_server::protocol::{wl_compositor, wl_subcompositor}; -impl GlobalHandler for CompositorHandler - where U: Send + Sync + 'static +impl GlobalHandler for CompositorHandler + where U: Send + 'static, + H: Send + 'static { fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_compositor::WlCompositor) { - evlh.register::<_, CompositorHandler>(&global, self.my_id); + evlh.register::<_, CompositorHandler>(&global, self.my_id); } } -impl GlobalHandler for CompositorHandler - where U: Send + Sync + 'static +impl GlobalHandler for CompositorHandler + where U: Send + 'static, + H: Send + 'static { fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_subcompositor::WlSubcompositor) { - evlh.register::<_, CompositorHandler>(&global, self.my_id); + evlh.register::<_, CompositorHandler>(&global, self.my_id); } } diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index b52d76f..73b210e 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -1,8 +1,8 @@ -use super::{Rectangle, RectangleKind, SubsurfaceAttributes, Damage, CompositorHandler}; +use super::{CompositorHandler, Damage, Handler as UserHandler, Rectangle, RectangleKind, + SubsurfaceAttributes}; use super::region::RegionData; use super::tree::SurfaceData; -use super::CompositorToken; -use wayland_server::{Client, Destroy, EventLoopHandle, Init, Resource}; +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}; @@ -14,26 +14,31 @@ struct CompositorDestructor { * wl_compositor */ -impl wl_compositor::Handler for CompositorHandler { - fn create_surface(&mut self, evqh: &mut EventLoopHandle, _: &Client, - _: &wl_compositor::WlCompositor, id: wl_surface::WlSurface) { +impl wl_compositor::Handler for CompositorHandler + where U: Default + Send + 'static, + H: UserHandler + Send + 'static +{ + fn create_surface(&mut self, evqh: &mut EventLoopHandle, _: &Client, _: &wl_compositor::WlCompositor, + id: wl_surface::WlSurface) { unsafe { SurfaceData::::init(&id) }; - evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); + evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); } - fn create_region(&mut self, evqh: &mut EventLoopHandle, _: &Client, - _: &wl_compositor::WlCompositor, id: wl_region::WlRegion) { + fn create_region(&mut self, evqh: &mut EventLoopHandle, _: &Client, _: &wl_compositor::WlCompositor, + id: wl_region::WlRegion) { unsafe { RegionData::init(&id) }; - evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); + evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); } } -unsafe impl ::wayland_server::Handler - for CompositorHandler { +unsafe impl ::wayland_server::Handler for CompositorHandler + where U: Default + Send + 'static, + H: UserHandler + Send + 'static +{ unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_compositor::WlCompositor, opcode: u32, args: *const ::wayland_server::sys::wl_argument) -> Result<(), ()> { - as ::wayland_server::protocol::wl_compositor::Handler>::__message(self, evq, client, resource, opcode, args) + as ::wayland_server::protocol::wl_compositor::Handler>::__message(self, evq, client, resource, opcode, args) } } @@ -41,7 +46,7 @@ unsafe impl ::wayland_server::Handler wl_surface::Handler for CompositorHandler { +impl wl_surface::Handler for CompositorHandler { fn attach(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, buffer: Option<&wl_buffer::WlBuffer>, x: i32, y: i32) { unsafe { @@ -52,13 +57,19 @@ impl wl_surface::Handler for CompositorHandler { fn damage(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32, y: i32, width: i32, height: i32) { unsafe { - SurfaceData::::with_data(surface, - |d| d.damage = Damage::Surface(Rectangle { x, y, width, height })); + SurfaceData::::with_data(surface, |d| { + d.damage = Damage::Surface(Rectangle { + x, + y, + width, + height, + }) + }); } } - fn frame(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, + fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, callback: wl_callback::WlCallback) { - unimplemented!() + UserHandler::frame(&mut self.handler, evlh, client, surface, callback); } fn set_opaque_region(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, region: Option<&wl_region::WlRegion>) { @@ -74,8 +85,8 @@ impl wl_surface::Handler for CompositorHandler { SurfaceData::::with_data(surface, |d| d.input_region = attributes); } } - fn commit(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface) { - unimplemented!() + fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface) { + UserHandler::commit(&mut self.handler, evlh, client, surface); } fn set_buffer_transform(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, transform: wl_output::Transform) { @@ -92,18 +103,24 @@ impl wl_surface::Handler for CompositorHandler { fn damage_buffer(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32, y: i32, width: i32, height: i32) { unsafe { - SurfaceData::::with_data(surface, - |d| d.damage = Damage::Buffer(Rectangle { x, y, width, height })); + SurfaceData::::with_data(surface, |d| { + d.damage = Damage::Buffer(Rectangle { + x, + y, + width, + height, + }) + }); } } } -unsafe impl ::wayland_server::Handler for CompositorHandler { +unsafe impl ::wayland_server::Handler for CompositorHandler { unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_surface::WlSurface, opcode: u32, args: *const ::wayland_server::sys::wl_argument) -> Result<(), ()> { - as ::wayland_server::protocol::wl_surface::Handler>::__message(self, evq, client, resource, opcode, args) + as ::wayland_server::protocol::wl_surface::Handler>::__message(self, evq, client, resource, opcode, args) } } @@ -117,11 +134,12 @@ impl Destroy for CompositorDestructor { * wl_region */ -impl wl_region::Handler for CompositorHandler { +impl wl_region::Handler for CompositorHandler { fn add(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32, y: i32, width: i32, height: i32) { unsafe { - RegionData::add_rectangle(region, RectangleKind::Add, + RegionData::add_rectangle(region, + RectangleKind::Add, Rectangle { x, y, @@ -133,7 +151,8 @@ impl wl_region::Handler for CompositorHandler { fn subtract(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32, y: i32, width: i32, height: i32) { unsafe { - RegionData::add_rectangle(region, RectangleKind::Subtract, + RegionData::add_rectangle(region, + RectangleKind::Subtract, Rectangle { x, y, @@ -144,12 +163,12 @@ impl wl_region::Handler for CompositorHandler { } } -unsafe impl ::wayland_server::Handler for CompositorHandler { +unsafe impl ::wayland_server::Handler for CompositorHandler { unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_region::WlRegion, opcode: u32, args: *const ::wayland_server::sys::wl_argument) -> Result<(), ()> { - as ::wayland_server::protocol::wl_region::Handler>::__message(self, evq, client, resource, opcode, args) + as ::wayland_server::protocol::wl_region::Handler>::__message(self, evq, client, resource, opcode, args) } } @@ -163,7 +182,10 @@ impl Destroy for CompositorDestructor { * wl_subcompositor */ -impl wl_subcompositor::Handler for CompositorHandler { +impl wl_subcompositor::Handler for CompositorHandler + where U: Send + 'static, + H: Send + 'static +{ fn get_subsurface(&mut self, evqh: &mut EventLoopHandle, _: &Client, resource: &wl_subcompositor::WlSubcompositor, id: wl_subsurface::WlSubsurface, surface: &wl_surface::WlSurface, parent: &wl_surface::WlSurface) { @@ -176,17 +198,19 @@ impl wl_subcompositor::Handler for CompositorHandler { SurfaceData::::with_data(surface, |d| d.subsurface_attributes = Some(Default::default())); } - evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); + evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); } } -unsafe impl ::wayland_server::Handler - for CompositorHandler { +unsafe impl ::wayland_server::Handler for CompositorHandler + where U: Send + 'static, + H: Send + 'static +{ unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_subcompositor::WlSubcompositor, opcode: u32, args: *const ::wayland_server::sys::wl_argument) -> Result<(), ()> { - as ::wayland_server::protocol::wl_subcompositor::Handler>::__message(self, evq, client, resource, opcode, args) + as ::wayland_server::protocol::wl_subcompositor::Handler>::__message(self, evq, client, resource, opcode, args) } } @@ -202,9 +226,9 @@ unsafe fn with_subsurface_attributes(subsurface: &wl_subsurface::WlSubsurf SurfaceData::::with_data(surface, |d| f(d.subsurface_attributes.as_mut().unwrap())); } -impl wl_subsurface::Handler for CompositorHandler { - fn set_position(&mut self, _: &mut EventLoopHandle, _: &Client, - resource: &wl_subsurface::WlSubsurface, x: i32, y: i32) { +impl wl_subsurface::Handler for CompositorHandler { + fn set_position(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_subsurface::WlSubsurface, + x: i32, y: i32) { unsafe { with_subsurface_attributes::(resource, |attrs| { attrs.x = x; @@ -212,34 +236,32 @@ impl wl_subsurface::Handler for CompositorHandler { }); } } - fn place_above(&mut self, _: &mut EventLoopHandle, _: &Client, - resource: &wl_subsurface::WlSubsurface, sibling: &wl_surface::WlSurface) { + 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) { + 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 set_sync(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_subsurface::WlSubsurface) { unsafe { with_subsurface_attributes::(resource, |attrs| { attrs.sync = true; }); } } - fn set_desync(&mut self, _: &mut EventLoopHandle, _: &Client, - resource: &wl_subsurface::WlSubsurface) { + fn set_desync(&mut self, _: &mut EventLoopHandle, _: &Client, resource: &wl_subsurface::WlSubsurface) { unsafe { with_subsurface_attributes::(resource, |attrs| { attrs.sync = false; }); } } } -unsafe impl ::wayland_server::Handler for CompositorHandler { +unsafe impl ::wayland_server::Handler for CompositorHandler { unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_subsurface::WlSubsurface, opcode: u32, args: *const ::wayland_server::sys::wl_argument) -> Result<(), ()> { - as ::wayland_server::protocol::wl_subsurface::Handler>::__message(self, evq, client, resource, opcode, args) + as ::wayland_server::protocol::wl_subsurface::Handler>::__message(self, evq, client, resource, opcode, args) } } diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index bd245e6..2af9f44 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -5,9 +5,9 @@ mod region; pub use self::tree::RoleStatus; use self::tree::SurfaceData; +use wayland_server::{Client, EventLoopHandle, Init, resource_is_registered}; -use wayland_server::protocol::{wl_buffer, wl_output, wl_surface}; -use wayland_server::{EventLoopHandle, resource_is_registered, Init}; +use wayland_server::protocol::{wl_buffer, wl_callback, wl_output, wl_surface}; /// Description of which part of a surface /// should be considered damaged and needs to be redrawn @@ -19,7 +19,7 @@ pub enum Damage { /// A rectangle containing the smaazed zone, in buffer coordinates /// /// Note: Buffer scaling must be taken into consideration - Buffer(Rectangle) + Buffer(Rectangle), } /// Data associated with a surface, aggreged by the handlers @@ -166,12 +166,13 @@ impl Default for RegionAttributes { /// access data associated with the wl_surface and wl_region managed /// by the `CompositorGlobal` that provided it. #[derive(Copy,Clone)] -pub struct CompositorToken { +pub struct CompositorToken { hid: usize, _data: ::std::marker::PhantomData<*mut U>, + _handler: ::std::marker::PhantomData<*mut H>, } -impl CompositorToken { +impl CompositorToken { /// Access the data of a surface /// /// The closure will be called with the contents of the data associated with this surface. @@ -181,7 +182,7 @@ impl CompositorToken { pub fn with_surface_data(&self, surface: &wl_surface::WlSurface, f: F) where F: FnOnce(&mut SurfaceAttributes) { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported."); unsafe { SurfaceData::::with_data(surface, f); @@ -198,7 +199,7 @@ impl CompositorToken { pub fn with_surface_tree(&self, surface: &wl_surface::WlSurface, f: F) -> Result<(), ()> where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported."); unsafe { SurfaceData::::map_tree(surface, f); @@ -213,23 +214,19 @@ impl CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn get_parent(&self, surface: &wl_surface::WlSurface) -> Option { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported."); - unsafe { - SurfaceData::::get_parent(surface) - } + unsafe { SurfaceData::::get_parent(surface) } } - + /// Retrieve the role status this surface /// /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn role_status(&self, surface: &wl_surface::WlSurface) -> RoleStatus { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported."); - unsafe { - SurfaceData::::role_status(surface) - } + unsafe { SurfaceData::::role_status(surface) } } /// Register that this surface has a role @@ -241,12 +238,10 @@ impl CompositorToken { /// /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). - pub fn give_role(&self, surface: &wl_surface::WlSurface) -> Result<(),()> { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + pub fn give_role(&self, surface: &wl_surface::WlSurface) -> Result<(), ()> { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported."); - unsafe { - SurfaceData::::give_role(surface) - } + unsafe { SurfaceData::::give_role(surface) } } /// Register that this surface has no role @@ -257,44 +252,67 @@ impl CompositorToken { /// /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). - pub fn remove_role(&self, surface: &wl_surface::WlSurface) -> Result<(),()> { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + pub fn remove_role(&self, surface: &wl_surface::WlSurface) -> Result<(), ()> { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported."); - unsafe { - SurfaceData::::remove_role(surface) - } + unsafe { SurfaceData::::remove_role(surface) } } } -pub struct CompositorHandler { +pub struct CompositorHandler { my_id: usize, log: ::slog::Logger, + handler: H, _data: ::std::marker::PhantomData, } -impl Init for CompositorHandler { +impl Init for CompositorHandler { fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) { self.my_id = index; debug!(self.log, "Init finished") } } -impl CompositorHandler { - pub fn new(logger: L) -> CompositorHandler +impl CompositorHandler { + /// Create a new CompositorHandler + pub fn new(handler: H, logger: L) -> CompositorHandler where L: Into> { let log = ::slog_or_stdlog(logger); CompositorHandler { my_id: ::std::usize::MAX, log: log.new(o!("smithay_module" => "compositor_handler")), + handler: handler, _data: ::std::marker::PhantomData, } } - pub fn get_token(&self) -> CompositorToken { + /// Create a token to access the data associated to the objects managed by this handler. + pub fn get_token(&self) -> CompositorToken { + assert!(self.my_id != ::std::usize::MAX, + "CompositorHandler is not initialized yet."); CompositorToken { hid: self.my_id, _data: ::std::marker::PhantomData, + _handler: ::std::marker::PhantomData, } } + + /// Access the underlying sub-handler + pub fn get_handler(&mut self) -> &mut H { + &mut self.handler + } +} + +/// Sub-handler trait for surface event handling +/// +/// The global provided by Smithay cannot process these events for you, so they +/// are forwarded directly to a handler implementing this trait that you must provide +/// at creation of the `CompositorHandler`. +pub trait Handler { + /// See `wayland_server::protocol::wl_surface::Handler::commit` + fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface); + /// See `wayland_server::protocol::wl_surface::Handler::frame` + fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, + callback: wl_callback::WlCallback); } diff --git a/src/compositor/region.rs b/src/compositor/region.rs index ff9ebd7..eb09e95 100644 --- a/src/compositor/region.rs +++ b/src/compositor/region.rs @@ -1,4 +1,4 @@ -use super::{Rectangle, RegionAttributes, RectangleKind}; +use super::{Rectangle, RectangleKind, RegionAttributes}; use std::sync::Mutex; use wayland_server::Resource; From a5ae27be8422db4fd9d1c115d2bd2ee4231768c3 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 4 Jun 2017 22:41:42 +0200 Subject: [PATCH 05/24] Implement wl_subsurface.place_{above,below}. --- src/compositor/handlers.rs | 44 +++++++++++++++++++------------ src/compositor/mod.rs | 3 ++- src/compositor/tree.rs | 53 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 17 deletions(-) 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, From deb072afbb81f0eb1942e00bd5d71f952ef68d7f Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 14:31:42 +0200 Subject: [PATCH 06/24] compositor: give access to surface children and region metadata --- src/compositor/mod.rs | 20 ++++++++++++++++++++ src/compositor/tree.rs | 11 +++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 084330c..7757352 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -220,6 +220,16 @@ impl CompositorToken { unsafe { SurfaceData::::get_parent(surface) } } + /// Retrieve the children of this surface + /// + /// If the surface is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn get_children(&self, surface: &wl_surface::WlSurface) -> Vec { + assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported."); + unsafe { SurfaceData::::get_children(surface) } + } + /// Retrieve the role status this surface /// /// If the surface is not managed by the CompositorGlobal that provided this token, this @@ -258,6 +268,16 @@ impl CompositorToken { "Accessing the data of foreign surfaces is not supported."); unsafe { SurfaceData::::remove_role(surface) } } + + /// Retrieve the metadata associated with a wl_region + /// + /// If the region is not managed by the CompositorGlobal that provided this token, this + /// will panic (having more than one compositor is not supported). + pub fn get_region_attributes(&self, region: &wl_region::WlRegion) -> RegionAttributes { + assert!(resource_is_registered::<_, CompositorHandler>(region, self.hid), + "Accessing the data of foreign regions is not supported."); + unsafe { RegionData::get_attributes(region) } + } } pub struct CompositorHandler { diff --git a/src/compositor/tree.rs b/src/compositor/tree.rs index 2bca930..a78558f 100644 --- a/src/compositor/tree.rs +++ b/src/compositor/tree.rs @@ -196,6 +196,17 @@ impl SurfaceData { child_guard.parent.as_ref().map(|p| p.clone_unchecked()) } + /// Retrieve the parent surface (if any) of this surface + pub unsafe fn get_children(child: &wl_surface::WlSurface) -> Vec { + let child_mutex = Self::get_data(child); + let child_guard = child_mutex.lock().unwrap(); + child_guard + .children + .iter() + .map(|p| p.clone_unchecked()) + .collect() + } + /// Reorders a surface relative to one of its sibling /// /// Fails if `relative_to` is not a sibling or parent of `surface`. From 43d1812e1fadf35adb2b3c4c041fc17587cbaf80 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 14:32:00 +0200 Subject: [PATCH 07/24] Donc use default features for glium It pulls two versions of winit as deps for nothing. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8793c6a..e62fc1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ slog-stdlog = "2.0.0-0.2" libloading = "0.4.0" wayland-client = { version = "~0.8.6", optional = true } winit = { git = "https://github.com/tomaka/winit.git", optional = true } -glium = { version = "~0.16.0", optional = true } +glium = { version = "~0.16.0", optional = true, default-features="false" } input = { version = "~0.2.0", optional = true } clippy = { version = "*", optional = true } rental = "0.4.11" From 9fe6f16af3d1449c793f2fe032bf408189c01c47 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 14:32:37 +0200 Subject: [PATCH 08/24] compositor: provide default noop impls from Handler --- src/compositor/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 7757352..d62da0c 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -330,10 +330,12 @@ impl CompositorHandler { /// The global provided by Smithay cannot process these events for you, so they /// are forwarded directly to a handler implementing this trait that you must provide /// at creation of the `CompositorHandler`. +#[allow(unused_variables)] pub trait Handler { /// See `wayland_server::protocol::wl_surface::Handler::commit` - fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface); + fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface) {} /// See `wayland_server::protocol::wl_surface::Handler::frame` fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, - callback: wl_callback::WlCallback); + callback: wl_callback::WlCallback) { + } } From 627008dbce0529c0641b0b2c780852674fe0efe2 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 14:33:03 +0200 Subject: [PATCH 09/24] compositor: module documentation --- src/compositor/mod.rs | 104 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index d62da0c..3bcd9f8 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -1,13 +1,107 @@ +//! Utilities for handling surfaces, subsurfaces and regions +//! +//! This module provides the `CompositorHandler` type, with implements +//! automatic handling of sufaces, subsurfaces and region wayland objects, +//! by being registered as a global handler for `wl_compositor` and +//! `wl_subcompositor`. +//! +//! ## Why use this handler +//! +//! This handler does a simple job: it stores in a coherent way the state of +//! surface trees with subsurfaces, to provide you a direct access to the tree +//! structure and all surface metadata. +//! +//! As such, you can, given a root surface with a role requiring it to be displayed, +//! you can iterate over the whole tree of subsurfaces to recover all the metadata you +//! need to display the subsurface tree. +//! +//! This handler will not do anything more than present you the metadata specified by the +//! client in a coherent and practical way. All the logic regarding to drawing itself, and +//! the positionning of windows (surface trees) one relative to another is out of its scope. +//! +//! ## How to use it +//! +//! ### Initialization +//! +//! To initialize this handler, simply instanciate it and register it to the event loop +//! as a global handler for wl_compositor and wl_subcompositor: +//! +//! ``` +//! # extern crate wayland_server; +//! # extern crate smithay; +//! use wayland_server::protocol::wl_compositor::WlCompositor; +//! use wayland_server::protocol::wl_subcompositor::WlSubcompositor; +//! use smithay::compositor; +//! +//! // Define some user data to be associated with the surfaces. +//! // It must implement the Default trait, which will represent the state of a surface which +//! // has just been created. +//! #[derive(Default)] +//! struct MyData { +//! // whatever you need here +//! } +//! +//! // Define a sub-handler to take care of the events the CompositorHandler does not rack for you +//! struct MyHandler { +//! // whatever you need +//! } +//! +//! // Implement the handler trait for this sub-handler +//! impl compositor::Handler for MyHandler { +//! // See the trait documentation for its implementation +//! // A default implementation for each method is provided, that does nothing +//! } +//! +//! // A type alias to shorten things: +//! type MyCompositorHandler = compositor::CompositorHandler; +//! +//! # fn main() { +//! # let (_display, mut event_loop) = wayland_server::create_display(); +//! +//! // Instanciate the CompositorHandler and give it to the event loop +//! let compositor_hid = event_loop.add_handler_with_init( +//! MyCompositorHandler::new(Myhandler::new()) +//! ); +//! +//! // Register it as a handler for wl_compositor +//! event_loop.register_global::(compositor_hid); +//! +//! // Register it as a handler for wl_subcompositor +//! event_loop.register_global::(compositor_hid); +//! +//! // retrieve the token needed to access the surfaces' metadata +//! let compositor_token = { +//! let state = event_loop.state(); +//! state.get_handler::>(handler_id).get_token() +//! }; +//! +//! // You're now ready to go! +//! # } +//! ``` +//! +//! ### Use the surface metadata +//! +//! As you can see in the previous example, in the end we are retrieving a token from +//! the `CompositorHandler`. This token is necessary to retrieve the metadata associated with +//! a surface. It can be cloned, and is sendable accross threads. See `CompositorToken` for +//! the details of what it enables you. +//! +//! The surface metadata is held in the `SurfaceAttributes` struct. In contains double-buffered +//! state pending from the client as defined by the protocol for wl_surface, as well as your +//! user-defined type holding any data you need to have associated with a struct. See its +//! documentation for details. + mod global; mod handlers; mod tree; mod region; +use self::region::RegionData; pub use self::tree::RoleStatus; use self::tree::SurfaceData; use wayland_server::{Client, EventLoopHandle, Init, resource_is_registered}; -use wayland_server::protocol::{wl_buffer, wl_callback, wl_output, wl_surface}; +use wayland_server::protocol::{wl_buffer, wl_callback, wl_output, wl_region, wl_surface}; /// Description of which part of a surface /// should be considered damaged and needs to be redrawn @@ -280,6 +374,14 @@ impl CompositorToken { } } +/// A struct handling the `wl_compositor` and `wl_subcompositor` globals +/// +/// It allows you to choose a custom `U` type to store data you want +/// associated with the surfaces in their metadata, as well a providing +/// a sub-handler to handle the events defined by the `Handler` trait +/// defined in this module. +/// +/// See the module-level documentation for instructions and examples of use. pub struct CompositorHandler { my_id: usize, log: ::slog::Logger, From f2698ec39aa9e9c29af1e6afe4e95ffcc9b21b39 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 14:55:03 +0200 Subject: [PATCH 10/24] Fix cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e62fc1f..aa8598f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ slog-stdlog = "2.0.0-0.2" libloading = "0.4.0" wayland-client = { version = "~0.8.6", optional = true } winit = { git = "https://github.com/tomaka/winit.git", optional = true } -glium = { version = "~0.16.0", optional = true, default-features="false" } +glium = { version = "~0.16.0", optional = true, default-features = false } input = { version = "~0.2.0", optional = true } clippy = { version = "*", optional = true } rental = "0.4.11" From 267847eebf4417f13478aed600d4a1d02f1de848 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 18:50:47 +0200 Subject: [PATCH 11/24] compositor: add logging --- src/compositor/global.rs | 2 ++ src/compositor/handlers.rs | 19 +++++++++++++++++++ src/compositor/mod.rs | 1 + 3 files changed, 22 insertions(+) diff --git a/src/compositor/global.rs b/src/compositor/global.rs index a5cd9c9..43df315 100644 --- a/src/compositor/global.rs +++ b/src/compositor/global.rs @@ -8,6 +8,7 @@ impl GlobalHandler for H: Send + 'static { fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_compositor::WlCompositor) { + debug!(self.log, "New compositor global binded."); evlh.register::<_, CompositorHandler>(&global, self.my_id); } } @@ -17,6 +18,7 @@ impl GlobalHandler for CompositorHandle H: Send + 'static { fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_subcompositor::WlSubcompositor) { + debug!(self.log, "New subcompositor global binded."); evlh.register::<_, CompositorHandler>(&global, self.my_id); } } diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index 266fb6d..49660ef 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -20,11 +20,13 @@ impl wl_compositor::Handler for CompositorHandler { fn create_surface(&mut self, evqh: &mut EventLoopHandle, _: &Client, _: &wl_compositor::WlCompositor, id: wl_surface::WlSurface) { + trace!(self.log, "New surface created."); unsafe { SurfaceData::::init(&id) }; evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); } fn create_region(&mut self, evqh: &mut EventLoopHandle, _: &Client, _: &wl_compositor::WlCompositor, id: wl_region::WlRegion) { + trace!(self.log, "New region created."); unsafe { RegionData::init(&id) }; evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); } @@ -49,6 +51,7 @@ unsafe impl ::wayland_server::Handler for Com impl wl_surface::Handler for CompositorHandler { fn attach(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, buffer: Option<&wl_buffer::WlBuffer>, x: i32, y: i32) { + trace!(self.log, "Attaching buffer to surface."); unsafe { SurfaceData::::with_data(surface, |d| d.buffer = Some(buffer.map(|b| (b.clone_unchecked(), (x, y))))); @@ -56,6 +59,7 @@ impl wl_surface::Handler for CompositorHandler { } fn damage(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32, y: i32, width: i32, height: i32) { + trace!(self.log, "Registering damage to surface."); unsafe { SurfaceData::::with_data(surface, |d| { d.damage = Damage::Surface(Rectangle { @@ -69,10 +73,12 @@ impl wl_surface::Handler for CompositorHandler { } fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, callback: wl_callback::WlCallback) { + trace!(self.log, "Frame surface callback."); UserHandler::frame(&mut self.handler, evlh, client, surface, callback); } fn set_opaque_region(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, region: Option<&wl_region::WlRegion>) { + trace!(self.log, "Setting surface opaque region."); unsafe { let attributes = region.map(|r| RegionData::get_attributes(r)); SurfaceData::::with_data(surface, |d| d.opaque_region = attributes); @@ -80,28 +86,33 @@ impl wl_surface::Handler for CompositorHandler { } fn set_input_region(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, region: Option<&wl_region::WlRegion>) { + trace!(self.log, "Setting surface input region."); unsafe { let attributes = region.map(|r| RegionData::get_attributes(r)); SurfaceData::::with_data(surface, |d| d.input_region = attributes); } } fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface) { + trace!(self.log, "Commit surface callback."); UserHandler::commit(&mut self.handler, evlh, client, surface); } fn set_buffer_transform(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, transform: wl_output::Transform) { + trace!(self.log, "Setting surface's buffer transform."); unsafe { SurfaceData::::with_data(surface, |d| d.buffer_transform = transform); } } fn set_buffer_scale(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, scale: i32) { + trace!(self.log, "Setting surface's buffer scale."); unsafe { SurfaceData::::with_data(surface, |d| d.buffer_scale = scale); } } fn damage_buffer(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32, y: i32, width: i32, height: i32) { + trace!(self.log, "Registering damage to surface (buffer coordinates)."); unsafe { SurfaceData::::with_data(surface, |d| { d.damage = Damage::Buffer(Rectangle { @@ -137,6 +148,7 @@ impl Destroy for CompositorDestructor { impl wl_region::Handler for CompositorHandler { fn add(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32, y: i32, width: i32, height: i32) { + trace!(self.log, "Adding rectangle to a region."); unsafe { RegionData::add_rectangle(region, RectangleKind::Add, @@ -150,6 +162,7 @@ impl wl_region::Handler for CompositorHandler { } fn subtract(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32, y: i32, width: i32, height: i32) { + trace!(self.log, "Subtracting rectangle to a region."); unsafe { RegionData::add_rectangle(region, RectangleKind::Subtract, @@ -189,6 +202,7 @@ impl wl_subcompositor::Handler for CompositorHandler fn get_subsurface(&mut self, evqh: &mut EventLoopHandle, _: &Client, resource: &wl_subcompositor::WlSubcompositor, id: wl_subsurface::WlSubsurface, surface: &wl_surface::WlSurface, parent: &wl_surface::WlSurface) { + trace!(self.log, "Creating new subsurface."); if let Err(()) = unsafe { SurfaceData::::set_parent(surface, parent) } { resource.post_error(wl_subcompositor::Error::BadSurface as u32, "Surface already has a role.".into()); return @@ -229,6 +243,7 @@ unsafe fn with_subsurface_attributes(subsurface: &wl_subsurface::WlSubsurf impl wl_subsurface::Handler for CompositorHandler { fn set_position(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface, x: i32, y: i32) { + trace!(self.log, "Setting subsurface position."); unsafe { with_subsurface_attributes::(subsurface, |attrs| { attrs.x = x; @@ -238,6 +253,7 @@ impl wl_subsurface::Handler for CompositorHandler { } fn place_above(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface, sibling: &wl_surface::WlSurface) { + trace!(self.log, "Setting subsurface above an other."); unsafe { let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut wl_surface::WlSurface); @@ -248,6 +264,7 @@ impl wl_subsurface::Handler for CompositorHandler { } fn place_below(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface, sibling: &wl_surface::WlSurface) { + trace!(self.log, "Setting subsurface below an other."); unsafe { let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut wl_surface::WlSurface); @@ -257,11 +274,13 @@ impl wl_subsurface::Handler for CompositorHandler { } } fn set_sync(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface) { + trace!(self.log, "Setting subsurface sync."; "sync_status" => true); unsafe { with_subsurface_attributes::(subsurface, |attrs| { attrs.sync = true; }); } } fn set_desync(&mut self, _: &mut EventLoopHandle, _: &Client, subsurface: &wl_subsurface::WlSubsurface) { + trace!(self.log, "Setting subsurface sync."; "sync_status" => false); unsafe { with_subsurface_attributes::(subsurface, |attrs| { attrs.sync = false; }); } diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 3bcd9f8..2ba51a7 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -414,6 +414,7 @@ impl CompositorHandler { pub fn get_token(&self) -> CompositorToken { assert!(self.my_id != ::std::usize::MAX, "CompositorHandler is not initialized yet."); + trace!(self.log, "Creating a compositor token."); CompositorToken { hid: self.my_id, _data: ::std::marker::PhantomData, From e00965137108fdacab49f941b0ecc3dfee3df77e Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 22:47:27 +0200 Subject: [PATCH 12/24] compositor: various doc fixes --- src/compositor/mod.rs | 26 +++++++++++++++++++------- src/compositor/tree.rs | 4 ++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 2ba51a7..927401c 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -60,19 +60,19 @@ //! //! // Instanciate the CompositorHandler and give it to the event loop //! let compositor_hid = event_loop.add_handler_with_init( -//! MyCompositorHandler::new(Myhandler::new()) +//! MyCompositorHandler::new(MyHandler{ /* ... */ }, None /* put a logger here */) //! ); //! //! // Register it as a handler for wl_compositor -//! event_loop.register_global::(compositor_hid); +//! event_loop.register_global::(compositor_hid, 4); //! //! // Register it as a handler for wl_subcompositor -//! event_loop.register_global::(compositor_hid); +//! event_loop.register_global::(compositor_hid, 1); //! //! // retrieve the token needed to access the surfaces' metadata //! let compositor_token = { //! let state = event_loop.state(); -//! state.get_handler::>(handler_id).get_token() +//! state.get_handler::(compositor_hid).get_token() //! }; //! //! // You're now ready to go! @@ -110,7 +110,7 @@ pub enum Damage { Full, /// A rectangle containing the damaged zone, in surface coordinates Surface(Rectangle), - /// A rectangle containing the smaazed zone, in buffer coordinates + /// A rectangle containing the damaged zone, in buffer coordinates /// /// Note: Buffer scaling must be taken into consideration Buffer(Rectangle), @@ -435,9 +435,21 @@ impl CompositorHandler { /// at creation of the `CompositorHandler`. #[allow(unused_variables)] pub trait Handler { - /// See `wayland_server::protocol::wl_surface::Handler::commit` + /// The double-buffered state has been validated by the client + /// + /// At this point, the pending state that has been accumulated in the `SurfaceAttributes` associated + /// to this surface should be integrated into the current state of the surface. + /// + /// See [`wayland_server::protocol::wl_surface::Handler::commit`](https://docs.rs/wayland-server/*/wayland_server/protocol/wl_surface/trait.Handler.html#method.commit) + /// for more details fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface) {} - /// See `wayland_server::protocol::wl_surface::Handler::frame` + /// The client asks to be notified when would be a good time to update the contents of this surface + /// + /// You must keep the provided `WlCallback` and trigger it at the appropriate time by calling + /// its `done()` method. + /// + /// See [`wayland_server::protocol::wl_surface::Handler::frame`](https://docs.rs/wayland-server/*/wayland_server/protocol/wl_surface/trait.Handler.html#method.frame) + /// for more details fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, callback: wl_callback::WlCallback) { } diff --git a/src/compositor/tree.rs b/src/compositor/tree.rs index a78558f..8a77bd3 100644 --- a/src/compositor/tree.rs +++ b/src/compositor/tree.rs @@ -35,7 +35,7 @@ pub enum RoleStatus { /// This surface does not have any role NoRole, /// This surface is a subsurface - Sursurface, + Subsurface, /// This surface has a role other than subsurface /// /// It is thus the root of a subsurface tree that will @@ -102,7 +102,7 @@ impl SurfaceData { let data_mutex = Self::get_data(surface); let data_guard = data_mutex.lock().unwrap(); match (data_guard.has_role, data_guard.parent.is_some()) { - (true, true) => RoleStatus::Sursurface, + (true, true) => RoleStatus::Subsurface, (true, false) => RoleStatus::HasRole, (false, false) => RoleStatus::NoRole, (false, true) => unreachable!(), From 712fc5b8b894694ee901ac644296726f7897192f Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 23:03:25 +0200 Subject: [PATCH 13/24] examples: improve simple.rs --- Cargo.toml | 3 ++- examples/simple.rs | 58 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aa8598f..772bdd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,8 @@ rental = "0.4.11" gl_generator = "0.5" [dev-dependencies] -slog-term = "~1.5" +slog-term = "2.0" +slog-async = "2.0" [features] default = ["backend_winit", "backend_libinput", "renderer_glium"] diff --git a/examples/simple.rs b/examples/simple.rs index ef264ef..29a1f97 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -2,36 +2,70 @@ extern crate wayland_server; extern crate smithay; extern crate glium; +#[macro_use] +extern crate slog; +extern crate slog_async; +extern crate slog_term; + +use slog::*; + use glium::Surface; + use smithay::backend::graphics::glium::IntoGlium; use smithay::backend::input::InputBackend; use smithay::backend::winit; use smithay::shm::ShmGlobal; -use wayland_server::protocol::wl_shm; +use smithay::compositor::{CompositorHandler, self}; + +use wayland_server::protocol::{wl_compositor, wl_shm, wl_subcompositor}; + +struct SurfaceHandler; + +impl compositor::Handler for SurfaceHandler { +} fn main() { + // A logger facility, here we use the terminal for this example + let log = Logger::root(slog_async::Async::default(slog_term::term_full().fuse()).fuse(), o!()); + // Initialize a simple backend for testing - let (renderer, mut input) = winit::init().unwrap(); + let (renderer, mut input) = winit::init(log.clone()).unwrap(); let (_display, mut event_loop) = wayland_server::create_display(); + /* + * Initialize wl_shm global + */ // Insert the ShmGlobal as a handler to your event loop // Here, we specify tha the standard Argb8888 and Xrgb8888 is the only supported. - let handler_id = event_loop.add_handler_with_init(ShmGlobal::new( - vec![], - None, /* we don't provide a logger here */ - )); - + let shm_handler_id = + event_loop.add_handler_with_init(ShmGlobal::new(vec![], log.clone())); // Register this handler to advertise a wl_shm global of version 1 - let shm_global = event_loop.register_global::(handler_id, 1); + event_loop.register_global::(shm_handler_id, 1); - // Retrieve the shm token for later use to access the buffers - let shm_token = { + /* + * Initialize the compositor global + */ + let compositor_handler_id = + event_loop.add_handler_with_init(CompositorHandler::<(),_>::new(SurfaceHandler, log.clone())); + // register it to handle wl_compositor and wl_subcompositor + event_loop.register_global::>(compositor_handler_id, 4); + event_loop.register_global::>(compositor_handler_id, 1); + + /* + * retrieve the tokens + */ + let (shm_token, compositor_token) = { let state = event_loop.state(); - state.get_handler::(handler_id).get_token() + ( + state.get_handler::(shm_handler_id).get_token(), + state.get_handler::>(compositor_handler_id).get_token() + ) }; - // Init glium + /* + * Initialize glium + */ let context = renderer.into_glium(); From bf9ee9a3952ea4d29494cc23e1ed0e7e5ddd6187 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 11 Jun 2017 23:08:59 +0200 Subject: [PATCH 14/24] cargo fmt --- examples/simple.rs | 23 +++++++++++------------ src/compositor/handlers.rs | 3 ++- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 29a1f97..7463fc0 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -7,26 +7,26 @@ extern crate slog; extern crate slog_async; extern crate slog_term; -use slog::*; use glium::Surface; +use slog::*; use smithay::backend::graphics::glium::IntoGlium; use smithay::backend::input::InputBackend; use smithay::backend::winit; +use smithay::compositor::{self, CompositorHandler}; use smithay::shm::ShmGlobal; -use smithay::compositor::{CompositorHandler, self}; use wayland_server::protocol::{wl_compositor, wl_shm, wl_subcompositor}; struct SurfaceHandler; -impl compositor::Handler for SurfaceHandler { -} +impl compositor::Handler for SurfaceHandler {} fn main() { // A logger facility, here we use the terminal for this example - let log = Logger::root(slog_async::Async::default(slog_term::term_full().fuse()).fuse(), o!()); + let log = Logger::root(slog_async::Async::default(slog_term::term_full().fuse()).fuse(), + o!()); // Initialize a simple backend for testing let (renderer, mut input) = winit::init(log.clone()).unwrap(); @@ -38,8 +38,7 @@ fn main() { */ // Insert the ShmGlobal as a handler to your event loop // Here, we specify tha the standard Argb8888 and Xrgb8888 is the only supported. - let shm_handler_id = - event_loop.add_handler_with_init(ShmGlobal::new(vec![], log.clone())); + let shm_handler_id = event_loop.add_handler_with_init(ShmGlobal::new(vec![], log.clone())); // Register this handler to advertise a wl_shm global of version 1 event_loop.register_global::(shm_handler_id, 1); @@ -47,7 +46,7 @@ fn main() { * Initialize the compositor global */ let compositor_handler_id = - event_loop.add_handler_with_init(CompositorHandler::<(),_>::new(SurfaceHandler, log.clone())); + event_loop.add_handler_with_init(CompositorHandler::<(), _>::new(SurfaceHandler, log.clone())); // register it to handle wl_compositor and wl_subcompositor event_loop.register_global::>(compositor_handler_id, 4); event_loop.register_global::>(compositor_handler_id, 1); @@ -57,10 +56,10 @@ fn main() { */ let (shm_token, compositor_token) = { let state = event_loop.state(); - ( - state.get_handler::(shm_handler_id).get_token(), - state.get_handler::>(compositor_handler_id).get_token() - ) + (state.get_handler::(shm_handler_id).get_token(), + state + .get_handler::>(compositor_handler_id) + .get_token()) }; /* diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index 49660ef..13b218d 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -112,7 +112,8 @@ impl wl_surface::Handler for CompositorHandler { } fn damage_buffer(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32, y: i32, width: i32, height: i32) { - trace!(self.log, "Registering damage to surface (buffer coordinates)."); + trace!(self.log, + "Registering damage to surface (buffer coordinates)."); unsafe { SurfaceData::::with_data(surface, |d| { d.damage = Damage::Buffer(Rectangle { From afd9ca5656a5b4f1ffd6cad2ab6af89e8588b97d Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 13 Jun 2017 16:45:46 +0200 Subject: [PATCH 15/24] shm: rename ShmGlobalToken to ShmToken --- src/shm/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shm/mod.rs b/src/shm/mod.rs index bf9b873..9dba511 100644 --- a/src/shm/mod.rs +++ b/src/shm/mod.rs @@ -13,7 +13,7 @@ //! //! To use it, first add a `ShmGlobal` to your event loop, specifying the formats //! you want to support (ARGB8888 and XRGB8888 are always considered as supported, -//! as specified by the wayland protocol) and obtain its `ShmGlobalToken`. +//! as specified by the wayland protocol) and obtain its `ShmToken`. //! //! ``` //! extern crate wayland_server; @@ -110,8 +110,8 @@ impl ShmGlobal { /// and has been initialized. If it is not the case, this method will panic. /// /// This is needed to retrieve the contents of the shm pools and buffers. - pub fn get_token(&self) -> ShmGlobalToken { - ShmGlobalToken { hid: self.handler_id.expect("ShmGlobal was not initialized.") } + pub fn get_token(&self) -> ShmToken { + ShmToken { hid: self.handler_id.expect("ShmGlobal was not initialized.") } } } @@ -119,7 +119,8 @@ impl ShmGlobal { /// /// It is needed to access the contents of the buffers & pools managed by the /// associated `ShmGlobal`. -pub struct ShmGlobalToken { +#[derive(Clone)] +pub struct ShmToken { hid: usize, } @@ -136,7 +137,7 @@ pub enum BufferAccessError { BadMap, } -impl ShmGlobalToken { +impl ShmToken { /// Call given closure with the contents of the given buffer /// /// If the buffer is managed by the associated ShmGlobal, its contents are From d819e15e29412db193c388665d75ded91c9f73e3 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 13 Jun 2017 16:46:31 +0200 Subject: [PATCH 16/24] compositor: Handler is now parametred by user data --- src/compositor/global.rs | 2 +- src/compositor/handlers.rs | 22 +++++++++++++--------- src/compositor/mod.rs | 23 +++++++++++++++++------ 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/compositor/global.rs b/src/compositor/global.rs index 43df315..42045ce 100644 --- a/src/compositor/global.rs +++ b/src/compositor/global.rs @@ -3,7 +3,7 @@ use super::{CompositorHandler, Handler as UserHandler}; use wayland_server::{Client, EventLoopHandle, GlobalHandler}; use wayland_server::protocol::{wl_compositor, wl_subcompositor}; -impl GlobalHandler for CompositorHandler +impl> GlobalHandler for CompositorHandler where U: Send + 'static, H: Send + 'static { diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index 13b218d..b9dc4bc 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -2,7 +2,7 @@ use super::{CompositorHandler, Damage, Handler as UserHandler, Rectangle, Rectan SubsurfaceAttributes}; use super::region::RegionData; use super::tree::{Location, SurfaceData}; -use wayland_server::{Client, Destroy, EventLoopHandle, Resource}; +use wayland_server::{Client, Destroy, EventLoopHandle, Resource, Liveness}; use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor, wl_subsurface, wl_surface}; @@ -16,7 +16,7 @@ struct CompositorDestructor { impl wl_compositor::Handler for CompositorHandler where U: Default + Send + 'static, - H: UserHandler + Send + 'static + H: UserHandler + Send + 'static { fn create_surface(&mut self, evqh: &mut EventLoopHandle, _: &Client, _: &wl_compositor::WlCompositor, id: wl_surface::WlSurface) { @@ -34,7 +34,7 @@ impl wl_compositor::Handler for CompositorHandler unsafe impl ::wayland_server::Handler for CompositorHandler where U: Default + Send + 'static, - H: UserHandler + Send + 'static + H: UserHandler + Send + 'static { unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_compositor::WlCompositor, opcode: u32, @@ -48,7 +48,7 @@ unsafe impl ::wayland_server::Handler for Com * wl_surface */ -impl wl_surface::Handler for CompositorHandler { +impl> wl_surface::Handler for CompositorHandler { fn attach(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, buffer: Option<&wl_buffer::WlBuffer>, x: i32, y: i32) { trace!(self.log, "Attaching buffer to surface."); @@ -74,7 +74,8 @@ impl wl_surface::Handler for CompositorHandler { fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, callback: wl_callback::WlCallback) { trace!(self.log, "Frame surface callback."); - UserHandler::frame(&mut self.handler, evlh, client, surface, callback); + let token = self.get_token(); + UserHandler::frame(&mut self.handler, evlh, client, surface, callback, token); } fn set_opaque_region(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, region: Option<&wl_region::WlRegion>) { @@ -94,7 +95,8 @@ impl wl_surface::Handler for CompositorHandler { } fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface) { trace!(self.log, "Commit surface callback."); - UserHandler::commit(&mut self.handler, evlh, client, surface); + let token = self.get_token(); + UserHandler::commit(&mut self.handler, evlh, client, surface, token); } fn set_buffer_transform(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, transform: wl_output::Transform) { @@ -127,7 +129,7 @@ impl wl_surface::Handler for CompositorHandler { } } -unsafe impl ::wayland_server::Handler for CompositorHandler { +unsafe impl> ::wayland_server::Handler for CompositorHandler { unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_surface::WlSurface, opcode: u32, args: *const ::wayland_server::sys::wl_argument) @@ -303,8 +305,10 @@ impl Destroy for CompositorDestructor { subsurface.set_user_data(::std::ptr::null_mut()); unsafe { let surface = Box::from_raw(ptr as *mut wl_surface::WlSurface); - SurfaceData::::with_data(&*surface, |d| d.subsurface_attributes = None); - SurfaceData::::unset_parent(&surface); + if surface.status() == Liveness::Alive { + SurfaceData::::with_data(&*surface, |d| d.subsurface_attributes = None); + SurfaceData::::unset_parent(&surface); + } } } } diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 927401c..5d6539f 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -47,7 +47,7 @@ //! } //! //! // Implement the handler trait for this sub-handler -//! impl compositor::Handler for MyHandler { +//! impl compositor::Handler for MyHandler { //! // See the trait documentation for its implementation //! // A default implementation for each method is provided, that does nothing //! } @@ -259,14 +259,25 @@ impl Default for RegionAttributes { /// This token can be cloned at will, and is the entry-point to /// access data associated with the wl_surface and wl_region managed /// by the `CompositorGlobal` that provided it. -#[derive(Copy,Clone)] pub struct CompositorToken { hid: usize, _data: ::std::marker::PhantomData<*mut U>, _handler: ::std::marker::PhantomData<*mut H>, } -impl CompositorToken { +unsafe impl Send for CompositorToken {} +unsafe impl Sync for CompositorToken {} + +// we implement them manually because #[derive(..)] would require +// U: Clone and H: Clone ... +impl Copy for CompositorToken {} +impl Clone for CompositorToken { + fn clone(&self) -> CompositorToken { + *self + } +} + +impl + Send + 'static> CompositorToken { /// Access the data of a surface /// /// The closure will be called with the contents of the data associated with this surface. @@ -434,7 +445,7 @@ impl CompositorHandler { /// are forwarded directly to a handler implementing this trait that you must provide /// at creation of the `CompositorHandler`. #[allow(unused_variables)] -pub trait Handler { +pub trait Handler : Sized{ /// The double-buffered state has been validated by the client /// /// At this point, the pending state that has been accumulated in the `SurfaceAttributes` associated @@ -442,7 +453,7 @@ pub trait Handler { /// /// See [`wayland_server::protocol::wl_surface::Handler::commit`](https://docs.rs/wayland-server/*/wayland_server/protocol/wl_surface/trait.Handler.html#method.commit) /// for more details - fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface) {} + fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, token: CompositorToken) {} /// The client asks to be notified when would be a good time to update the contents of this surface /// /// You must keep the provided `WlCallback` and trigger it at the appropriate time by calling @@ -451,6 +462,6 @@ pub trait Handler { /// See [`wayland_server::protocol::wl_surface::Handler::frame`](https://docs.rs/wayland-server/*/wayland_server/protocol/wl_surface/trait.Handler.html#method.frame) /// for more details fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, - callback: wl_callback::WlCallback) { + callback: wl_callback::WlCallback, token: CompositorToken) { } } From bffc02c5f10f596df2acf42cde706653eef1450f Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 13 Jun 2017 16:52:17 +0200 Subject: [PATCH 17/24] glium: impl Facade --- src/backend/graphics/glium.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/backend/graphics/glium.rs b/src/backend/graphics/glium.rs index a3629de..dacfb51 100644 --- a/src/backend/graphics/glium.rs +++ b/src/backend/graphics/glium.rs @@ -3,7 +3,7 @@ use backend::graphics::egl::{EGLGraphicsBackend, SwapBuffersError}; use glium::Frame; use glium::SwapBuffersError as GliumSwapBuffersError; -use glium::backend::{Backend, Context}; +use glium::backend::{Backend, Context, Facade}; use glium::debug::DebugCallbackBehavior; use std::ops::Deref; use std::os::raw::c_void; @@ -63,6 +63,12 @@ impl Deref for GliumGraphicsBackend { } } +impl Facade for GliumGraphicsBackend { + fn get_context(&self) -> &Rc { + &self.context + } +} + /// Converter trait to expose `glium` compatibility for all `EGLGraphicsBackend`s pub trait IntoGlium: EGLGraphicsBackend + Sized { /// Wrap the given `EGLGraphicsBackend` to a `GliumGraphicBackend` From 19634f30ede9b9de029b182fb17f6b24c751d323 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 13 Jun 2017 16:52:43 +0200 Subject: [PATCH 18/24] example: actually draw some windows! --- examples/helpers/glium.rs | 116 +++++++++++++++++++++++++++++++++++ examples/helpers/mod.rs | 5 ++ examples/helpers/shell.rs | 97 +++++++++++++++++++++++++++++ examples/simple.rs | 126 ++++++++++++++++++++++++++++++++------ 4 files changed, 326 insertions(+), 18 deletions(-) create mode 100644 examples/helpers/glium.rs create mode 100644 examples/helpers/mod.rs create mode 100644 examples/helpers/shell.rs diff --git a/examples/helpers/glium.rs b/examples/helpers/glium.rs new file mode 100644 index 0000000..4af2b4c --- /dev/null +++ b/examples/helpers/glium.rs @@ -0,0 +1,116 @@ +use glium; +use glium::Surface; +use glium::index::PrimitiveType; + +#[derive(Copy, Clone)] +struct Vertex { + position: [f32; 2], + tex_coords: [f32; 2], +} + +implement_vertex!(Vertex, position, tex_coords); + +pub struct GliumDrawer<'a, F: 'a> { + display: &'a F, + vertex_buffer: glium::VertexBuffer, + index_buffer: glium::IndexBuffer, + program: glium::Program, +} + +impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { + pub fn new(display: &'a F) -> GliumDrawer<'a, F> + { + + // building the vertex buffer, which contains all the vertices that we will draw + let vertex_buffer = glium::VertexBuffer::new(display, + &[Vertex { + position: [0.0, 0.0], + tex_coords: [0.0, 0.0], + }, + Vertex { + position: [0.0, 1.0], + tex_coords: [0.0, 1.0], + }, + Vertex { + position: [1.0, 1.0], + tex_coords: [1.0, 1.0], + }, + Vertex { + position: [1.0, 0.0], + tex_coords: [1.0, 0.0], + }]) + .unwrap(); + + // building the index buffer + let index_buffer = + glium::IndexBuffer::new(display, PrimitiveType::TriangleStrip, &[1 as u16, 2, 0, 3]).unwrap(); + + // compiling shaders and linking them together + let program = program!(display, + 100 => { + vertex: " + #version 100 + uniform lowp mat4 matrix; + attribute lowp vec2 position; + attribute lowp vec2 tex_coords; + varying lowp vec2 v_tex_coords; + void main() { + gl_Position = matrix * vec4(position, 0.0, 1.0); + v_tex_coords = tex_coords; + } + ", + + fragment: " + #version 100 + uniform lowp sampler2D tex; + varying lowp vec2 v_tex_coords; + void main() { + lowp vec4 color = texture2D(tex, v_tex_coords); + gl_FragColor.r = color.z; + gl_FragColor.g = color.y; + gl_FragColor.b = color.x; + gl_FragColor.a = color.w; + } + ", + }, + ) + .unwrap(); + + GliumDrawer { + display, + vertex_buffer, + index_buffer, + program, + } + } + + pub fn draw(&self, target: &mut glium::Frame, contents: &[u8], surface_dimensions: (u32, u32), surface_location: (i32,i32), screen_size: (u32,u32)) { + + let image = glium::texture::RawImage2d { + data: contents.into(), + width: surface_dimensions.0, + height: surface_dimensions.1, + format: glium::texture::ClientFormat::U8U8U8U8 + }; + let opengl_texture = glium::texture::CompressedSrgbTexture2d::new(self.display, image).unwrap(); + + let xscale = 2.0*(surface_dimensions.0 as f32) / (screen_size.0 as f32); + let yscale = -2.0*(surface_dimensions.1 as f32) / (screen_size.1 as f32); + + let x = 2.0*(surface_location.0 as f32) / (screen_size.0 as f32) - 1.0; + let y = 1.0 - 2.0*(surface_location.1 as f32) / (screen_size.1 as f32); + + let uniforms = uniform! { + matrix: [ + [xscale, 0.0 , 0.0, 0.0], + [ 0.0 , yscale , 0.0, 0.0], + [ 0.0 , 0.0 , 1.0, 0.0], + [ x , y , 0.0, 1.0] + ], + tex: &opengl_texture + }; + + target.draw(&self.vertex_buffer, &self.index_buffer, &self.program, &uniforms, &Default::default()).unwrap(); + + } +} diff --git a/examples/helpers/mod.rs b/examples/helpers/mod.rs new file mode 100644 index 0000000..e913100 --- /dev/null +++ b/examples/helpers/mod.rs @@ -0,0 +1,5 @@ +mod shell; +mod glium; + +pub use self::glium::GliumDrawer; +pub use self::shell::WlShellStubHandler; diff --git a/examples/helpers/shell.rs b/examples/helpers/shell.rs new file mode 100644 index 0000000..de73b2c --- /dev/null +++ b/examples/helpers/shell.rs @@ -0,0 +1,97 @@ + + +use smithay::compositor::{CompositorToken, Handler as CompositorHandler}; +use wayland_server::{Client, EventLoopHandle, GlobalHandler, Init, Resource}; +use wayland_server::protocol::{wl_shell, wl_shell_surface, wl_surface}; + +/// A very basic handler for wl_shell +/// +/// All it does is track which wl_shell_surface exist and which do not, +/// as well as the roles associated to them. +/// +/// That's it. +pub struct WlShellStubHandler { + my_id: Option, + token: CompositorToken, + surfaces: Vec<(wl_shell_surface::WlShellSurface, wl_surface::WlSurface)>, +} + +impl WlShellStubHandler { + pub fn new(compositor_token: CompositorToken) -> WlShellStubHandler { + WlShellStubHandler { + my_id: None, + token: compositor_token, + surfaces: Vec::new(), + } + } + + pub fn surfaces(&self) -> &[(wl_shell_surface::WlShellSurface, wl_surface::WlSurface)] { + &self.surfaces + } +} + +impl Init for WlShellStubHandler { + fn init(&mut self, evqh: &mut EventLoopHandle, index: usize) { + self.my_id = Some(index) + } +} + + +impl GlobalHandler for WlShellStubHandler + where U: Send + 'static, + H: CompositorHandler + Send + 'static +{ + fn bind(&mut self, evqh: &mut EventLoopHandle, client: &Client, global: wl_shell::WlShell) { + evqh.register::<_, Self>(&global, + self.my_id + .expect("WlShellStubHandler was not properly initialized.")); + } +} + +impl wl_shell::Handler for WlShellStubHandler + where U: Send + 'static, + H: CompositorHandler + Send + 'static +{ + fn get_shell_surface(&mut self, evqh: &mut EventLoopHandle, client: &Client, + resource: &wl_shell::WlShell, id: wl_shell_surface::WlShellSurface, + surface: &wl_surface::WlSurface) { + let surface = surface.clone().expect("WlShellStubHandler can only manage surfaces managed by Smithay's CompositorHandler."); + if self.token.give_role(&surface).is_err() { + // This surface already has a role, and thus cannot be given one! + resource.post_error(wl_shell::Error::Role as u32, + "Surface already has a role.".into()); + return; + } + evqh.register::<_, Self>(&id, self.my_id.unwrap()); + self.surfaces.push((id, surface)) + } +} + +unsafe impl ::wayland_server::Handler for WlShellStubHandler + where U: Send + 'static, + H: CompositorHandler + Send + 'static +{ + unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_shell::WlShell, + opcode: u32, args: *const ::wayland_server::sys::wl_argument) + -> Result<(), ()> { + as ::wayland_server::protocol::wl_shell::Handler>::__message(self, evq, client, resource, opcode, args) + } +} + +impl wl_shell_surface::Handler for WlShellStubHandler + where U: Send + 'static, + H: CompositorHandler + Send + 'static +{ +} + +unsafe impl ::wayland_server::Handler for WlShellStubHandler + where U: Send + 'static, + H: CompositorHandler + Send + 'static +{ + unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, + resource: &wl_shell_surface::WlShellSurface, opcode: u32, + args: *const ::wayland_server::sys::wl_argument) + -> Result<(), ()> { + as ::wayland_server::protocol::wl_shell_surface::Handler>::__message(self, evq, client, resource, opcode, args) + } +} diff --git a/examples/simple.rs b/examples/simple.rs index 7463fc0..1cdbb86 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,5 +1,6 @@ extern crate wayland_server; extern crate smithay; +#[macro_use] extern crate glium; #[macro_use] @@ -7,21 +8,59 @@ extern crate slog; extern crate slog_async; extern crate slog_term; +mod helpers; use glium::Surface; + +use helpers::{WlShellStubHandler, GliumDrawer}; use slog::*; use smithay::backend::graphics::glium::IntoGlium; use smithay::backend::input::InputBackend; use smithay::backend::winit; -use smithay::compositor::{self, CompositorHandler}; -use smithay::shm::ShmGlobal; +use smithay::compositor::{self, CompositorHandler, CompositorToken}; +use smithay::shm::{ShmGlobal, ShmToken, BufferData}; -use wayland_server::protocol::{wl_compositor, wl_shm, wl_subcompositor}; +use wayland_server::protocol::{wl_compositor, wl_shell, wl_shm, wl_subcompositor, wl_surface}; +use wayland_server::{EventLoopHandle,Client,Liveness, Resource}; -struct SurfaceHandler; +struct SurfaceHandler { + shm_token: ShmToken +} -impl compositor::Handler for SurfaceHandler {} +#[derive(Default)] +struct SurfaceData { + buffer: Option<(Vec, (u32, u32))> +} + +impl compositor::Handler for SurfaceHandler { + fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, token: CompositorToken) { + // we retrieve the contents of the associated buffer and copy it + token.with_surface_data(surface, |attributes| { + match attributes.buffer.take() { + Some(Some((buffer, (x,y)))) => { + self.shm_token.with_buffer_contents(&buffer, |slice, data| { + let offset = data.offset as usize; + let stride = data.stride as usize; + let width = data.width as usize; + let height = data.height as usize; + let mut new_vec = Vec::with_capacity(width*height*4); + for i in 0..height { + new_vec.extend(&slice[(offset+i*stride)..(offset+i*stride+width*4)]); + } + attributes.user_data.buffer = Some((new_vec, (data.width as u32, data.height as u32))); + }); + + } + Some(None) => { + // erase the contents + attributes.user_data.buffer = None; + } + None => {} + } + }); + } +} fn main() { // A logger facility, here we use the terminal for this example @@ -31,7 +70,7 @@ fn main() { // Initialize a simple backend for testing let (renderer, mut input) = winit::init(log.clone()).unwrap(); - let (_display, mut event_loop) = wayland_server::create_display(); + let (mut display, mut event_loop) = wayland_server::create_display(); /* * Initialize wl_shm global @@ -41,40 +80,91 @@ fn main() { let shm_handler_id = event_loop.add_handler_with_init(ShmGlobal::new(vec![], log.clone())); // Register this handler to advertise a wl_shm global of version 1 event_loop.register_global::(shm_handler_id, 1); + // retreive the token + let shm_token = { + let state = event_loop.state(); + state + .get_handler::(shm_handler_id) + .get_token() + }; + /* * Initialize the compositor global */ let compositor_handler_id = - event_loop.add_handler_with_init(CompositorHandler::<(), _>::new(SurfaceHandler, log.clone())); + event_loop.add_handler_with_init(CompositorHandler::::new(SurfaceHandler { shm_token: shm_token.clone() }, log.clone())); // register it to handle wl_compositor and wl_subcompositor - event_loop.register_global::>(compositor_handler_id, 4); - event_loop.register_global::>(compositor_handler_id, 1); + event_loop.register_global::>(compositor_handler_id, 4); + event_loop.register_global::>(compositor_handler_id, 1); + // retrieve the tokens + let compositor_token = { + let state = event_loop.state(); + state + .get_handler::>(compositor_handler_id) + .get_token() + }; /* - * retrieve the tokens + * Initialize the shell stub global */ - let (shm_token, compositor_token) = { - let state = event_loop.state(); - (state.get_handler::(shm_handler_id).get_token(), - state - .get_handler::>(compositor_handler_id) - .get_token()) - }; + let shell_handler_id = + event_loop.add_handler_with_init(WlShellStubHandler::new(compositor_token.clone())); + event_loop.register_global::>(shell_handler_id, + 1); /* * Initialize glium */ let context = renderer.into_glium(); + let drawer = GliumDrawer::new(&context); + + /* + * Add a listening socket: + */ + let name = display + .add_socket_auto() + .unwrap() + .into_string() + .unwrap(); + println!("Listening on socket: {}", name); loop { input.dispatch_new_events().unwrap(); let mut frame = context.draw(); - frame.clear(None, Some((0.0, 0.0, 0.0, 1.0)), false, None, None); + frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, None, None); + // redraw the frame, in a simple but inneficient way + { + let screen_dimensions = context.get_framebuffer_dimensions(); + let state = event_loop.state(); + for &(_, ref surface) in + state + .get_handler::>(shell_handler_id) + .surfaces() { + if surface.status() != Liveness::Alive { + continue; + } + // this surface is a root of a subsurface tree that needs to be drawn + compositor_token.with_surface_tree(surface, |surface, attributes| { + if let Some((ref contents, (w, h))) = attributes.user_data.buffer { + // there is actually something to draw ! + let mut x = 100; + let mut y = 100; + if let Some(ref subdata) = attributes.subsurface_attributes { + x += subdata.x; + y += subdata.y; + } + drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); + } + true + }); + } + } frame.finish().unwrap(); event_loop.dispatch(Some(16)).unwrap(); + display.flush_clients(); } } From a487c5963a7b75f5aa29897aa2691052172b4fcb Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 13 Jun 2017 17:38:25 +0200 Subject: [PATCH 19/24] compositor: TraversalAction for tree traversal --- examples/simple.rs | 11 ++++++---- src/compositor/mod.rs | 8 +++---- src/compositor/tree.rs | 49 +++++++++++++++++++++++++++++------------- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 1cdbb86..412e2e3 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -147,18 +147,21 @@ fn main() { continue; } // this surface is a root of a subsurface tree that needs to be drawn - compositor_token.with_surface_tree(surface, |surface, attributes| { + compositor_token.with_surface_tree(surface, (100, 100), |surface, + attributes, + &(mut x, mut y)| { if let Some((ref contents, (w, h))) = attributes.user_data.buffer { // there is actually something to draw ! - let mut x = 100; - let mut y = 100; if let Some(ref subdata) = attributes.subsurface_attributes { x += subdata.x; y += subdata.y; } drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); + TraversalAction::DoChildren((x, y)) + } else { + // we are not display, so our children are neither + TraversalAction::SkipChildren } - true }); } } diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 5d6539f..94dc023 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -97,7 +97,7 @@ mod tree; mod region; use self::region::RegionData; -pub use self::tree::RoleStatus; +pub use self::tree::{RoleStatus, TraversalAction}; use self::tree::SurfaceData; use wayland_server::{Client, EventLoopHandle, Init, resource_is_registered}; @@ -302,13 +302,13 @@ impl + Send + 'static> CompositorToken { /// /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). - pub fn with_surface_tree(&self, surface: &wl_surface::WlSurface, f: F) -> Result<(), ()> - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + pub fn with_surface_tree(&self, surface: &wl_surface::WlSurface, initial: T, f: F) -> Result<(), ()> + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction { assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported."); unsafe { - SurfaceData::::map_tree(surface, f); + SurfaceData::::map_tree(surface, initial, f); } Ok(()) } diff --git a/src/compositor/tree.rs b/src/compositor/tree.rs index 8a77bd3..71d7786 100644 --- a/src/compositor/tree.rs +++ b/src/compositor/tree.rs @@ -48,6 +48,16 @@ pub enum Location { After, } +/// Possible actions to do after handling a node diring tree traversal +pub enum TraversalAction { + /// Traverse its children as well, providing them the data T + DoChildren(T), + /// Skip its children + SkipChildren, + /// Stop traversal completely + Break, +} + impl SurfaceData { fn new() -> SurfaceData { SurfaceData { @@ -275,12 +285,14 @@ impl SurfaceData { /// /// The callback returns wether the traversal should continue or not. Returning /// false will cause an early-stopping. - pub unsafe fn map_tree(root: &wl_surface::WlSurface, mut f: F) - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + pub unsafe fn map_tree(root: &wl_surface::WlSurface, initial: T, mut f: F) + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction { // helper function for recursion - unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, f: &mut F) -> bool - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, initial: &T, + f: &mut F) + -> bool + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction { // stop if we met the root, so to not deadlock/inifinte loop if surface.equals(root) { @@ -290,27 +302,34 @@ impl SurfaceData { let data_mutex = SurfaceData::::get_data(surface); let mut data_guard = data_mutex.lock().unwrap(); // call the callback on ourselves - if f(surface, &mut data_guard.attributes) { - // loop over children - for c in &data_guard.children { - if !map(c, root, f) { - return false; + match f(surface, &mut data_guard.attributes, initial) { + TraversalAction::DoChildren(t) => { + // loop over children + for c in &data_guard.children { + if !map(c, root, &t, f) { + return false; + } } + true } + TraversalAction::SkipChildren => true, + TraversalAction::Break => false, } - true } let data_mutex = Self::get_data(root); let mut data_guard = data_mutex.lock().unwrap(); // call the callback on ourselves - if f(root, &mut data_guard.attributes) { - // loop over children - for c in &data_guard.children { - if !map::(c, root, &mut f) { - break; + match f(root, &mut data_guard.attributes, &initial) { + TraversalAction::DoChildren(t) => { + // loop over children + for c in &data_guard.children { + if !map::(c, root, &t, &mut f) { + break; + } } } + _ => {} } } } From d475435fcbe91f5c95dd54c103d4225758ec1694 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 13 Jun 2017 17:39:25 +0200 Subject: [PATCH 20/24] cargo fmt --- examples/helpers/glium.rs | 33 ++++++++++++++----------- examples/simple.rs | 50 +++++++++++++++++++------------------- src/compositor/handlers.rs | 15 +++++++----- src/compositor/mod.rs | 10 +++++--- 4 files changed, 59 insertions(+), 49 deletions(-) diff --git a/examples/helpers/glium.rs b/examples/helpers/glium.rs index 4af2b4c..718b009 100644 --- a/examples/helpers/glium.rs +++ b/examples/helpers/glium.rs @@ -18,8 +18,7 @@ pub struct GliumDrawer<'a, F: 'a> { } impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { - pub fn new(display: &'a F) -> GliumDrawer<'a, F> - { + pub fn new(display: &'a F) -> GliumDrawer<'a, F> { // building the vertex buffer, which contains all the vertices that we will draw let vertex_buffer = glium::VertexBuffer::new(display, @@ -38,8 +37,7 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { Vertex { position: [1.0, 0.0], tex_coords: [1.0, 0.0], - }]) - .unwrap(); + }]).unwrap(); // building the index buffer let index_buffer = @@ -73,8 +71,7 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { } ", }, - ) - .unwrap(); + ).unwrap(); GliumDrawer { display, @@ -84,23 +81,25 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { } } - pub fn draw(&self, target: &mut glium::Frame, contents: &[u8], surface_dimensions: (u32, u32), surface_location: (i32,i32), screen_size: (u32,u32)) { + pub fn draw(&self, target: &mut glium::Frame, contents: &[u8], surface_dimensions: (u32, u32), + surface_location: (i32, i32), screen_size: (u32, u32)) { let image = glium::texture::RawImage2d { data: contents.into(), width: surface_dimensions.0, height: surface_dimensions.1, - format: glium::texture::ClientFormat::U8U8U8U8 + format: glium::texture::ClientFormat::U8U8U8U8, }; let opengl_texture = glium::texture::CompressedSrgbTexture2d::new(self.display, image).unwrap(); - let xscale = 2.0*(surface_dimensions.0 as f32) / (screen_size.0 as f32); - let yscale = -2.0*(surface_dimensions.1 as f32) / (screen_size.1 as f32); + let xscale = 2.0 * (surface_dimensions.0 as f32) / (screen_size.0 as f32); + let yscale = -2.0 * (surface_dimensions.1 as f32) / (screen_size.1 as f32); - let x = 2.0*(surface_location.0 as f32) / (screen_size.0 as f32) - 1.0; - let y = 1.0 - 2.0*(surface_location.1 as f32) / (screen_size.1 as f32); + let x = 2.0 * (surface_location.0 as f32) / (screen_size.0 as f32) - 1.0; + let y = 1.0 - 2.0 * (surface_location.1 as f32) / (screen_size.1 as f32); - let uniforms = uniform! { + let uniforms = + uniform! { matrix: [ [xscale, 0.0 , 0.0, 0.0], [ 0.0 , yscale , 0.0, 0.0], @@ -110,7 +109,13 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { tex: &opengl_texture }; - target.draw(&self.vertex_buffer, &self.index_buffer, &self.program, &uniforms, &Default::default()).unwrap(); + target + .draw(&self.vertex_buffer, + &self.index_buffer, + &self.program, + &uniforms, + &Default::default()) + .unwrap(); } } diff --git a/examples/simple.rs b/examples/simple.rs index 412e2e3..5c76fc0 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -12,43 +12,45 @@ mod helpers; use glium::Surface; -use helpers::{WlShellStubHandler, GliumDrawer}; +use helpers::{GliumDrawer, WlShellStubHandler}; use slog::*; use smithay::backend::graphics::glium::IntoGlium; use smithay::backend::input::InputBackend; use smithay::backend::winit; -use smithay::compositor::{self, CompositorHandler, CompositorToken}; -use smithay::shm::{ShmGlobal, ShmToken, BufferData}; +use smithay::compositor::{self, CompositorHandler, CompositorToken, TraversalAction}; +use smithay::shm::{BufferData, ShmGlobal, ShmToken}; +use wayland_server::{Client, EventLoopHandle, Liveness, Resource}; use wayland_server::protocol::{wl_compositor, wl_shell, wl_shm, wl_subcompositor, wl_surface}; -use wayland_server::{EventLoopHandle,Client,Liveness, Resource}; struct SurfaceHandler { - shm_token: ShmToken + shm_token: ShmToken, } #[derive(Default)] struct SurfaceData { - buffer: Option<(Vec, (u32, u32))> + buffer: Option<(Vec, (u32, u32))>, } impl compositor::Handler for SurfaceHandler { - fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, token: CompositorToken) { + fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, + token: CompositorToken) { // we retrieve the contents of the associated buffer and copy it token.with_surface_data(surface, |attributes| { match attributes.buffer.take() { - Some(Some((buffer, (x,y)))) => { + Some(Some((buffer, (x, y)))) => { self.shm_token.with_buffer_contents(&buffer, |slice, data| { let offset = data.offset as usize; let stride = data.stride as usize; let width = data.width as usize; let height = data.height as usize; - let mut new_vec = Vec::with_capacity(width*height*4); + let mut new_vec = Vec::with_capacity(width * height * 4); for i in 0..height { - new_vec.extend(&slice[(offset+i*stride)..(offset+i*stride+width*4)]); + new_vec.extend(&slice[(offset + i * stride)..(offset + i * stride + width * 4)]); } - attributes.user_data.buffer = Some((new_vec, (data.width as u32, data.height as u32))); + attributes.user_data.buffer = Some((new_vec, + (data.width as u32, data.height as u32))); }); } @@ -83,9 +85,7 @@ fn main() { // retreive the token let shm_token = { let state = event_loop.state(); - state - .get_handler::(shm_handler_id) - .get_token() + state.get_handler::(shm_handler_id).get_token() }; @@ -93,23 +93,27 @@ fn main() { * Initialize the compositor global */ let compositor_handler_id = - event_loop.add_handler_with_init(CompositorHandler::::new(SurfaceHandler { shm_token: shm_token.clone() }, log.clone())); + event_loop.add_handler_with_init(CompositorHandler::::new(SurfaceHandler { + shm_token: shm_token + .clone(), + }, + log.clone())); // register it to handle wl_compositor and wl_subcompositor event_loop.register_global::>(compositor_handler_id, 4); event_loop.register_global::>(compositor_handler_id, 1); // retrieve the tokens let compositor_token = { let state = event_loop.state(); - state - .get_handler::>(compositor_handler_id) - .get_token() + state + .get_handler::>(compositor_handler_id) + .get_token() }; /* * Initialize the shell stub global */ - let shell_handler_id = - event_loop.add_handler_with_init(WlShellStubHandler::new(compositor_token.clone())); + let shell_handler_id = event_loop + .add_handler_with_init(WlShellStubHandler::new(compositor_token.clone())); event_loop.register_global::>(shell_handler_id, 1); @@ -123,11 +127,7 @@ fn main() { /* * Add a listening socket: */ - let name = display - .add_socket_auto() - .unwrap() - .into_string() - .unwrap(); + let name = display.add_socket_auto().unwrap().into_string().unwrap(); println!("Listening on socket: {}", name); loop { diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index b9dc4bc..03ff52b 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -2,7 +2,7 @@ use super::{CompositorHandler, Damage, Handler as UserHandler, Rectangle, Rectan SubsurfaceAttributes}; use super::region::RegionData; use super::tree::{Location, SurfaceData}; -use wayland_server::{Client, Destroy, EventLoopHandle, Resource, Liveness}; +use wayland_server::{Client, Destroy, EventLoopHandle, Liveness, Resource}; use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor, wl_subsurface, wl_surface}; @@ -53,8 +53,9 @@ impl> wl_surface::Handler for CompositorHandler { buffer: Option<&wl_buffer::WlBuffer>, x: i32, y: i32) { trace!(self.log, "Attaching buffer to surface."); unsafe { - SurfaceData::::with_data(surface, - |d| d.buffer = Some(buffer.map(|b| (b.clone_unchecked(), (x, y))))); + SurfaceData::::with_data(surface, |d| { + d.buffer = Some(buffer.map(|b| (b.clone_unchecked(), (x, y)))) + }); } } fn damage(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32, @@ -129,7 +130,8 @@ impl> wl_surface::Handler for CompositorHandler { } } -unsafe impl> ::wayland_server::Handler for CompositorHandler { +unsafe impl> ::wayland_server::Handler + for CompositorHandler { unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_surface::WlSurface, opcode: u32, args: *const ::wayland_server::sys::wl_argument) @@ -212,8 +214,9 @@ impl wl_subcompositor::Handler for CompositorHandler } id.set_user_data(Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _); unsafe { - SurfaceData::::with_data(surface, - |d| d.subsurface_attributes = Some(Default::default())); + SurfaceData::::with_data(surface, |d| { + d.subsurface_attributes = Some(Default::default()) + }); } evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>(&id, self.my_id); } diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 94dc023..0b552df 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -213,7 +213,7 @@ impl Default for SubsurfaceAttributes { } /// Kind of a rectangle part of a region -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub enum RectangleKind { /// This rectangle should be added to the region Add, @@ -223,7 +223,7 @@ pub enum RectangleKind { } /// A rectangle defined by its top-left corner and dimensions -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Rectangle { /// horizontal position of the top-leftcorner of the rectangle, in surface coordinates pub x: i32, @@ -445,7 +445,7 @@ impl CompositorHandler { /// are forwarded directly to a handler implementing this trait that you must provide /// at creation of the `CompositorHandler`. #[allow(unused_variables)] -pub trait Handler : Sized{ +pub trait Handler: Sized { /// The double-buffered state has been validated by the client /// /// At this point, the pending state that has been accumulated in the `SurfaceAttributes` associated @@ -453,7 +453,9 @@ pub trait Handler : Sized{ /// /// See [`wayland_server::protocol::wl_surface::Handler::commit`](https://docs.rs/wayland-server/*/wayland_server/protocol/wl_surface/trait.Handler.html#method.commit) /// for more details - fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, token: CompositorToken) {} + fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, + token: CompositorToken) { + } /// The client asks to be notified when would be a good time to update the contents of this surface /// /// You must keep the provided `WlCallback` and trigger it at the appropriate time by calling From c2c5716524b86c3d6868f569e4052586925df5e5 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Wed, 14 Jun 2017 14:02:07 +0200 Subject: [PATCH 21/24] example: use Texture2d to have correct gamma correction This mimicks what weston does. --- examples/helpers/glium.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/helpers/glium.rs b/examples/helpers/glium.rs index 718b009..421a85d 100644 --- a/examples/helpers/glium.rs +++ b/examples/helpers/glium.rs @@ -90,7 +90,7 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { height: surface_dimensions.1, format: glium::texture::ClientFormat::U8U8U8U8, }; - let opengl_texture = glium::texture::CompressedSrgbTexture2d::new(self.display, image).unwrap(); + let opengl_texture = glium::texture::Texture2d::new(self.display, image).unwrap(); let xscale = 2.0 * (surface_dimensions.0 as f32) / (screen_size.0 as f32); let yscale = -2.0 * (surface_dimensions.1 as f32) / (screen_size.1 as f32); From 9d2f03943e523e484e7d72acf3b2b5c0a5f96bc5 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 23 Jun 2017 15:18:12 +0200 Subject: [PATCH 22/24] replace unsafe impls from wayland-server with declare_handler macro --- examples/helpers/shell.rs | 23 ++--------------- examples/simple.rs | 1 + src/compositor/handlers.rs | 52 ++++---------------------------------- 3 files changed, 8 insertions(+), 68 deletions(-) diff --git a/examples/helpers/shell.rs b/examples/helpers/shell.rs index de73b2c..ddee1d1 100644 --- a/examples/helpers/shell.rs +++ b/examples/helpers/shell.rs @@ -67,16 +67,7 @@ impl wl_shell::Handler for WlShellStubHandler } } -unsafe impl ::wayland_server::Handler for WlShellStubHandler - where U: Send + 'static, - H: CompositorHandler + Send + 'static -{ - unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &wl_shell::WlShell, - opcode: u32, args: *const ::wayland_server::sys::wl_argument) - -> Result<(), ()> { - as ::wayland_server::protocol::wl_shell::Handler>::__message(self, evq, client, resource, opcode, args) - } -} +server_declare_handler!(WlShellStubHandler, Send]>, wl_shell::Handler, wl_shell::WlShell); impl wl_shell_surface::Handler for WlShellStubHandler where U: Send + 'static, @@ -84,14 +75,4 @@ impl wl_shell_surface::Handler for WlShellStubHandler { } -unsafe impl ::wayland_server::Handler for WlShellStubHandler - where U: Send + 'static, - H: CompositorHandler + Send + 'static -{ - unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, - resource: &wl_shell_surface::WlShellSurface, opcode: u32, - args: *const ::wayland_server::sys::wl_argument) - -> Result<(), ()> { - as ::wayland_server::protocol::wl_shell_surface::Handler>::__message(self, evq, client, resource, opcode, args) - } -} +server_declare_handler!(WlShellStubHandler, Send]>, wl_shell_surface::Handler, wl_shell_surface::WlShellSurface); diff --git a/examples/simple.rs b/examples/simple.rs index 5c76fc0..eca2509 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,3 +1,4 @@ +#[macro_use(server_declare_handler)] extern crate wayland_server; extern crate smithay; #[macro_use] diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index 03ff52b..4a6e598 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -32,17 +32,7 @@ impl wl_compositor::Handler for CompositorHandler } } -unsafe impl ::wayland_server::Handler for CompositorHandler - where U: Default + Send + 'static, - H: UserHandler + Send + 'static -{ - unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, - resource: &wl_compositor::WlCompositor, opcode: u32, - args: *const ::wayland_server::sys::wl_argument) - -> Result<(), ()> { - as ::wayland_server::protocol::wl_compositor::Handler>::__message(self, evq, client, resource, opcode, args) - } -} +server_declare_handler!(CompositorHandler, Send]>, wl_compositor::Handler, wl_compositor::WlCompositor); /* * wl_surface @@ -130,15 +120,7 @@ impl> wl_surface::Handler for CompositorHandler { } } -unsafe impl> ::wayland_server::Handler - for CompositorHandler { - unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, - resource: &wl_surface::WlSurface, opcode: u32, - args: *const ::wayland_server::sys::wl_argument) - -> Result<(), ()> { - as ::wayland_server::protocol::wl_surface::Handler>::__message(self, evq, client, resource, opcode, args) - } -} +server_declare_handler!(CompositorHandler]>, wl_surface::Handler, wl_surface::WlSurface); impl Destroy for CompositorDestructor { fn destroy(surface: &wl_surface::WlSurface) { @@ -181,14 +163,7 @@ impl wl_region::Handler for CompositorHandler { } } -unsafe impl ::wayland_server::Handler for CompositorHandler { - unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, - resource: &wl_region::WlRegion, opcode: u32, - args: *const ::wayland_server::sys::wl_argument) - -> Result<(), ()> { - as ::wayland_server::protocol::wl_region::Handler>::__message(self, evq, client, resource, opcode, args) - } -} +server_declare_handler!(CompositorHandler, wl_region::Handler, wl_region::WlRegion); impl Destroy for CompositorDestructor { fn destroy(region: &wl_region::WlRegion) { @@ -222,17 +197,7 @@ impl wl_subcompositor::Handler for CompositorHandler } } -unsafe impl ::wayland_server::Handler for CompositorHandler - where U: Send + 'static, - H: Send + 'static -{ - unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, - resource: &wl_subcompositor::WlSubcompositor, opcode: u32, - args: *const ::wayland_server::sys::wl_argument) - -> Result<(), ()> { - as ::wayland_server::protocol::wl_subcompositor::Handler>::__message(self, evq, client, resource, opcode, args) - } -} +server_declare_handler!(CompositorHandler, wl_subcompositor::Handler, wl_subcompositor::WlSubcompositor); /* * wl_subsurface @@ -293,14 +258,7 @@ impl wl_subsurface::Handler for CompositorHandler { } } -unsafe impl ::wayland_server::Handler for CompositorHandler { - unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, - resource: &wl_subsurface::WlSubsurface, opcode: u32, - args: *const ::wayland_server::sys::wl_argument) - -> Result<(), ()> { - as ::wayland_server::protocol::wl_subsurface::Handler>::__message(self, evq, client, resource, opcode, args) - } -} +server_declare_handler!(CompositorHandler, wl_subsurface::Handler, wl_subsurface::WlSubsurface); impl Destroy for CompositorDestructor { fn destroy(subsurface: &wl_subsurface::WlSubsurface) { From 4f6a85265247f5ca93da4cb56a07a3607440474e Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 23 Jun 2017 15:40:28 +0200 Subject: [PATCH 23/24] cargo fmt --- examples/helpers/glium.rs | 50 +++++++++++++----------- examples/helpers/shell.rs | 20 ++++++---- examples/simple.rs | 75 +++++++++++++++++++++--------------- src/compositor/global.rs | 5 ++- src/compositor/handlers.rs | 79 ++++++++++++++++++++++---------------- src/compositor/mod.rs | 63 ++++++++++++++++++++---------- src/compositor/region.rs | 4 +- src/compositor/tree.rs | 13 +++++-- 8 files changed, 186 insertions(+), 123 deletions(-) diff --git a/examples/helpers/glium.rs b/examples/helpers/glium.rs index 421a85d..23a8278 100644 --- a/examples/helpers/glium.rs +++ b/examples/helpers/glium.rs @@ -21,23 +21,27 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { pub fn new(display: &'a F) -> GliumDrawer<'a, F> { // building the vertex buffer, which contains all the vertices that we will draw - let vertex_buffer = glium::VertexBuffer::new(display, - &[Vertex { - position: [0.0, 0.0], - tex_coords: [0.0, 0.0], - }, - Vertex { - position: [0.0, 1.0], - tex_coords: [0.0, 1.0], - }, - Vertex { - position: [1.0, 1.0], - tex_coords: [1.0, 1.0], - }, - Vertex { - position: [1.0, 0.0], - tex_coords: [1.0, 0.0], - }]).unwrap(); + let vertex_buffer = glium::VertexBuffer::new( + display, + &[ + Vertex { + position: [0.0, 0.0], + tex_coords: [0.0, 0.0], + }, + Vertex { + position: [0.0, 1.0], + tex_coords: [0.0, 1.0], + }, + Vertex { + position: [1.0, 1.0], + tex_coords: [1.0, 1.0], + }, + Vertex { + position: [1.0, 0.0], + tex_coords: [1.0, 0.0], + }, + ], + ).unwrap(); // building the index buffer let index_buffer = @@ -110,11 +114,13 @@ impl<'a, F: glium::backend::Facade + 'a> GliumDrawer<'a, F> { }; target - .draw(&self.vertex_buffer, - &self.index_buffer, - &self.program, - &uniforms, - &Default::default()) + .draw( + &self.vertex_buffer, + &self.index_buffer, + &self.program, + &uniforms, + &Default::default(), + ) .unwrap(); } diff --git a/examples/helpers/shell.rs b/examples/helpers/shell.rs index ddee1d1..6e56466 100644 --- a/examples/helpers/shell.rs +++ b/examples/helpers/shell.rs @@ -49,17 +49,22 @@ impl GlobalHandler for WlShellStubHandler } impl wl_shell::Handler for WlShellStubHandler - where U: Send + 'static, - H: CompositorHandler + Send + 'static +where + U: Send + 'static, + H: CompositorHandler + Send + 'static, { fn get_shell_surface(&mut self, evqh: &mut EventLoopHandle, client: &Client, resource: &wl_shell::WlShell, id: wl_shell_surface::WlShellSurface, surface: &wl_surface::WlSurface) { - let surface = surface.clone().expect("WlShellStubHandler can only manage surfaces managed by Smithay's CompositorHandler."); + let surface = surface.clone().expect( + "WlShellStubHandler can only manage surfaces managed by Smithay's CompositorHandler.", + ); if self.token.give_role(&surface).is_err() { // This surface already has a role, and thus cannot be given one! - resource.post_error(wl_shell::Error::Role as u32, - "Surface already has a role.".into()); + resource.post_error( + wl_shell::Error::Role as u32, + "Surface already has a role.".into(), + ); return; } evqh.register::<_, Self>(&id, self.my_id.unwrap()); @@ -70,8 +75,9 @@ impl wl_shell::Handler for WlShellStubHandler server_declare_handler!(WlShellStubHandler, Send]>, wl_shell::Handler, wl_shell::WlShell); impl wl_shell_surface::Handler for WlShellStubHandler - where U: Send + 'static, - H: CompositorHandler + Send + 'static +where + U: Send + 'static, + H: CompositorHandler + Send + 'static, { } diff --git a/examples/simple.rs b/examples/simple.rs index eca2509..906f34b 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -48,10 +48,12 @@ impl compositor::Handler for SurfaceHandler { let height = data.height as usize; let mut new_vec = Vec::with_capacity(width * height * 4); for i in 0..height { - new_vec.extend(&slice[(offset + i * stride)..(offset + i * stride + width * 4)]); + new_vec.extend( + &slice[(offset + i * stride)..(offset + i * stride + width * 4)], + ); } - attributes.user_data.buffer = Some((new_vec, - (data.width as u32, data.height as u32))); + attributes.user_data.buffer = + Some((new_vec, (data.width as u32, data.height as u32))); }); } @@ -67,8 +69,10 @@ impl compositor::Handler for SurfaceHandler { fn main() { // A logger facility, here we use the terminal for this example - let log = Logger::root(slog_async::Async::default(slog_term::term_full().fuse()).fuse(), - o!()); + let log = Logger::root( + slog_async::Async::default(slog_term::term_full().fuse()).fuse(), + o!(), + ); // Initialize a simple backend for testing let (renderer, mut input) = winit::init(log.clone()).unwrap(); @@ -93,14 +97,16 @@ fn main() { /* * Initialize the compositor global */ - let compositor_handler_id = - event_loop.add_handler_with_init(CompositorHandler::::new(SurfaceHandler { - shm_token: shm_token - .clone(), - }, - log.clone())); + let compositor_handler_id = event_loop.add_handler_with_init(CompositorHandler::::new( + SurfaceHandler { shm_token: shm_token.clone() }, + log.clone(), + )); // register it to handle wl_compositor and wl_subcompositor - event_loop.register_global::>(compositor_handler_id, 4); + event_loop + .register_global::>( + compositor_handler_id, + 4, + ); event_loop.register_global::>(compositor_handler_id, 1); // retrieve the tokens let compositor_token = { @@ -113,10 +119,12 @@ fn main() { /* * Initialize the shell stub global */ - let shell_handler_id = event_loop - .add_handler_with_init(WlShellStubHandler::new(compositor_token.clone())); - event_loop.register_global::>(shell_handler_id, - 1); + let shell_handler_id = + event_loop.add_handler_with_init(WlShellStubHandler::new(compositor_token.clone())); + event_loop.register_global::>( + shell_handler_id, + 1, + ); /* * Initialize glium @@ -143,27 +151,30 @@ fn main() { for &(_, ref surface) in state .get_handler::>(shell_handler_id) - .surfaces() { + .surfaces() + { if surface.status() != Liveness::Alive { continue; } // this surface is a root of a subsurface tree that needs to be drawn - compositor_token.with_surface_tree(surface, (100, 100), |surface, - attributes, - &(mut x, mut y)| { - if let Some((ref contents, (w, h))) = attributes.user_data.buffer { - // there is actually something to draw ! - if let Some(ref subdata) = attributes.subsurface_attributes { - x += subdata.x; - y += subdata.y; + compositor_token.with_surface_tree( + surface, + (100, 100), + |surface, attributes, &(mut x, mut y)| { + if let Some((ref contents, (w, h))) = attributes.user_data.buffer { + // there is actually something to draw ! + if let Some(ref subdata) = attributes.subsurface_attributes { + x += subdata.x; + y += subdata.y; + } + drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); + TraversalAction::DoChildren((x, y)) + } else { + // we are not display, so our children are neither + TraversalAction::SkipChildren } - drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); - TraversalAction::DoChildren((x, y)) - } else { - // we are not display, so our children are neither - TraversalAction::SkipChildren - } - }); + }, + ); } } frame.finish().unwrap(); diff --git a/src/compositor/global.rs b/src/compositor/global.rs index 42045ce..cf744ca 100644 --- a/src/compositor/global.rs +++ b/src/compositor/global.rs @@ -14,8 +14,9 @@ impl> GlobalHandler f } impl GlobalHandler for CompositorHandler - where U: Send + 'static, - H: Send + 'static +where + U: Send + 'static, + H: Send + 'static, { fn bind(&mut self, evlh: &mut EventLoopHandle, _: &Client, global: wl_subcompositor::WlSubcompositor) { debug!(self.log, "New subcompositor global binded."); diff --git a/src/compositor/handlers.rs b/src/compositor/handlers.rs index 4a6e598..e418ddc 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -15,8 +15,9 @@ struct CompositorDestructor { */ impl wl_compositor::Handler for CompositorHandler - where U: Default + Send + 'static, - H: UserHandler + Send + 'static +where + U: Default + Send + 'static, + H: UserHandler + Send + 'static, { fn create_surface(&mut self, evqh: &mut EventLoopHandle, _: &Client, _: &wl_compositor::WlCompositor, id: wl_surface::WlSurface) { @@ -54,11 +55,11 @@ impl> wl_surface::Handler for CompositorHandler { unsafe { SurfaceData::::with_data(surface, |d| { d.damage = Damage::Surface(Rectangle { - x, - y, - width, - height, - }) + x, + y, + width, + height, + }) }); } } @@ -105,16 +106,18 @@ impl> wl_surface::Handler for CompositorHandler { } fn damage_buffer(&mut self, _: &mut EventLoopHandle, _: &Client, surface: &wl_surface::WlSurface, x: i32, y: i32, width: i32, height: i32) { - trace!(self.log, - "Registering damage to surface (buffer coordinates)."); + trace!( + self.log, + "Registering damage to surface (buffer coordinates)." + ); unsafe { SurfaceData::::with_data(surface, |d| { d.damage = Damage::Buffer(Rectangle { - x, - y, - width, - height, - }) + x, + y, + width, + height, + }) }); } } @@ -137,28 +140,32 @@ impl wl_region::Handler for CompositorHandler { width: i32, height: i32) { trace!(self.log, "Adding rectangle to a region."); unsafe { - RegionData::add_rectangle(region, - RectangleKind::Add, - Rectangle { - x, - y, - width, - height, - }) + RegionData::add_rectangle( + region, + RectangleKind::Add, + Rectangle { + x, + y, + width, + height, + }, + ) }; } fn subtract(&mut self, _: &mut EventLoopHandle, _: &Client, region: &wl_region::WlRegion, x: i32, y: i32, width: i32, height: i32) { trace!(self.log, "Subtracting rectangle to a region."); unsafe { - RegionData::add_rectangle(region, - RectangleKind::Subtract, - Rectangle { - x, - y, - width, - height, - }) + RegionData::add_rectangle( + region, + RectangleKind::Subtract, + Rectangle { + x, + y, + width, + height, + }, + ) }; } } @@ -176,8 +183,9 @@ impl Destroy for CompositorDestructor { */ impl wl_subcompositor::Handler for CompositorHandler - where U: Send + 'static, - H: Send + 'static +where + U: Send + 'static, + H: Send + 'static, { fn get_subsurface(&mut self, evqh: &mut EventLoopHandle, _: &Client, resource: &wl_subcompositor::WlSubcompositor, id: wl_subsurface::WlSubsurface, @@ -187,7 +195,9 @@ impl wl_subcompositor::Handler for CompositorHandler resource.post_error(wl_subcompositor::Error::BadSurface as u32, "Surface already has a role.".into()); return } - id.set_user_data(Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _); + id.set_user_data(Box::into_raw( + Box::new(unsafe { surface.clone_unchecked() }), + ) as *mut _); unsafe { SurfaceData::::with_data(surface, |d| { d.subsurface_attributes = Some(Default::default()) @@ -204,7 +214,8 @@ server_declare_handler!(CompositorHandler, wl_subcomposito */ unsafe fn with_subsurface_attributes(subsurface: &wl_subsurface::WlSubsurface, f: F) - where F: FnOnce(&mut SubsurfaceAttributes) +where + F: FnOnce(&mut SubsurfaceAttributes), { let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut wl_surface::WlSurface); diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 0b552df..c48d45f 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -285,10 +285,13 @@ impl + Send + 'static> CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn with_surface_data(&self, surface: &wl_surface::WlSurface, f: F) - where F: FnOnce(&mut SurfaceAttributes) + where + F: FnOnce(&mut SurfaceAttributes), { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), - "Accessing the data of foreign surfaces is not supported."); + assert!( + resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported." + ); unsafe { SurfaceData::::with_data(surface, f); } @@ -303,10 +306,13 @@ impl + Send + 'static> CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn with_surface_tree(&self, surface: &wl_surface::WlSurface, initial: T, f: F) -> Result<(), ()> - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction + where + F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction, { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), - "Accessing the data of foreign surfaces is not supported."); + assert!( + resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported." + ); unsafe { SurfaceData::::map_tree(surface, initial, f); } @@ -320,8 +326,10 @@ impl + Send + 'static> CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn get_parent(&self, surface: &wl_surface::WlSurface) -> Option { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), - "Accessing the data of foreign surfaces is not supported."); + assert!( + resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported." + ); unsafe { SurfaceData::::get_parent(surface) } } @@ -330,8 +338,10 @@ impl + Send + 'static> CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn get_children(&self, surface: &wl_surface::WlSurface) -> Vec { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), - "Accessing the data of foreign surfaces is not supported."); + assert!( + resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported." + ); unsafe { SurfaceData::::get_children(surface) } } @@ -340,8 +350,10 @@ impl + Send + 'static> CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn role_status(&self, surface: &wl_surface::WlSurface) -> RoleStatus { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), - "Accessing the data of foreign surfaces is not supported."); + assert!( + resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported." + ); unsafe { SurfaceData::::role_status(surface) } } @@ -355,8 +367,10 @@ impl + Send + 'static> CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn give_role(&self, surface: &wl_surface::WlSurface) -> Result<(), ()> { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), - "Accessing the data of foreign surfaces is not supported."); + assert!( + resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported." + ); unsafe { SurfaceData::::give_role(surface) } } @@ -369,8 +383,10 @@ impl + Send + 'static> CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn remove_role(&self, surface: &wl_surface::WlSurface) -> Result<(), ()> { - assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), - "Accessing the data of foreign surfaces is not supported."); + assert!( + resource_is_registered::<_, CompositorHandler>(surface, self.hid), + "Accessing the data of foreign surfaces is not supported." + ); unsafe { SurfaceData::::remove_role(surface) } } @@ -379,8 +395,10 @@ impl + Send + 'static> CompositorToken { /// If the region is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn get_region_attributes(&self, region: &wl_region::WlRegion) -> RegionAttributes { - assert!(resource_is_registered::<_, CompositorHandler>(region, self.hid), - "Accessing the data of foreign regions is not supported."); + assert!( + resource_is_registered::<_, CompositorHandler>(region, self.hid), + "Accessing the data of foreign regions is not supported." + ); unsafe { RegionData::get_attributes(region) } } } @@ -410,7 +428,8 @@ impl Init for CompositorHandler { impl CompositorHandler { /// Create a new CompositorHandler pub fn new(handler: H, logger: L) -> CompositorHandler - where L: Into> + where + L: Into>, { let log = ::slog_or_stdlog(logger); CompositorHandler { @@ -423,8 +442,10 @@ impl CompositorHandler { /// Create a token to access the data associated to the objects managed by this handler. pub fn get_token(&self) -> CompositorToken { - assert!(self.my_id != ::std::usize::MAX, - "CompositorHandler is not initialized yet."); + assert!( + self.my_id != ::std::usize::MAX, + "CompositorHandler is not initialized yet." + ); trace!(self.log, "Creating a compositor token."); CompositorToken { hid: self.my_id, diff --git a/src/compositor/region.rs b/src/compositor/region.rs index eb09e95..7f56d1c 100644 --- a/src/compositor/region.rs +++ b/src/compositor/region.rs @@ -13,7 +13,9 @@ pub struct RegionData { impl RegionData { /// Initialize the user_data of a region, must be called right when the surface is created pub unsafe fn init(region: &wl_region::WlRegion) { - region.set_user_data(Box::into_raw(Box::new(Mutex::new(RegionData::default()))) as *mut _) + region.set_user_data(Box::into_raw( + Box::new(Mutex::new(RegionData::default())), + ) as *mut _) } /// Cleans the user_data of that surface, must be called when it is destroyed diff --git a/src/compositor/tree.rs b/src/compositor/tree.rs index 71d7786..914f076 100644 --- a/src/compositor/tree.rs +++ b/src/compositor/tree.rs @@ -70,7 +70,9 @@ impl SurfaceData { /// Initialize the user_data of a surface, must be called right when the surface is created pub unsafe fn init(surface: &wl_surface::WlSurface) { - surface.set_user_data(Box::into_raw(Box::new(Mutex::new(SurfaceData::::new()))) as *mut _) + surface.set_user_data(Box::into_raw( + Box::new(Mutex::new(SurfaceData::::new())), + ) as *mut _) } } @@ -270,7 +272,8 @@ impl SurfaceData { /// Note that an internal lock is taken during access of this data, /// so the tree cannot be manipulated at the same time pub unsafe fn with_data(surface: &wl_surface::WlSurface, f: F) - where F: FnOnce(&mut SurfaceAttributes) + where + F: FnOnce(&mut SurfaceAttributes), { let data_mutex = Self::get_data(surface); let mut data_guard = data_mutex.lock().unwrap(); @@ -286,13 +289,15 @@ impl SurfaceData { /// The callback returns wether the traversal should continue or not. Returning /// false will cause an early-stopping. pub unsafe fn map_tree(root: &wl_surface::WlSurface, initial: T, mut f: F) - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction + where + F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction, { // helper function for recursion unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, initial: &T, f: &mut F) -> bool - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction + where + F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction, { // stop if we met the root, so to not deadlock/inifinte loop if surface.equals(root) { From 030261116d18f598b84c9c495c59a6d91f900191 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 23 Jun 2017 16:02:15 +0200 Subject: [PATCH 24/24] winit's Event has more variants now --- src/backend/winit.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/winit.rs b/src/backend/winit.rs index e54ceb8..9f72f11 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -763,6 +763,7 @@ impl InputBackend for WinitInputBackend { *time_counter += 1; } Event::DeviceEvent { .. } => {} + _ => {} }); }