1
0
Fork 0
forked from wry/wry
wry/src/globals.rs
2022-07-21 20:16:22 +02:00

280 lines
8.5 KiB
Rust

use {
crate::{
backend::Backend,
client::Client,
ifs::{
ext_session_lock_manager_v1::ExtSessionLockManagerV1Global,
ipc::{
wl_data_device_manager::WlDataDeviceManagerGlobal,
zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1Global,
},
jay_compositor::JayCompositorGlobal,
org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManagerGlobal,
wl_compositor::WlCompositorGlobal,
wl_output::WlOutputGlobal,
wl_registry::WlRegistry,
wl_seat::{
zwp_pointer_constraints_v1::ZwpPointerConstraintsV1Global,
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1Global, WlSeatGlobal,
},
wl_shm::WlShmGlobal,
wl_subcompositor::WlSubcompositorGlobal,
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
wp_presentation::WpPresentationGlobal,
wp_viewporter::WpViewporterGlobal,
xdg_wm_base::XdgWmBaseGlobal,
zwlr_layer_shell_v1::ZwlrLayerShellV1Global,
zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1Global,
zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1Global,
zxdg_decoration_manager_v1::ZxdgDecorationManagerV1Global,
zxdg_output_manager_v1::ZxdgOutputManagerV1Global,
},
object::{Interface, ObjectId},
state::State,
utils::{
copyhashmap::{CopyHashMap, Locked},
numcell::NumCell,
},
},
std::{
error::Error,
fmt::{Display, Formatter},
rc::Rc,
},
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<dyn Error>,
}
#[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<Self>,
client: &'a Rc<Client>,
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<u32>,
registry: CopyHashMap<GlobalName, Rc<dyn Global>>,
pub outputs: CopyHashMap<GlobalName, Rc<WlOutputGlobal>>,
pub seats: CopyHashMap<GlobalName, Rc<WlSeatGlobal>>,
}
impl Globals {
pub fn new() -> Self {
let slf = Self {
next_name: NumCell::new(1),
registry: CopyHashMap::new(),
outputs: Default::default(),
seats: Default::default(),
};
slf.add_singletons();
slf
}
pub fn clear(&self) {
self.registry.clear();
self.outputs.clear();
self.seats.clear();
}
fn add_singletons(&self) {
macro_rules! add_singleton {
($name:ident) => {
self.add_global_no_broadcast(&Rc::new($name::new(self.name())));
};
}
add_singleton!(WlCompositorGlobal);
add_singleton!(WlShmGlobal);
add_singleton!(WlSubcompositorGlobal);
add_singleton!(XdgWmBaseGlobal);
add_singleton!(WlDataDeviceManagerGlobal);
add_singleton!(ZxdgDecorationManagerV1Global);
add_singleton!(OrgKdeKwinServerDecorationManagerGlobal);
add_singleton!(ZwpPrimarySelectionDeviceManagerV1Global);
add_singleton!(ZwlrLayerShellV1Global);
add_singleton!(ZxdgOutputManagerV1Global);
add_singleton!(JayCompositorGlobal);
add_singleton!(ZwlrScreencopyManagerV1Global);
add_singleton!(ZwpRelativePointerManagerV1Global);
add_singleton!(ExtSessionLockManagerV1Global);
add_singleton!(WpViewporterGlobal);
add_singleton!(WpFractionalScaleManagerV1Global);
add_singleton!(ZwpPointerConstraintsV1Global);
}
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
macro_rules! add_singleton {
($name:ident) => {
self.add_global_no_broadcast(&Rc::new($name::new(self.name())));
};
}
if backend.supports_idle() {
add_singleton!(ZwpIdleInhibitManagerV1Global);
}
if backend.supports_presentation_feedback() {
add_singleton!(WpPresentationGlobal);
}
}
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<dyn Global>) {
self.insert_no_broadcast_(&global);
}
fn insert_no_broadcast_<'a>(&'a self, global: &Rc<dyn Global>) {
self.registry.set(global.name(), global.clone());
}
fn insert(&self, state: &State, global: Rc<dyn Global>) {
self.insert_no_broadcast_(&global);
self.broadcast(state, global.secure(), |r| r.send_global(&global));
}
pub fn get(
&self,
name: GlobalName,
allow_secure: bool,
) -> Result<Rc<dyn Global>, GlobalsError> {
let global = self.take(name, false)?;
if global.secure() && !allow_secure {
return Err(GlobalsError::GlobalDoesNotExist(name));
}
Ok(global)
}
pub fn remove<T: WaylandGlobal>(&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) -> Locked<GlobalName, Rc<WlSeatGlobal>> {
self.seats.lock()
}
pub fn notify_all(&self, registry: &Rc<WlRegistry>) {
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<F: Fn(&Rc<WlRegistry>)>(&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<Rc<dyn Global>, 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<Rc<WlOutputGlobal>, GlobalsError> {
match self.outputs.get(&output) {
Some(o) => Ok(o),
_ => Err(GlobalsError::OutputDoesNotExist(output)),
}
}
pub fn add_global<T: WaylandGlobal>(&self, state: &State, global: &Rc<T>) {
global.clone().add(self);
self.insert(state, global.clone())
}
pub fn add_global_no_broadcast<T: WaylandGlobal>(&self, global: &Rc<T>) {
global.clone().add(self);
self.insert_no_broadcast(global.clone());
}
}
pub trait WaylandGlobal: Global + 'static {
fn add(self: Rc<Self>, globals: &Globals) {
let _ = globals;
}
fn remove(&self, globals: &Globals) {
let _ = globals;
}
}