use { crate::{ globals::GlobalName, ifs::wl_seat::WlSeatGlobal, it::{ test_error::TestError, test_ifs::{ test_compositor::TestCompositor, test_content_type_manager::TestContentTypeManager, test_cursor_shape_manager::TestCursorShapeManager, test_data_control_manager::TestDataControlManager, test_data_device_manager::TestDataDeviceManager, test_dmabuf::TestDmabuf, test_ext_foreign_toplevel_list::TestExtForeignToplevelList, test_jay_compositor::TestJayCompositor, test_shm::TestShm, test_single_pixel_buffer_manager::TestSinglePixelBufferManager, test_subcompositor::TestSubcompositor, test_syncobj_manager::TestSyncobjManager, test_toplevel_drag_manager::TestToplevelDragManager, test_viewporter::TestViewporter, test_xdg_activation::TestXdgActivation, test_xdg_base::TestXdgWmBase, }, test_object::TestObject, test_transport::TestTransport, testrun::ParseFull, }, utils::{buffd::MsgParser, clonecell::CloneCell, copyhashmap::CopyHashMap}, wire::{wl_registry::*, WlRegistryId, WlSeat}, }, std::rc::Rc, }; pub struct TestGlobal { pub name: u32, pub interface: String, pub version: u32, } pub struct TestRegistrySingletons { pub jay_compositor: u32, pub wl_compositor: u32, pub wl_subcompositor: u32, pub wl_shm: u32, pub xdg_wm_base: u32, pub wp_single_pixel_buffer_manager_v1: u32, pub wp_viewporter: u32, pub xdg_activation_v1: u32, pub ext_foreign_toplevel_list_v1: u32, pub wl_data_device_manager: u32, pub wp_cursor_shape_manager_v1: u32, pub wp_linux_drm_syncobj_manager_v1: u32, pub wp_content_type_manager_v1: u32, pub zwlr_data_control_manager_v1: u32, pub zwp_linux_dmabuf_v1: u32, pub xdg_toplevel_drag_manager_v1: u32, } pub struct TestRegistry { pub id: WlRegistryId, pub tran: Rc, pub globals: CopyHashMap>, pub singletons: CloneCell>>, pub jay_compositor: CloneCell>>, pub compositor: CloneCell>>, pub subcompositor: CloneCell>>, pub shm: CloneCell>>, pub spbm: CloneCell>>, pub viewporter: CloneCell>>, pub xdg: CloneCell>>, pub activation: CloneCell>>, pub foreign_toplevel_list: CloneCell>>, pub data_device_manager: CloneCell>>, pub cursor_shape_manager: CloneCell>>, pub syncobj_manager: CloneCell>>, pub content_type_manager: CloneCell>>, pub data_control_manager: CloneCell>>, pub dmabuf: CloneCell>>, pub drag_manager: CloneCell>>, pub seats: CopyHashMap>, } macro_rules! singleton { ($field:expr) => { if let Some(s) = $field.get() { return Ok(s); } }; } macro_rules! create_singleton { ($fn:ident, $field:ident, $name:ident, $ver:expr, $ty:ident) => { pub async fn $fn(&self) -> Result, TestError> { singleton!(self.$field); let singletons = self.get_singletons().await?; singleton!(self.$field); let jc = Rc::new($ty::new(&self.tran)); self.bind(&jc, singletons.$name, $ver)?; self.$field.set(Some(jc.clone())); Ok(jc) } }; } impl TestRegistry { pub async fn get_singletons(&self) -> Result, TestError> { singleton!(self.singletons); self.tran.sync().await; singleton!(self.singletons); macro_rules! singleton { ($($name:ident,)*) => {{ $( let mut $name = u32::MAX; )* for global in self.globals.lock().values() { match global.interface.as_str() { $( stringify!($name) => $name = global.name, )* _ => {} } } Rc::new(TestRegistrySingletons { $( $name, )* }) }} } let singletons = singleton! { jay_compositor, wl_compositor, wl_subcompositor, wl_shm, xdg_wm_base, wp_single_pixel_buffer_manager_v1, wp_viewporter, xdg_activation_v1, ext_foreign_toplevel_list_v1, wl_data_device_manager, wp_cursor_shape_manager_v1, wp_linux_drm_syncobj_manager_v1, wp_content_type_manager_v1, zwlr_data_control_manager_v1, zwp_linux_dmabuf_v1, xdg_toplevel_drag_manager_v1, }; self.singletons.set(Some(singletons.clone())); Ok(singletons) } create_singleton!( get_jay_compositor, jay_compositor, jay_compositor, 1, TestJayCompositor ); create_singleton!(get_compositor, compositor, wl_compositor, 6, TestCompositor); create_singleton!( get_subcompositor, subcompositor, wl_subcompositor, 1, TestSubcompositor ); create_singleton!(get_shm, shm, wl_shm, 1, TestShm); create_singleton!( get_spbm, spbm, wp_single_pixel_buffer_manager_v1, 1, TestSinglePixelBufferManager ); create_singleton!(get_viewporter, viewporter, wp_viewporter, 1, TestViewporter); create_singleton!( get_activation, activation, xdg_activation_v1, 1, TestXdgActivation ); create_singleton!(get_xdg, xdg, xdg_wm_base, 6, TestXdgWmBase); create_singleton!( get_foreign_toplevel_list, foreign_toplevel_list, ext_foreign_toplevel_list_v1, 1, TestExtForeignToplevelList ); create_singleton!( get_data_device_manager, data_device_manager, wl_data_device_manager, 3, TestDataDeviceManager ); create_singleton!( get_cursor_shape_manager, cursor_shape_manager, wp_cursor_shape_manager_v1, 1, TestCursorShapeManager ); create_singleton!( get_syncobj_manager, syncobj_manager, wp_linux_drm_syncobj_manager_v1, 1, TestSyncobjManager ); create_singleton!( get_content_type_manager, content_type_manager, wp_content_type_manager_v1, 1, TestContentTypeManager ); create_singleton!( get_data_control_manager, data_control_manager, zwlr_data_control_manager_v1, 2, TestDataControlManager ); create_singleton!(get_dmabuf, dmabuf, zwp_linux_dmabuf_v1, 5, TestDmabuf); create_singleton!( get_drag_manager, drag_manager, xdg_toplevel_drag_manager_v1, 1, TestToplevelDragManager ); pub fn bind( &self, obj: &Rc, name: u32, version: u32, ) -> Result<(), TestError> { self.tran.send(Bind { self_id: self.id, name, interface: obj.interface().name(), version, id: obj.id(), })?; self.tran.add_obj(obj.clone())?; Ok(()) } fn handle_global(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> { let ev = Global::parse_full(parser)?; let global = Rc::new(TestGlobal { name: ev.name, interface: ev.interface.to_string(), version: ev.version, }); let prev = self.globals.set(ev.name, global.clone()); let name = GlobalName::from_raw(ev.name); if ev.interface == WlSeat.name() { let seat = match self.tran.run.state.globals.seats.get(&name) { Some(s) => s, _ => bail!("Compositor sent seat global but seat does not exist"), }; self.seats.set(GlobalName::from_raw(ev.name), seat); } if prev.is_some() { bail!("Compositor sent global {} multiple times", ev.name); } Ok(()) } fn handle_global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> { let ev = GlobalRemove::parse_full(parser)?; let global = match self.globals.remove(&ev.name) { Some(g) => g, _ => bail!( "Compositor sent global_remove for {} which does not exist", ev.name ), }; let name = GlobalName::from_raw(ev.name); if global.interface == WlSeat.name() { self.seats.remove(&name); } Ok(()) } } test_object! { TestRegistry, WlRegistry; GLOBAL => handle_global, GLOBAL_REMOVE => handle_global_remove, } impl TestObject for TestRegistry {}