use crate::client::{Client, ClientError}; use crate::ifs::ipc::wl_data_source::WlDataSource; use crate::ifs::ipc::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1; use crate::ifs::wl_buffer::WlBuffer; use crate::ifs::wl_display::WlDisplay; use crate::ifs::wl_output::WlOutput; use crate::ifs::wl_region::WlRegion; use crate::ifs::wl_registry::WlRegistry; use crate::ifs::wl_seat::WlSeat; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; use crate::ifs::wl_surface::xdg_surface::XdgSurface; use crate::ifs::wl_surface::WlSurface; use crate::ifs::xdg_positioner::XdgPositioner; use crate::ifs::xdg_wm_base::XdgWmBase; use crate::object::{Object, ObjectId}; use crate::tree::Node; use crate::utils::clonecell::CloneCell; use crate::utils::copyhashmap::{CopyHashMap, Locked}; use crate::wire::{ WlBufferId, WlDataSourceId, WlOutputId, WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId, XdgPositionerId, XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwpPrimarySelectionSourceV1Id, }; use std::cell::RefCell; use std::mem; use std::ops::DerefMut; use std::rc::Rc; pub struct Objects { pub display: CloneCell>>, registry: CopyHashMap>, registries: CopyHashMap>, pub outputs: CopyHashMap>, pub surfaces: CopyHashMap>, pub xdg_surfaces: CopyHashMap>, pub xdg_toplevel: CopyHashMap>, pub wl_data_source: CopyHashMap>, pub zwp_primary_selection_source: CopyHashMap>, pub xdg_positioners: CopyHashMap>, pub regions: CopyHashMap>, pub buffers: CopyHashMap>, pub xdg_wm_bases: CopyHashMap>, pub seats: CopyHashMap>, ids: RefCell>, } pub const MIN_SERVER_ID: u32 = 0xff000000; const SEG_SIZE: usize = 8 * mem::size_of::(); impl Objects { pub fn new() -> Self { Self { display: CloneCell::new(None), registry: Default::default(), registries: Default::default(), outputs: Default::default(), surfaces: Default::default(), xdg_surfaces: Default::default(), xdg_toplevel: Default::default(), wl_data_source: Default::default(), zwp_primary_selection_source: Default::default(), xdg_positioners: Default::default(), regions: Default::default(), buffers: Default::default(), xdg_wm_bases: Default::default(), seats: Default::default(), ids: RefCell::new(vec![]), } } pub fn destroy(&self) { { let mut toplevel = self.xdg_toplevel.lock(); for obj in toplevel.values_mut() { obj.destroy_node(true); } mem::take(toplevel.deref_mut()); } { let mut registry = self.registry.lock(); for obj in registry.values_mut() { obj.break_loops(); } mem::take(registry.deref_mut()); } self.display.set(None); self.registries.clear(); self.outputs.clear(); self.surfaces.clear(); self.xdg_surfaces.clear(); self.wl_data_source.clear(); self.zwp_primary_selection_source.clear(); self.xdg_positioners.clear(); self.regions.clear(); self.buffers.clear(); self.xdg_wm_bases.clear(); self.seats.clear(); } pub fn id(&self, client_data: &Client) -> Result where ObjectId: Into, { const MAX_ID_OFFSET: u32 = u32::MAX - MIN_SERVER_ID; let offset = self.id_offset(); if offset > MAX_ID_OFFSET { log::error!( "Client {} caused the server to allocate more than 0x{:x} ids", client_data.id, MAX_ID_OFFSET + 1 ); return Err(ClientError::TooManyIds); } Ok(ObjectId::from_raw(MIN_SERVER_ID + offset).into()) } pub fn get_obj(&self, id: ObjectId) -> Result, ClientError> { match self.registry.get(&id) { Some(o) => Ok(o), _ => Err(ClientError::UnknownId), } } pub fn add_server_object(&self, obj: Rc) { let id = obj.id(); assert!(id.raw() >= MIN_SERVER_ID); assert!(!self.registry.contains(&id)); self.registry.set(id, obj.clone()); } pub fn add_client_object(&self, obj: Rc) -> Result<(), ClientError> { let id = obj.id(); let res = (|| { if id.raw() == 0 || id.raw() >= MIN_SERVER_ID { return Err(ClientError::ClientIdOutOfBounds); } if self.registry.contains(&id) { return Err(ClientError::IdAlreadyInUse); } self.registry.set(id, obj.clone()); Ok(()) })(); if let Err(e) = res { return Err(ClientError::AddObjectError(id, Box::new(e))); } Ok(()) } pub fn remove_obj(&self, client_data: &Rc, id: ObjectId) -> Result<(), ClientError> { let _obj = match self.registry.remove(&id) { Some(o) => o, _ => return Err(ClientError::UnknownId), }; if id.raw() >= MIN_SERVER_ID { let offset = (id.raw() - MIN_SERVER_ID) as usize; let pos = offset / SEG_SIZE; let seg_offset = offset % SEG_SIZE; let mut ids = self.ids.borrow_mut(); if ids.len() <= pos { return Err(ClientError::ServerIdOutOfBounds); } ids[pos] |= 1 << seg_offset; } else { client_data.display()?.send_delete_id(id); } Ok(()) } pub fn registries(&self) -> Locked> { self.registries.lock() } fn id_offset(&self) -> u32 { let mut ids = self.ids.borrow_mut(); for (pos, seg) in ids.iter_mut().enumerate() { if *seg != 0 { let offset = seg.trailing_zeros(); *seg &= !(1 << offset); return (pos * SEG_SIZE) as u32 + offset; } } ids.push(!1); ((ids.len() - 1) * SEG_SIZE) as u32 } }