use std::collections::{hash_map, HashMap, HashSet}; use std::io::Read; use std::io::Write; use std::os::fd::{AsFd, BorrowedFd, OwnedFd}; use std::os::unix::net::UnixStream; use std::sync::{Arc, Mutex, OnceLock}; use std::time::Instant; use wayland_protocols::{ wp::{ linux_dmabuf::zv1::server::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1, pointer_constraints::zv1::server::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1, relative_pointer::zv1::server::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, viewporter::server::wp_viewporter::WpViewporter, }, xdg::{ shell::server::{ xdg_popup::{self, XdgPopup}, xdg_positioner::{self, XdgPositioner}, xdg_surface::XdgSurface, xdg_toplevel::{self, XdgToplevel}, xdg_wm_base::{self, XdgWmBase}, }, xdg_output::zv1::server::zxdg_output_manager_v1::ZxdgOutputManagerV1, }, }; use wayland_server::{ backend::{ protocol::{Interface, ProtocolError}, GlobalHandler, ObjectData, }, protocol::{ self as proto, wl_buffer::WlBuffer, wl_callback::WlCallback, wl_compositor::WlCompositor, wl_data_device::{self, WlDataDevice}, wl_data_device_manager::{self, WlDataDeviceManager}, wl_data_offer::{self, WlDataOffer}, wl_data_source::{self, WlDataSource}, wl_keyboard::{self, WlKeyboard}, wl_output::WlOutput, wl_pointer::{self, WlPointer}, wl_seat::{self, WlSeat}, wl_shm::WlShm, wl_shm_pool::WlShmPool, wl_surface::WlSurface, }, Client, Dispatch, Display, DisplayHandle, GlobalDispatch, Resource, }; use wl_drm::server::wl_drm::WlDrm; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct BufferDamage { pub x: i32, pub y: i32, pub width: i32, pub height: i32, } #[derive(Debug, PartialEq, Eq)] pub struct SurfaceData { pub surface: WlSurface, pub buffer: Option, pub last_damage: Option, pub role: Option, pub last_enter_serial: Option, } impl SurfaceData { pub fn xdg(&self) -> &XdgSurfaceData { match self.role.as_ref().expect("Surface missing role") { SurfaceRole::Toplevel(ref t) => &t.xdg, SurfaceRole::Popup(ref p) => &p.xdg, SurfaceRole::Cursor => panic!("cursor surface doesn't have an XdgSurface"), } } pub fn toplevel(&self) -> &Toplevel { match self.role.as_ref().expect("Surface missing role") { SurfaceRole::Toplevel(ref t) => t, other => panic!("Surface role was not toplevel: {other:?}"), } } pub fn popup(&self) -> &Popup { match self.role.as_ref().expect("Surface missing role") { SurfaceRole::Popup(ref p) => p, other => panic!("Surface role was not popup: {other:?}"), } } } #[derive(Debug, PartialEq, Eq)] pub enum SurfaceRole { Toplevel(Toplevel), Popup(Popup), Cursor, } #[derive(Debug, PartialEq, Eq)] pub struct Toplevel { pub xdg: XdgSurfaceData, pub toplevel: XdgToplevel, pub min_size: Option, pub max_size: Option, pub states: Vec, pub closed: bool, pub title: Option, pub app_id: Option, } #[derive(Debug, PartialEq, Eq)] pub struct Popup { pub xdg: XdgSurfaceData, pub parent: XdgSurface, pub popup: XdgPopup, pub positioner_state: PositionerState, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub struct Vec2 { pub x: i32, pub y: i32, } #[derive(Debug, PartialEq, Eq)] pub struct XdgSurfaceData { pub surface: XdgSurface, pub last_configure_serial: u32, } impl XdgSurfaceData { fn new(surface: XdgSurface) -> Self { Self { surface, last_configure_serial: 0, } } fn configure(&mut self, serial: u32) { self.surface.configure(serial); self.last_configure_serial = serial; } } #[derive(Debug, Hash, Clone, Copy, Eq, PartialEq)] pub struct SurfaceId(u32); #[derive(Hash, Clone, Copy, Eq, PartialEq)] struct PositionerId(u32); #[derive(Default)] struct DataSourceData { mimes: Vec, } struct State { surfaces: HashMap, positioners: HashMap, buffers: HashSet, begin: Instant, last_surface_id: Option, callbacks: Vec, pointer: Option, keyboard: Option, configure_serial: u32, selection: Option, data_device_man: Option, data_device: Option, } impl Default for State { fn default() -> Self { Self { surfaces: Default::default(), buffers: Default::default(), positioners: Default::default(), begin: Instant::now(), last_surface_id: None, callbacks: Vec::new(), pointer: None, keyboard: None, configure_serial: 0, selection: None, data_device_man: None, data_device: None, } } } impl State { #[track_caller] fn configure_toplevel( &mut self, surface_id: SurfaceId, width: i32, height: i32, states: Vec, ) { let last_serial = self.configure_serial; if states.contains(&xdg_toplevel::State::Activated) { if let Some(kb) = &self.keyboard { kb.enter( last_serial, &self.surfaces[&surface_id].surface, Vec::default(), ); } } let toplevel = self.get_toplevel(surface_id); toplevel.states = states.clone(); let states: Vec = states .into_iter() .map(|state| u32::from(state) as u8) .collect(); toplevel.toplevel.configure(width, height, states); toplevel.xdg.configure(last_serial); self.configure_serial += 1; } #[track_caller] fn get_toplevel(&mut self, surface_id: SurfaceId) -> &mut Toplevel { let surface = self .surfaces .get_mut(&surface_id) .expect("Surface does not exist"); match &mut surface.role { Some(SurfaceRole::Toplevel(t)) => t, other => panic!("Surface does not have toplevel role: {:?}", other), } } } macro_rules! simple_global_dispatch { ($type:ty) => { impl GlobalDispatch<$type, ()> for State { fn bind( _: &mut Self, _: &DisplayHandle, _: &wayland_server::Client, resource: wayland_server::New<$type>, _: &(), data_init: &mut wayland_server::DataInit<'_, Self>, ) { data_init.init(resource, ()); } } }; } pub struct Server { display: Display, dh: DisplayHandle, state: State, client: Option, configure_serial: u32, } impl Server { pub fn new(noops: bool) -> Self { let display = Display::new().unwrap(); let dh = display.handle(); macro_rules! global_noop { ($type:ty) => { if noops { dh.create_global::(1, ()); } simple_global_dispatch!($type); impl Dispatch<$type, ()> for State { fn request( _: &mut Self, _: &Client, _: &$type, _: <$type as Resource>::Request, _: &(), _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { todo!("Dispatch for {} is no-op", stringify!($type)); } } }; } dh.create_global::(6, ()); dh.create_global::(1, ()); dh.create_global::(6, ()); dh.create_global::(5, ()); dh.create_global::(3, ()); global_noop!(WlOutput); global_noop!(ZwpLinuxDmabufV1); global_noop!(ZwpRelativePointerManagerV1); global_noop!(ZxdgOutputManagerV1); global_noop!(WpViewporter); global_noop!(ZwpPointerConstraintsV1); struct HandlerData; impl ObjectData for HandlerData { fn request( self: Arc, _: &wayland_server::backend::Handle, _: &mut State, _: wayland_server::backend::ClientId, _: wayland_server::backend::protocol::Message< wayland_server::backend::ObjectId, OwnedFd, >, ) -> Option>> { None } fn destroyed( self: Arc, _: &wayland_server::backend::Handle, _: &mut State, _: wayland_server::backend::ClientId, _: wayland_server::backend::ObjectId, ) { } } struct Handler; impl GlobalHandler for Handler { fn bind( self: Arc, _: &wayland_server::backend::Handle, _: &mut State, _: wayland_server::backend::ClientId, _: wayland_server::backend::GlobalId, _: wayland_server::backend::ObjectId, ) -> Arc> { Arc::new(HandlerData) } } // Simulate interface with higher interface than supported client side static IF: OnceLock = OnceLock::new(); let interface = IF.get_or_init(|| Interface { version: WlDrm::interface().version + 1, ..*WlDrm::interface() }); if noops { dh.backend_handle() .create_global(&interface, interface.version, Arc::new(Handler)); } Self { display, dh, state: State::default(), client: None, configure_serial: 1, } } pub fn poll_fd(&mut self) -> BorrowedFd<'_> { self.display.backend().poll_fd() } pub fn connect(&mut self, stream: UnixStream) { let client = self .dh .insert_client(stream, std::sync::Arc::new(())) .unwrap(); assert!( self.client.replace(client).is_none(), "Client already connected to test server" ); } pub fn dispatch(&mut self) { self.display.dispatch_clients(&mut self.state).unwrap(); for callback in std::mem::take(&mut self.state.callbacks) { callback.done(self.state.begin.elapsed().as_millis().try_into().unwrap()); } self.display.flush_clients().unwrap(); } pub fn get_surface_data(&self, surface_id: SurfaceId) -> Option<&SurfaceData> { self.state.surfaces.get(&surface_id) } pub fn last_created_surface_id(&self) -> Option { self.state.last_surface_id } pub fn get_object( &self, id: SurfaceId, ) -> Result { let client = self.client.as_ref().unwrap(); client.object_from_protocol_id::(&self.display.handle(), id.0) } #[track_caller] pub fn configure_toplevel( &mut self, surface_id: SurfaceId, width: i32, height: i32, states: Vec, ) { self.state .configure_toplevel(surface_id, width, height, states); self.display.flush_clients().unwrap(); } #[track_caller] pub fn configure_popup(&mut self, surface_id: SurfaceId) { let surface = self.state.surfaces.get_mut(&surface_id).unwrap(); let Some(SurfaceRole::Popup(p)) = &mut surface.role else { panic!("Surface does not have popup role: {:?}", surface.role); }; let PositionerState { size, offset, .. } = &p.positioner_state; let size = size.unwrap(); p.popup.configure(offset.x, offset.y, size.x, size.y); p.xdg.configure(self.configure_serial); self.configure_serial += 1; self.dispatch(); } #[track_caller] pub fn close_toplevel(&mut self, surface_id: SurfaceId) { let toplevel = self.state.get_toplevel(surface_id); toplevel.toplevel.close(); self.dispatch(); } #[track_caller] pub fn pointer(&self) -> &WlPointer { self.state.pointer.as_ref().unwrap() } pub fn data_source_mimes(&self) -> Vec { let Some(selection) = &self.state.selection else { panic!("No selection set on data device"); }; let data: &Mutex = selection.data().unwrap(); let data = data.lock().unwrap(); data.mimes.to_vec() } pub fn paste_data(&mut self) -> PasteDataResolver { let Some(selection) = &self.state.selection else { panic!("No selection set on data device"); }; let ret = PasteDataResolver::new(&selection); self.display.flush_clients().unwrap(); ret } pub fn data_source_exists(&self) -> bool { self.state.selection.is_none() } pub fn create_data_offer(&mut self, data: Vec) { let Some(dev) = &self.state.data_device else { panic!("No data device created"); }; if let Some(selection) = self.state.selection.take() { selection.cancelled(); } let mimes: Vec<_> = data.iter().map(|m| m.mime_type.clone()).collect(); let offer = self .client .as_ref() .unwrap() .create_resource::<_, _, State>(&self.dh, 3, data) .unwrap(); dev.data_offer(&offer); for mime in mimes { offer.offer(mime); } dev.selection(Some(&offer)); self.display.flush_clients().unwrap(); } } pub struct PasteDataResolver { fds: Vec<(String, OwnedFd, OwnedFd)>, } impl PasteDataResolver { fn new(source: &WlDataSource) -> Self { let data: &Mutex = source.data().unwrap(); let data = data.lock().unwrap(); let mimes = &data.mimes; let fds = mimes .iter() .map(|mime| { let (rx, tx) = rustix::pipe::pipe().unwrap(); source.send(mime.clone(), tx.as_fd()); (mime.clone(), tx, rx) }) .collect(); PasteDataResolver { fds } } pub fn resolve(self) -> Vec { self.fds .into_iter() .map(|(mime, tx, rx)| { drop(tx); let mut data = Vec::new(); let mut file = std::fs::File::from(rx); file.read_to_end(&mut data).unwrap(); PasteData { mime_type: mime, data, } }) .collect() } } #[derive(Clone, Eq, PartialEq, Debug)] pub struct PasteData { pub mime_type: String, pub data: Vec, } simple_global_dispatch!(WlShm); simple_global_dispatch!(WlCompositor); simple_global_dispatch!(XdgWmBase); impl GlobalDispatch for State { fn bind( state: &mut Self, _: &DisplayHandle, _: &Client, resource: wayland_server::New, _: &(), data_init: &mut wayland_server::DataInit<'_, Self>, ) { state.data_device_man = Some(data_init.init(resource, ())); } } impl Dispatch> for State { fn request( _: &mut Self, _: &Client, _: &WlDataOffer, request: ::Request, data: &Vec, _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { match request { wl_data_offer::Request::Receive { mime_type, fd } => { let pos = data .iter() .position(|data| data.mime_type == mime_type) .expect("Invalid mime type: {mime_type}"); let mut stream = UnixStream::from(fd); stream.write_all(&data[pos].data).unwrap(); } other => todo!("unhandled request: {other:?}"), } } } impl Dispatch> for State { fn request( state: &mut Self, _: &Client, _: &WlDataSource, request: ::Request, data: &Mutex, _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { let mut data = data.lock().unwrap(); match request { wl_data_source::Request::Offer { mime_type } => { data.mimes.push(mime_type); } wl_data_source::Request::Destroy => { state.selection = None; } other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( state: &mut Self, _: &Client, _: &WlDataDevice, request: ::Request, _: &WlSeat, _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { match request { wl_data_device::Request::SetSelection { source, .. } => { state.selection = source; } wl_data_device::Request::Release => { state.data_device = None; } other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( state: &mut Self, _: &Client, _: &WlDataDeviceManager, request: ::Request, _: &(), _: &DisplayHandle, data_init: &mut wayland_server::DataInit<'_, Self>, ) { match request { wl_data_device_manager::Request::CreateDataSource { id } => { data_init.init(id, DataSourceData::default().into()); } wl_data_device_manager::Request::GetDataDevice { id, seat } => { state.data_device = Some(data_init.init(id, seat)); } other => todo!("unhandled request: {other:?}"), } } } impl GlobalDispatch for State { fn bind( _: &mut Self, _: &DisplayHandle, _: &Client, resource: wayland_server::New, _: &(), data_init: &mut wayland_server::DataInit<'_, Self>, ) { let seat = data_init.init(resource, ()); seat.capabilities(wl_seat::Capability::Pointer | wl_seat::Capability::Keyboard); } } impl Dispatch for State { fn request( state: &mut Self, _: &Client, _: &WlSeat, request: ::Request, _: &(), _: &DisplayHandle, data_init: &mut wayland_server::DataInit<'_, Self>, ) { match request { wl_seat::Request::GetPointer { id } => { state.pointer = Some(data_init.init(id, ())); } wl_seat::Request::GetKeyboard { id } => { state.keyboard = Some(data_init.init(id, ())); } wl_seat::Request::Release => {} other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( state: &mut Self, _: &Client, _: &WlPointer, request: ::Request, _: &(), _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { match request { wl_pointer::Request::SetCursor { surface, .. } => { if let Some(surface) = surface { let data = state .surfaces .get_mut(&SurfaceId(surface.id().protocol_id())) .unwrap(); assert!( data.role.replace(SurfaceRole::Cursor).is_none(), "Surface already had a role!" ); } } wl_pointer::Request::Release => { state.pointer.take(); } other => todo!("unhandled pointer request: {other:?}"), } } } impl Dispatch for State { fn request( _: &mut Self, _: &Client, _: &WlKeyboard, request: ::Request, _: &(), _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { match request { wl_keyboard::Request::Release => {} other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( _: &mut Self, _: &Client, _: &XdgPopup, request: ::Request, _: &SurfaceId, _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { match request { xdg_popup::Request::Destroy => {} other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( state: &mut Self, _: &wayland_server::Client, _: &XdgToplevel, request: ::Request, surface_id: &SurfaceId, _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { match request { xdg_toplevel::Request::SetMinSize { width, height } => { let data = state.surfaces.get_mut(surface_id).unwrap(); let Some(SurfaceRole::Toplevel(toplevel)) = &mut data.role else { unreachable!(); }; toplevel.min_size = Some(Vec2 { x: width, y: height, }); } xdg_toplevel::Request::SetMaxSize { width, height } => { let data = state.surfaces.get_mut(surface_id).unwrap(); let Some(SurfaceRole::Toplevel(toplevel)) = &mut data.role else { unreachable!(); }; toplevel.max_size = Some(Vec2 { x: width, y: height, }); } xdg_toplevel::Request::SetFullscreen { .. } => { let data = state.surfaces.get_mut(surface_id).unwrap(); let Some(SurfaceRole::Toplevel(toplevel)) = &mut data.role else { unreachable!(); }; toplevel.states.push(xdg_toplevel::State::Fullscreen); let states = toplevel.states.clone(); state.configure_toplevel(*surface_id, 100, 100, states); } xdg_toplevel::Request::UnsetFullscreen { .. } => { let data = state.surfaces.get_mut(surface_id).unwrap(); let Some(SurfaceRole::Toplevel(toplevel)) = &mut data.role else { unreachable!(); }; let Some(pos) = toplevel .states .iter() .copied() .position(|p| p == xdg_toplevel::State::Fullscreen) else { return; }; toplevel.states.swap_remove(pos); let states = toplevel.states.clone(); state.configure_toplevel(*surface_id, 100, 100, states); } xdg_toplevel::Request::Destroy => {} xdg_toplevel::Request::SetTitle { title } => { let data = state.surfaces.get_mut(surface_id).unwrap(); let Some(SurfaceRole::Toplevel(toplevel)) = &mut data.role else { unreachable!(); }; toplevel.title = title.into(); } xdg_toplevel::Request::SetAppId { app_id } => { let data = state.surfaces.get_mut(surface_id).unwrap(); let Some(SurfaceRole::Toplevel(toplevel)) = &mut data.role else { unreachable!(); }; toplevel.app_id = app_id.into(); } other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( state: &mut Self, client: &wayland_server::Client, resource: &XdgSurface, request: ::Request, surface_id: &SurfaceId, dh: &DisplayHandle, data_init: &mut wayland_server::DataInit<'_, Self>, ) { use wayland_protocols::xdg::shell::server::xdg_surface; match request { xdg_surface::Request::GetToplevel { id } => { let toplevel = data_init.init(id, *surface_id); let t = Toplevel { xdg: XdgSurfaceData::new(resource.clone()), toplevel, min_size: None, max_size: None, states: Vec::new(), closed: false, title: None, app_id: None, }; let data = state.surfaces.get_mut(surface_id).unwrap(); data.role = Some(SurfaceRole::Toplevel(t)); } xdg_surface::Request::GetPopup { id, parent, positioner, } => { let popup = data_init.init(id, *surface_id); let p = Popup { xdg: XdgSurfaceData::new(resource.clone()), popup, parent: parent.unwrap(), positioner_state: state.positioners [&PositionerId(positioner.id().protocol_id())] .clone(), }; let data = state.surfaces.get_mut(surface_id).unwrap(); data.role = Some(SurfaceRole::Popup(p)); } xdg_surface::Request::AckConfigure { serial } => { let data = state.surfaces.get_mut(surface_id).unwrap(); assert_eq!(data.xdg().last_configure_serial, serial); } xdg_surface::Request::Destroy => { let data = state.surfaces.get_mut(surface_id).unwrap(); let role_alive = data.role.is_none() || match data.role.as_ref().unwrap() { SurfaceRole::Toplevel(t) => t.toplevel.is_alive(), SurfaceRole::Popup(p) => p.popup.is_alive(), SurfaceRole::Cursor => false, }; if role_alive { client.kill( dh, ProtocolError { code: xdg_surface::Error::DefunctRoleObject.into(), object_id: resource.id().protocol_id(), object_interface: XdgSurface::interface().name.to_string(), message: "destroyed xdg surface before role".to_string(), }, ); } } other => todo!("unhandled request {other:?}"), } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Rect { pub size: Vec2, pub offset: Vec2, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PositionerState { pub size: Option, pub anchor_rect: Option, pub offset: Vec2, pub anchor: xdg_positioner::Anchor, pub gravity: xdg_positioner::Gravity, } impl Default for PositionerState { fn default() -> Self { Self { size: None, anchor_rect: None, offset: Vec2 { x: 0, y: 0 }, anchor: xdg_positioner::Anchor::None, gravity: xdg_positioner::Gravity::None, } } } impl Dispatch for State { fn request( state: &mut Self, _: &Client, resource: &XdgPositioner, request: ::Request, _: &(), _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { let hash_map::Entry::Occupied(mut data) = state .positioners .entry(PositionerId(resource.id().protocol_id())) else { unreachable!(); }; match request { xdg_positioner::Request::SetSize { width, height } => { data.get_mut().size = Some(Vec2 { x: width, y: height, }); } xdg_positioner::Request::SetAnchorRect { x, y, width, height, } => { data.get_mut().anchor_rect = Some(Rect { size: Vec2 { x: width, y: height, }, offset: Vec2 { x, y }, }); } xdg_positioner::Request::SetOffset { x, y } => { data.get_mut().offset = Vec2 { x, y }; } xdg_positioner::Request::SetAnchor { anchor } => { data.get_mut().anchor = anchor.into_result().unwrap(); } xdg_positioner::Request::SetGravity { gravity } => { data.get_mut().gravity = gravity.into_result().unwrap(); } xdg_positioner::Request::Destroy => { data.remove(); } other => todo!("unhandled positioner request {other:?}"), } } } impl Dispatch for State { fn request( state: &mut Self, client: &wayland_server::Client, _: &XdgWmBase, request: ::Request, _: &(), dhandle: &DisplayHandle, data_init: &mut wayland_server::DataInit<'_, Self>, ) { match request { xdg_wm_base::Request::GetXdgSurface { id, surface } => { let surface_id = SurfaceId(surface.id().protocol_id()); let data = state.surfaces.get(&surface_id).unwrap(); if data.buffer.is_some() { client.kill( dhandle, ProtocolError { code: xdg_wm_base::Error::InvalidSurfaceState.into(), object_id: surface_id.0, object_interface: XdgWmBase::interface().name.to_string(), message: "Buffer already attached to surface".to_string(), }, ); return; } data_init.init(id, surface_id); } xdg_wm_base::Request::CreatePositioner { id } => { let pos = data_init.init(id, ()); state.positioners.insert( PositionerId(pos.id().protocol_id()), PositionerState::default(), ); } other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( _: &mut Self, _: &wayland_server::Client, _: &WlShm, request: ::Request, _: &(), _: &DisplayHandle, data_init: &mut wayland_server::DataInit<'_, Self>, ) { match request { proto::wl_shm::Request::CreatePool { id, .. } => { data_init.init(id, ()); } _ => unreachable!(), } } } impl Dispatch for State { fn request( state: &mut Self, _: &wayland_server::Client, _: &WlShmPool, request: ::Request, _: &(), _: &DisplayHandle, data_init: &mut wayland_server::DataInit<'_, Self>, ) { use proto::wl_shm_pool::Request::*; match request { CreateBuffer { id, .. } => { let buf = data_init.init(id, ()); state.buffers.insert(buf); } Destroy => {} other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( state: &mut Self, _: &wayland_server::Client, resource: &WlBuffer, request: ::Request, _: &(), _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { match request { proto::wl_buffer::Request::Destroy => { state.buffers.remove(resource); } _ => unreachable!(), } } } impl Dispatch for State { fn request( state: &mut Self, _: &wayland_server::Client, _: &WlCompositor, request: ::Request, _: &(), _: &DisplayHandle, data_init: &mut wayland_server::DataInit<'_, Self>, ) { match request { proto::wl_compositor::Request::CreateSurface { id } => { let surface = data_init.init(id, ()); let id = surface.id().protocol_id(); state.surfaces.insert( SurfaceId(id), SurfaceData { surface, buffer: None, last_damage: None, role: None, last_enter_serial: None, }, ); state.last_surface_id = Some(SurfaceId(id)); } _ => unreachable!(), } } } impl Dispatch for State { fn request( state: &mut Self, _: &wayland_server::Client, resource: &WlSurface, request: ::Request, _: &(), _: &DisplayHandle, data_init: &mut wayland_server::DataInit<'_, Self>, ) { use proto::wl_surface::Request::*; let data = state .surfaces .get_mut(&SurfaceId(resource.id().protocol_id())) .unwrap_or_else(|| panic!("{:?} missing from surface map", resource)); match request { Attach { buffer, .. } => { data.buffer = buffer; } Frame { callback } => { // XXX: calling done immediately will cause wayland_backend to panic, // report upstream state.callbacks.push(data_init.init(callback, ())); } DamageBuffer { x, y, width, height, } => { data.last_damage = Some(BufferDamage { x, y, width, height, }); } Commit => {} Destroy => { state .surfaces .remove(&SurfaceId(resource.id().protocol_id())); } SetInputRegion { .. } => {} other => todo!("unhandled request {other:?}"), } } } impl Dispatch for State { fn request( _: &mut Self, _: &wayland_server::Client, _: &WlCallback, _: ::Request, _: &(), _: &DisplayHandle, _: &mut wayland_server::DataInit<'_, Self>, ) { unreachable!() } }