use crate::client::Client; use crate::ifs::ipc::wl_data_device_manager::WlDataDeviceManagerGlobal; use crate::ifs::ipc::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1Global; use crate::ifs::jay_compositor::JayCompositorGlobal; use crate::ifs::org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManagerGlobal; use crate::ifs::wl_compositor::WlCompositorGlobal; use crate::ifs::wl_drm::WlDrmGlobal; use crate::ifs::wl_output::WlOutputGlobal; use crate::ifs::wl_registry::WlRegistry; use crate::ifs::wl_seat::WlSeatGlobal; use crate::ifs::wl_shm::WlShmGlobal; use crate::ifs::wl_subcompositor::WlSubcompositorGlobal; use crate::ifs::xdg_wm_base::XdgWmBaseGlobal; use crate::ifs::zwlr_layer_shell_v1::ZwlrLayerShellV1Global; use crate::ifs::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global; use crate::ifs::zxdg_decoration_manager_v1::ZxdgDecorationManagerV1Global; use crate::ifs::zxdg_output_manager_v1::ZxdgOutputManagerV1Global; use crate::object::{Interface, ObjectId}; use crate::state::State; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::numcell::NumCell; use ahash::AHashMap; use std::cell::RefMut; use std::error::Error; use std::fmt::{Display, Formatter}; use std::rc::Rc; use thiserror::Error; #[derive(Debug, Error)] pub enum GlobalsError { #[error("The requested global {0} does not exist")] GlobalDoesNotExist(GlobalName), #[error("The output with id {0} does not exist")] OutputDoesNotExist(GlobalName), #[error(transparent)] GlobalError(GlobalError), } #[derive(Debug, Error)] #[error("An error occurred in a `{}` global", .interface.name())] pub struct GlobalError { pub interface: Interface, #[source] pub error: Box, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct GlobalName(u32); impl GlobalName { pub fn from_raw(id: u32) -> Self { Self(id) } pub fn raw(self) -> u32 { self.0 } } impl Display for GlobalName { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { Display::fmt(&self.0, f) } } pub trait GlobalBase { fn name(&self) -> GlobalName; fn bind<'a>( self: Rc, client: &'a Rc, id: ObjectId, version: u32, ) -> Result<(), GlobalsError>; fn interface(&self) -> Interface; } pub trait Global: GlobalBase { fn singleton(&self) -> bool; fn version(&self) -> u32; fn break_loops(&self) {} fn secure(&self) -> bool { false } } pub struct Globals { next_name: NumCell, registry: CopyHashMap>, pub outputs: CopyHashMap>, pub seats: CopyHashMap>, } impl Globals { pub fn new() -> Self { let slf = Self { next_name: NumCell::new(1), registry: CopyHashMap::new(), outputs: Default::default(), seats: Default::default(), }; macro_rules! add_singleton { ($name:ident) => { slf.add_global_no_broadcast(&Rc::new($name::new(slf.name()))); }; } add_singleton!(WlCompositorGlobal); add_singleton!(WlShmGlobal); add_singleton!(WlSubcompositorGlobal); add_singleton!(XdgWmBaseGlobal); add_singleton!(WlDataDeviceManagerGlobal); add_singleton!(ZwpLinuxDmabufV1Global); add_singleton!(WlDrmGlobal); add_singleton!(ZxdgDecorationManagerV1Global); add_singleton!(OrgKdeKwinServerDecorationManagerGlobal); add_singleton!(ZwpPrimarySelectionDeviceManagerV1Global); add_singleton!(ZwlrLayerShellV1Global); add_singleton!(ZxdgOutputManagerV1Global); add_singleton!(JayCompositorGlobal); slf } pub fn name(&self) -> GlobalName { let id = self.next_name.fetch_add(1); if id == 0 { panic!("Global names overflowed"); } GlobalName(id) } fn insert_no_broadcast<'a>(&'a self, global: Rc) { self.insert_no_broadcast_(&global); } fn insert_no_broadcast_<'a>(&'a self, global: &Rc) { self.registry.set(global.name(), global.clone()); } fn insert(&self, state: &State, global: Rc) { self.insert_no_broadcast_(&global); self.broadcast(state, global.secure(), |r| r.send_global(&global)); } pub fn get(&self, name: GlobalName) -> Result, GlobalsError> { self.take(name, false) } pub fn remove(&self, state: &State, global: &T) -> Result<(), GlobalsError> { let _global = self.take(global.name(), true)?; global.remove(self); self.broadcast(state, global.secure(), |r| { r.send_global_remove(global.name()) }); Ok(()) } pub fn lock_seats(&self) -> RefMut>> { self.seats.lock() } pub fn notify_all(&self, registry: &Rc) { let secure = registry.client.secure; let globals = self.registry.lock(); macro_rules! emit { ($singleton:expr) => { for global in globals.values() { if secure || !global.secure() { if global.singleton() == $singleton { registry.send_global(global); } } } }; } emit!(true); emit!(false); } fn broadcast)>(&self, state: &State, secure: bool, f: F) { state.clients.broadcast(secure, |c| { let registries = c.lock_registries(); for registry in registries.values() { f(registry); } c.flush(); }); } fn take(&self, name: GlobalName, remove: bool) -> Result, GlobalsError> { let res = if remove { self.registry.remove(&name) } else { self.registry.get(&name) }; match res { Some(g) => Ok(g), None => Err(GlobalsError::GlobalDoesNotExist(name)), } } #[allow(dead_code)] pub fn get_output(&self, output: GlobalName) -> Result, GlobalsError> { match self.outputs.get(&output) { Some(o) => Ok(o), _ => Err(GlobalsError::OutputDoesNotExist(output)), } } pub fn add_global(&self, state: &State, global: &Rc) { global.clone().add(self); self.insert(state, global.clone()) } pub fn add_global_no_broadcast(&self, global: &Rc) { global.clone().add(self); self.insert_no_broadcast(global.clone()); } } pub trait WaylandGlobal: Global + 'static { fn add(self: Rc, globals: &Globals) { let _ = globals; } fn remove(&self, globals: &Globals) { let _ = globals; } }