diff --git a/src/compositor/global.rs b/src/compositor/global.rs deleted file mode 100644 index db03be3..0000000 --- a/src/compositor/global.rs +++ /dev/null @@ -1,28 +0,0 @@ -use super::{CompositorHandler, Handler as UserHandler, Role, RoleType, SubsurfaceRole}; - -use wayland_server::{Client, EventLoopHandle, GlobalHandler}; -use wayland_server::protocol::{wl_compositor, wl_subcompositor}; - -impl GlobalHandler for CompositorHandler -where - U: Default + Send + 'static, - R: Default + Send + 'static, - H: UserHandler + 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); - } -} - -impl GlobalHandler for CompositorHandler -where - U: Send + 'static, - R: RoleType + Role + Send + 'static, - 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 b8acb67..63d20d7 100644 --- a/src/compositor/handlers.rs +++ b/src/compositor/handlers.rs @@ -1,66 +1,101 @@ -use super::{CompositorHandler, Damage, Handler as UserHandler, Rectangle, RectangleKind, Role, RoleType, - SubsurfaceRole}; +use super::{CompositorToken, Damage, Rectangle, RectangleKind, Role, RoleType, SubsurfaceRole, + SurfaceUserImplementation}; use super::region::RegionData; use super::tree::{Location, SurfaceData}; -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}; - -struct CompositorDestructor { - _t: ::std::marker::PhantomData, - _r: ::std::marker::PhantomData, -} +use std::cell::RefCell; +use std::rc::Rc; +use wayland_server::{Client, EventLoopHandle, Liveness, Resource}; +use wayland_server::protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface}; /* * wl_compositor */ -impl wl_compositor::Handler for CompositorHandler +pub(crate) fn compositor_bind(evlh: &mut EventLoopHandle, idata: &mut SurfaceIData, + _: &Client, compositor: wl_compositor::WlCompositor) where - U: Default + Send + 'static, - R: Default + Send + 'static, - H: UserHandler + Send + 'static, + U: Default + 'static, + R: Default + 'static, + ID: 'static, { - 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, - ); - } + trace!(idata.log, "Binding a new wl_compositor."); + evlh.register( + &compositor, + compositor_implementation::(), + idata.clone(), + None, + ); } -server_declare_handler!(CompositorHandler, Send]>, wl_compositor::Handler, wl_compositor::WlCompositor); +fn compositor_implementation() -> wl_compositor::Implementation> +where + U: Default + 'static, + R: Default + 'static, + ID: 'static, +{ + wl_compositor::Implementation { + create_surface: |evlh, idata, _, _, surface| { + unsafe { SurfaceData::::init(&surface) }; + evlh.register( + &surface, + surface_implementation::(), + idata.clone(), + Some(destroy_surface::), + ); + }, + create_region: |evlh, _, _, _, region| { + unsafe { RegionData::init(®ion) }; + evlh.register(®ion, region_implementation(), (), Some(destroy_region)); + }, + } +} /* * 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) { - trace!(self.log, "Attaching buffer to surface."); - unsafe { +/// Internal implementation data of surfaces +/// +/// This type is only visible as type parameter of +/// the `Global` handle you are provided. +pub struct SurfaceIData { + log: ::slog::Logger, + implem: SurfaceUserImplementation, + idata: Rc>, +} + +impl SurfaceIData { + pub(crate) fn make(log: ::slog::Logger, implem: SurfaceUserImplementation, idata: ID) + -> SurfaceIData { + SurfaceIData { + log: log, + implem: implem, + idata: Rc::new(RefCell::new(idata)), + } + } +} + +impl Clone for SurfaceIData { + fn clone(&self) -> SurfaceIData { + SurfaceIData { + log: self.log.clone(), + implem: self.implem.clone(), + idata: self.idata.clone(), + } + } +} + +pub(crate) fn surface_implementation( + ) + -> wl_surface::Implementation> +{ + wl_surface::Implementation { + attach: |_, _, _, surface, buffer, x, y| 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) { - trace!(self.log, "Registering damage to surface."); - unsafe { + }, + damage: |_, _, _, surface, x, y, width, height| unsafe { SurfaceData::::with_data(surface, |d| { d.damage = Damage::Surface(Rectangle { x, @@ -69,56 +104,38 @@ impl> wl_surface::Handler for CompositorHandler) { - trace!(self.log, "Setting surface opaque region."); - unsafe { + }, + frame: |evlh, idata, _, surface, callback| { + let mut user_idata = idata.idata.borrow_mut(); + trace!(idata.log, "Calling user callback for wl_surface.frame"); + (idata.implem.frame)( + evlh, + &mut *user_idata, + surface, + callback, + CompositorToken::make(), + ) + }, + set_opaque_region: |_, _, _, surface, region| 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>) { - trace!(self.log, "Setting surface input region."); - unsafe { + }, + set_input_region: |_, _, _, surface, 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."); - 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) { - trace!(self.log, "Setting surface's buffer transform."); - unsafe { + }, + commit: |evlh, idata, _, surface| { + let mut user_idata = idata.idata.borrow_mut(); + trace!(idata.log, "Calling user callback for wl_surface.commit"); + (idata.implem.commit)(evlh, &mut *user_idata, surface, CompositorToken::make()) + }, + set_buffer_transform: |_, _, _, surface, 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 { + }, + set_buffer_scale: |_, _, _, surface, 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 { + }, + damage_buffer: |_, _, _, surface, x, y, width, height| unsafe { SurfaceData::::with_data(surface, |d| { d.damage = Damage::Buffer(Rectangle { x, @@ -127,97 +144,102 @@ impl> wl_surface::Handler for CompositorHandler]>, wl_surface::Handler, wl_surface::WlSurface); - -impl Destroy for CompositorDestructor { - fn destroy(surface: &wl_surface::WlSurface) { - unsafe { SurfaceData::::cleanup(surface) } - } +fn destroy_surface(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) { - trace!(self.log, "Adding rectangle to a region."); - 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) { - trace!(self.log, "Subtracting rectangle to a region."); - unsafe { - RegionData::add_rectangle( - region, - RectangleKind::Subtract, - Rectangle { - x, - y, - width, - height, - }, - ) - }; +pub(crate) fn region_implementation() -> wl_region::Implementation<()> { + wl_region::Implementation { + add: |_, _, _, region, x, y, width, height| { + unsafe { + RegionData::add_rectangle( + region, + RectangleKind::Add, + Rectangle { + x, + y, + width, + height, + }, + ) + }; + }, + subtract: |_, _, _, region, x, y, width, height| { + unsafe { + RegionData::add_rectangle( + region, + RectangleKind::Subtract, + Rectangle { + x, + y, + width, + height, + }, + ) + }; + }, + destroy: |_, _, _, _| {}, } } -server_declare_handler!(CompositorHandler, wl_region::Handler, wl_region::WlRegion); - -impl Destroy for CompositorDestructor { - fn destroy(region: &wl_region::WlRegion) { - unsafe { RegionData::cleanup(region) }; - } +fn destroy_region(region: &wl_region::WlRegion) { + unsafe { RegionData::cleanup(region) }; } /* * wl_subcompositor */ -impl wl_subcompositor::Handler for CompositorHandler +pub(crate) fn subcompositor_bind(evlh: &mut EventLoopHandle, _: &mut (), _: &Client, + subcompositor: wl_subcompositor::WlSubcompositor) where - U: Send + 'static, - R: RoleType + Role + Send + 'static, - H: Send + 'static, + R: RoleType + Role + 'static, + U: '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) { - 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; - } - id.set_user_data( - Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _, - ); - evqh.register_with_destructor::<_, CompositorHandler, CompositorDestructor>( - &id, - self.my_id, - ); - } + evlh.register( + &subcompositor, + subcompositor_implementation::(), + (), + None, + ); } -server_declare_handler!(CompositorHandler, Send], H: [Send]>, wl_subcompositor::Handler, wl_subcompositor::WlSubcompositor); +fn subcompositor_implementation() -> wl_subcompositor::Implementation<()> +where + R: RoleType + Role + 'static, + U: 'static, +{ + wl_subcompositor::Implementation { + get_subsurface: |evlh, _, _, subcompositor, subsurface, surface, parent| { + if let Err(()) = unsafe { SurfaceData::::set_parent(surface, parent) } { + subcompositor.post_error( + wl_subcompositor::Error::BadSurface as u32, + "Surface already has a role.".into(), + ); + return; + } + subsurface.set_user_data( + Box::into_raw(Box::new(unsafe { surface.clone_unchecked() })) as *mut _, + ); + evlh.register( + &subsurface, + subsurface_implementation::(), + (), + Some(destroy_subsurface::), + ); + }, + destroy: |_, _, _, _| {}, + } +} /* * wl_subsurface @@ -226,7 +248,8 @@ server_declare_handler!(CompositorHandler(subsurface: &wl_subsurface::WlSubsurface, f: F) where F: FnOnce(&mut SubsurfaceRole), - R: RoleType + Role, + U: 'static, + R: RoleType + Role + 'static, { let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut wl_surface::WlSurface); @@ -235,24 +258,19 @@ where ); } -impl wl_subsurface::Handler for CompositorHandler +fn subsurface_implementation() -> wl_subsurface::Implementation<()> where - R: RoleType + Role, + R: RoleType + Role + 'static, + U: 'static, { - fn set_position(&mut self, _: &mut EventLoopHandle, _: &Client, - subsurface: &wl_subsurface::WlSubsurface, x: i32, y: i32) { - trace!(self.log, "Setting subsurface position."); - unsafe { + wl_subsurface::Implementation { + set_position: |_, _, _, subsurface, x, y| unsafe { with_subsurface_attributes::(subsurface, |attrs| { attrs.x = x; attrs.y = y; }); - } - } - 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 { + }, + place_above: |_, _, _, subsurface, sibling| unsafe { let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut wl_surface::WlSurface); if let Err(()) = SurfaceData::::reorder(surface, Location::After, sibling) { @@ -261,12 +279,8 @@ where "Provided surface is not a sibling or parent.".into(), ); } - } - } - 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 { + }, + place_below: |_, _, _, subsurface, sibling| unsafe { let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut wl_surface::WlSurface); if let Err(()) = SurfaceData::::reorder(surface, Location::Before, sibling) { @@ -275,36 +289,32 @@ where "Provided surface is not a sibling or parent.".into(), ); } - } - } - 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; }); - } + }, + set_sync: |_, _, _, subsurface| unsafe { + with_subsurface_attributes::(subsurface, |attrs| { + attrs.sync = true; + }); + }, + set_desync: |_, _, _, subsurface| unsafe { + with_subsurface_attributes::(subsurface, |attrs| { + attrs.sync = false; + }); + }, + destroy: |_, _, _, _| {}, } } -server_declare_handler!(CompositorHandler], H: []>, wl_subsurface::Handler, wl_subsurface::WlSubsurface); - -impl Destroy for CompositorDestructor +fn destroy_subsurface(subsurface: &wl_subsurface::WlSubsurface) where - R: RoleType + Role, + U: 'static, + R: RoleType + Role + 'static, { - 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); - if surface.status() == Liveness::Alive { - SurfaceData::::unset_parent(&surface); - } + 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); + if surface.status() == Liveness::Alive { + SurfaceData::::unset_parent(&surface); } } } diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 77d11b0..68336c2 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -1,13 +1,12 @@ //! 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`. +//! This module provides automatic handling of sufaces, subsurfaces +//! and region wayland objects, by registering an implementation for +//! for the `wl_compositor` and `wl_subcompositor` globals. //! -//! ## Why use this handler +//! ## Why use this implementation //! -//! This handler does a simple job: it stores in a coherent way the state of +//! This implementation 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. //! @@ -15,7 +14,7 @@ //! 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 +//! This implementation 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. //! @@ -23,15 +22,16 @@ //! //! ### 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: +//! To initialize this implementation, use the `compositor_init` method provided +//! by this module. It'll require you to first define as few things, as shown in +//! this example: //! //! ``` //! # extern crate wayland_server; //! # #[macro_use] extern crate smithay; //! use wayland_server::protocol::wl_compositor::WlCompositor; //! use wayland_server::protocol::wl_subcompositor::WlSubcompositor; -//! use smithay::compositor; +//! use smithay::compositor::{compositor_init, SurfaceUserImplementation}; //! //! // 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 @@ -44,39 +44,25 @@ //! // Declare the roles enum //! define_roles!(MyRoles); //! -//! // 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(); +//! // define your implementation for surface +//! let my_implementation = SurfaceUserImplementation { +//! commit: |evlh, idata, surface, token| { /* ... */ }, +//! frame: |evlh, idata, surface, callback, token| { /* ... */ } +//! }; +//! // define your implementation data +//! let my_implementation_data = (); //! -//! // Instanciate the CompositorHandler and give it to the event loop -//! let compositor_hid = event_loop.add_handler_with_init( -//! MyCompositorHandler::new(MyHandler{ /* ... */ }, None /* put a logger here */) +//! // Call the init function: +//! let (token, _, _) = compositor_init::( +//! &mut event_loop, +//! my_implementation, // instance of compositor::SurfaceUserImplementation +//! my_implementation_data, // whatever implementation data you need +//! None // put a logger here //! ); //! -//! // Register it as a handler for wl_compositor -//! event_loop.register_global::(compositor_hid, 4); -//! -//! // Register it as a handler for wl_subcompositor -//! 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::(compositor_hid).get_token() -//! }; +//! // this `token` is what you'll use to access the surface associated data //! //! // You're now ready to go! //! # } @@ -85,8 +71,9 @@ //! ### 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 init function. This token is necessary to retrieve the metadata associated with +//! a surface. It can be cloned, and is sendable accross threads (as long as your +//! `Mydata` and `MyRoles` are `Send` too). See `CompositorToken` for //! the details of what it enables you. //! //! The surface metadata is held in the `SurfaceAttributes` struct. In contains double-buffered @@ -97,19 +84,19 @@ //! This `CompositorToken` also provides access to the metadata associated with the role of the //! surfaces. See the documentation of the `roles` submodule for a detailed explanation. -mod global; mod handlers; mod tree; mod region; pub mod roles; +pub use self::handlers::SurfaceIData; use self::region::RegionData; use self::roles::{Role, RoleType, WrongRole}; use self::tree::SurfaceData; pub use self::tree::TraversalAction; -use wayland_server::{resource_is_registered, Client, EventLoopHandle, Init}; - -use wayland_server::protocol::{wl_buffer, wl_callback, wl_output, wl_region, wl_surface}; +use wayland_server::{resource_is_registered, EventLoop, EventLoopHandle, Global}; +use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, + wl_subcompositor, wl_surface}; /// Description of which part of a surface /// should be considered damaged and needs to be redrawn @@ -124,6 +111,12 @@ pub enum Damage { Buffer(Rectangle), } +#[derive(Copy, Clone, Default)] +struct Marker { + _u: ::std::marker::PhantomData, + _r: ::std::marker::PhantomData, +} + /// Data associated with a surface, aggreged by the handlers /// /// Most of the fields of this struct represent a double-buffered state, which @@ -261,26 +254,35 @@ 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. -pub struct CompositorToken { - hid: usize, +pub struct CompositorToken { _data: ::std::marker::PhantomData<*mut U>, _role: ::std::marker::PhantomData<*mut R>, - _handler: ::std::marker::PhantomData<*mut H>, + _idata: ::std::marker::PhantomData<*mut ID>, } -unsafe impl Send for CompositorToken {} -unsafe impl Sync for 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 { +// U: Clone and R: Clone +impl Copy for CompositorToken {} +impl Clone for CompositorToken { + fn clone(&self) -> CompositorToken { *self } } -impl + Send + 'static> CompositorToken { +impl CompositorToken { + pub(crate) fn make() -> CompositorToken { + CompositorToken { + _data: ::std::marker::PhantomData, + _role: ::std::marker::PhantomData, + _idata: ::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. @@ -292,18 +294,21 @@ impl + Send + 'static> Co F: FnOnce(&mut SurfaceAttributes) -> T, { assert!( - resource_is_registered::<_, CompositorHandler>(surface, self.hid), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::with_data(surface, f) } } } -impl CompositorToken +impl CompositorToken where - U: Send + 'static, - R: RoleType + Role + Send + 'static, - H: Handler + Send + 'static, + U: 'static, + R: RoleType + Role + 'static, + ID: 'static, { /// Access the data of a surface tree /// @@ -327,7 +332,10 @@ where -> TraversalAction, { assert!( - resource_is_registered::<_, CompositorHandler>(surface, self.hid), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { @@ -344,7 +352,10 @@ where /// 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), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::get_parent(surface) } @@ -356,22 +367,27 @@ where /// 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), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::get_children(surface) } } } -impl + Send + 'static> - CompositorToken { +impl CompositorToken { /// Check wether this surface as a role or not /// /// 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 has_a_role(&self, surface: &wl_surface::WlSurface) -> bool { assert!( - resource_is_registered::<_, CompositorHandler>(surface, self.hid), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::has_a_role(surface) } @@ -386,7 +402,10 @@ impl + Send + R: Role, { assert!( - resource_is_registered::<_, CompositorHandler>(surface, self.hid), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::has_role::(surface) } @@ -405,7 +424,10 @@ impl + Send + RoleData: Default, { assert!( - resource_is_registered::<_, CompositorHandler>(surface, self.hid), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::give_role::(surface) } @@ -423,7 +445,10 @@ impl + Send + R: Role, { assert!( - resource_is_registered::<_, CompositorHandler>(surface, self.hid), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::give_role_with::(surface, data) } @@ -442,7 +467,10 @@ impl + Send + F: FnOnce(&mut RoleData) -> T, { assert!( - resource_is_registered::<_, CompositorHandler>(surface, self.hid), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::with_role_data::(surface, f) } @@ -459,7 +487,10 @@ impl + Send + R: Role, { assert!( - resource_is_registered::<_, CompositorHandler>(surface, self.hid), + resource_is_registered( + surface, + &self::handlers::surface_implementation::() + ), "Accessing the data of foreign surfaces is not supported." ); unsafe { SurfaceData::::remove_role::(surface) } @@ -471,98 +502,93 @@ impl + Send + /// 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." + resource_is_registered(region, &self::handlers::region_implementation()), + "Accessing the data of foreign surfaces is not supported." ); unsafe { RegionData::get_attributes(region) } } } -/// A struct handling the `wl_compositor` and `wl_subcompositor` globals +/// Create new 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. +/// The globals are directly registered into the eventloop, and this function +/// returns a `CompositorToken` which you'll need access the data associated to +/// the `wl_surface`s. /// -/// See the module-level documentation for instructions and examples of use. -pub struct CompositorHandler { - my_id: usize, - log: ::slog::Logger, - handler: H, - _role: ::std::marker::PhantomData, - _data: ::std::marker::PhantomData, +/// It also returns the two global handles, in case you whish to remove these +/// globals from the event loop in the future. +pub fn compositor_init( + evl: &mut EventLoop, implem: SurfaceUserImplementation, idata: ID, logger: L) + -> ( + CompositorToken, + Global>, + Global, + ) +where + L: Into>, + U: Default + 'static, + R: Default + RoleType + Role + 'static, + ID: 'static, +{ + let log = ::slog_or_stdlog(logger); + let idata = self::handlers::SurfaceIData::make( + log.new(o!("smithay_module" => "compositor_handler")), + implem, + idata, + ); + let compositor_global_token = + evl.register_global::(4, self::handlers::compositor_bind, idata); + let subcompositor_global_token = evl.register_global::( + 1, + self::handlers::subcompositor_bind::, + (), + ); + + ( + CompositorToken::make(), + compositor_global_token, + subcompositor_global_token, + ) } -impl Init for CompositorHandler { - fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) { - self.my_id = index; - debug!(self.log, "Init finished") - } -} - -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, - _role: ::std::marker::PhantomData, - _data: ::std::marker::PhantomData, - } - } - - /// 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." - ); - trace!(self.log, "Creating a compositor token."); - CompositorToken { - hid: self.my_id, - _data: ::std::marker::PhantomData, - _role: ::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 +/// Sub-implementation 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`. -#[allow(unused_variables)] -pub trait Handler: Sized { +/// are forwarded directly to this implementation that you must provide +/// at creation of the compositor global. +pub struct SurfaceUserImplementation { /// 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) + /// See [`wayland_server::protocol::wl_surface::Implementation::commit`](https://docs.rs/wayland-server/0.10.1/wayland_server/protocol/wl_surface/struct.Implementation.html#structfield.commit) /// for more details - fn commit(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, - token: CompositorToken) { - } + pub commit: fn( + evlh: &mut EventLoopHandle, + idata: &mut ID, + 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 /// 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) + /// See [`wayland_server::protocol::wl_surface::Implementation::frame`](https://docs.rs/wayland-server/0.10.1/wayland_server/protocol/wl_surface/struct.Implementation.html#structfield.frame) /// for more details - fn frame(&mut self, evlh: &mut EventLoopHandle, client: &Client, surface: &wl_surface::WlSurface, - callback: wl_callback::WlCallback, token: CompositorToken) { + pub frame: fn( + evlh: &mut EventLoopHandle, + idata: &mut ID, + surface: &wl_surface::WlSurface, + callback: wl_callback::WlCallback, + token: CompositorToken, + ), +} + +impl Copy for SurfaceUserImplementation {} +impl Clone for SurfaceUserImplementation { + fn clone(&self) -> SurfaceUserImplementation { + *self } } diff --git a/src/compositor/region.rs b/src/compositor/region.rs index d6a7a22..b4f0b48 100644 --- a/src/compositor/region.rs +++ b/src/compositor/region.rs @@ -1,8 +1,6 @@ use super::{Rectangle, RectangleKind, RegionAttributes}; - use std::sync::Mutex; use wayland_server::Resource; - use wayland_server::protocol::wl_region; #[derive(Default)] @@ -13,9 +11,8 @@ 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 ccd0de4..134f7c9 100644 --- a/src/compositor/tree.rs +++ b/src/compositor/tree.rs @@ -1,7 +1,6 @@ use super::{SubsurfaceRole, SurfaceAttributes}; use super::roles::*; use std::sync::Mutex; - use wayland_server::{Liveness, Resource}; use wayland_server::protocol::wl_surface; @@ -64,7 +63,11 @@ impl SurfaceData { } } -impl SurfaceData { +impl SurfaceData +where + U: 'static, + R: 'static, +{ unsafe fn get_data(surface: &wl_surface::WlSurface) -> &Mutex> { let ptr = surface.get_user_data(); &*(ptr as *mut _) @@ -97,7 +100,7 @@ impl SurfaceData { } } -impl SurfaceData { +impl SurfaceData { pub unsafe fn has_a_role(surface: &wl_surface::WlSurface) -> bool { debug_assert!(surface.status() == Liveness::Alive); let data_mutex = Self::get_data(surface); @@ -171,7 +174,7 @@ impl SurfaceData { } } -impl> SurfaceData { +impl + 'static> SurfaceData { /// Sets the parent of a surface /// /// if this surface already has a role, does nothing and fails, otherwise @@ -291,7 +294,7 @@ impl> SurfaceData { } } -impl SurfaceData { +impl SurfaceData { /// Access the attributes associated with a surface /// /// Note that an internal lock is taken during access of this data, @@ -319,9 +322,9 @@ impl SurfaceData { -> TraversalAction, { // helper function for recursion - unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, - initial: &T, f: &mut F) - -> 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, &mut R, &T) -> TraversalAction, diff --git a/src/lib.rs b/src/lib.rs index e36afb5..09fb217 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ extern crate slog; extern crate slog_stdlog; pub mod backend; -//pub mod compositor; +pub mod compositor; pub mod shm; pub mod keyboard; //pub mod shell;