use super::{CompositorToken, Damage, Rectangle, RectangleKind, Role, RoleType, SubsurfaceRole, SurfaceEvent}; use super::region::RegionData; use super::tree::{Location, SurfaceData}; use std::cell::RefCell; use std::rc::Rc; use wayland_server::{LoopToken, NewResource, Resource}; use wayland_server::commons::Implementation; use wayland_server::protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface}; /* * wl_compositor */ pub(crate) fn implement_compositor( compositor: NewResource, token: LoopToken, log: ::slog::Logger, implem: Rc>, ) -> Resource where U: Default + 'static, R: Default + 'static, Impl: Implementation<(Resource, CompositorToken), SurfaceEvent> + 'static, { let my_token = token.clone(); compositor.implement_nonsend( move |request, _compositor| match request { wl_compositor::Request::CreateSurface { id } => { trace!(log, "Creating a new wl_surface."); implement_surface(id, &token, log.clone(), implem.clone()); } wl_compositor::Request::CreateRegion { id } => { trace!(log, "Creating a new wl_region."); implement_region(id, &token); } }, None::, &my_token, ) } /* * wl_surface */ // Internal implementation data of surfaces pub(crate) struct SurfaceImplem { log: ::slog::Logger, implem: Rc, CompositorToken), SurfaceEvent>>>, } impl SurfaceImplem { fn make(log: ::slog::Logger, implem: Rc>) -> SurfaceImplem where Impl: Implementation<(Resource, CompositorToken), SurfaceEvent> + 'static, { SurfaceImplem { log, implem, } } } impl Implementation, wl_surface::Request> for SurfaceImplem where U: 'static, R: 'static, { fn receive(&mut self, req: wl_surface::Request, surface: Resource) { match req { wl_surface::Request::Attach { buffer, x, y } => unsafe { SurfaceData::::with_data(&surface, |d| { d.buffer = Some(buffer.map(|b| (b.clone(), (x, y)))) }); }, wl_surface::Request::Damage { x, y, width, height, } => unsafe { SurfaceData::::with_data(&surface, |d| { d.damage = Damage::Surface(Rectangle { x, y, width, height, }) }); }, wl_surface::Request::Frame { callback } => { let mut user_impl = self.implem.borrow_mut(); trace!(self.log, "Calling user implementation for wl_surface.frame"); user_impl.receive( SurfaceEvent::Frame { callback }, (surface, CompositorToken::make()), ); } wl_surface::Request::SetOpaqueRegion { region } => unsafe { let attributes = region.map(|r| RegionData::get_attributes(&r)); SurfaceData::::with_data(&surface, |d| d.opaque_region = attributes); }, wl_surface::Request::SetInputRegion { region } => unsafe { let attributes = region.map(|r| RegionData::get_attributes(&r)); SurfaceData::::with_data(&surface, |d| d.input_region = attributes); }, wl_surface::Request::Commit => { let mut user_impl = self.implem.borrow_mut(); trace!( self.log, "Calling user implementation for wl_surface.commit" ); user_impl.receive(SurfaceEvent::Commit, (surface, CompositorToken::make())); } wl_surface::Request::SetBufferTransform { transform } => unsafe { SurfaceData::::with_data(&surface, |d| d.buffer_transform = transform); }, wl_surface::Request::SetBufferScale { scale } => unsafe { SurfaceData::::with_data(&surface, |d| d.buffer_scale = scale); }, wl_surface::Request::DamageBuffer { x, y, width, height, } => unsafe { SurfaceData::::with_data(&surface, |d| { d.damage = Damage::Buffer(Rectangle { x, y, width, height, }) }); }, wl_surface::Request::Destroy => { // All is already handled by our destructor } } } } fn implement_surface( surface: NewResource, token: &LoopToken, log: ::slog::Logger, implem: Rc>, ) -> Resource where U: Default + 'static, R: Default + 'static, Impl: Implementation<(Resource, CompositorToken), SurfaceEvent> + 'static, { let surface = surface.implement_nonsend( SurfaceImplem::make(log, implem), Some(|surface, _| unsafe { SurfaceData::::cleanup(&surface); }), token, ); unsafe { SurfaceData::::init(&surface); } surface } /* * wl_region */ pub(crate) struct RegionImplem; impl Implementation, wl_region::Request> for RegionImplem { fn receive(&mut self, request: wl_region::Request, region: Resource) { unsafe { match request { wl_region::Request::Add { x, y, width, height, } => RegionData::add_rectangle( ®ion, RectangleKind::Add, Rectangle { x, y, width, height, }, ), wl_region::Request::Subtract { x, y, width, height, } => RegionData::add_rectangle( ®ion, RectangleKind::Subtract, Rectangle { x, y, width, height, }, ), wl_region::Request::Destroy => { // all is handled by our destructor } } } } } fn implement_region( region: NewResource, token: &LoopToken, ) -> Resource { let region = region.implement_nonsend( RegionImplem, Some(|region, _| unsafe { RegionData::cleanup(®ion) }), token, ); unsafe { RegionData::init(®ion); } region } /* * wl_subcompositor */ pub(crate) fn implement_subcompositor( subcompositor: NewResource, token: LoopToken, ) -> Resource where R: RoleType + Role + 'static, U: 'static, { let my_token = token.clone(); subcompositor.implement_nonsend( move |request, subcompositor: Resource<_>| match request { wl_subcompositor::Request::GetSubsurface { id, 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; } let subsurface = implement_subsurface::(id, &token); subsurface.set_user_data(Box::into_raw(Box::new(surface.clone())) as *mut ()); } wl_subcompositor::Request::Destroy => {} }, None::, &my_token, ) } /* * wl_subsurface */ unsafe fn with_subsurface_attributes(subsurface: &Resource, f: F) where F: FnOnce(&mut SubsurfaceRole), U: 'static, R: RoleType + Role + 'static, { let ptr = subsurface.get_user_data(); let surface = &*(ptr as *mut Resource); SurfaceData::::with_role_data::(surface, |d| f(d)) .expect("The surface does not have a subsurface role while it has a wl_subsurface?!"); } fn implement_subsurface( subsurface: NewResource, token: &LoopToken, ) -> Resource where U: 'static, R: RoleType + Role + 'static, { subsurface.implement_nonsend( |request, subsurface| unsafe { match request { wl_subsurface::Request::SetPosition { x, y } => { with_subsurface_attributes::(&subsurface, |attrs| { attrs.location = (x, y); }) } wl_subsurface::Request::PlaceAbove { sibling } => { let surface = &*(subsurface.get_user_data() as *mut Resource); 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(), ) } } wl_subsurface::Request::PlaceBelow { sibling } => { let surface = &*(subsurface.get_user_data() as *mut Resource); 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(), ) } } wl_subsurface::Request::SetSync => { with_subsurface_attributes::(&subsurface, |attrs| { attrs.sync = true; }) } wl_subsurface::Request::SetDesync => { with_subsurface_attributes::(&subsurface, |attrs| { attrs.sync = false; }) } wl_subsurface::Request::Destroy => { // Our destructor already handles it } } }, Some(|subsurface, _| unsafe { destroy_subsurface::(&subsurface); }), token, ) } unsafe fn destroy_subsurface(subsurface: &Resource) where U: 'static, R: RoleType + Role + 'static, { let ptr = subsurface.get_user_data(); subsurface.set_user_data(::std::ptr::null_mut()); let surface = Box::from_raw(ptr as *mut Resource); if surface.is_alive() { SurfaceData::::unset_parent(&surface); } }