From c27bf4d597294cee0d196c4fb4356e34659fa0dc Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 25 Apr 2024 19:52:26 +0200 Subject: [PATCH] wayland: allow binding to removed outputs --- src/globals.rs | 21 +++++++++- src/ifs/wl_output.rs | 6 ++- src/ifs/wl_output/removed_output.rs | 63 +++++++++++++++++++++++++++++ src/state.rs | 4 +- 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/ifs/wl_output/removed_output.rs diff --git a/src/globals.rs b/src/globals.rs index e73fe0bf..41aeb925 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -127,6 +127,7 @@ pub trait Global: GlobalBase { pub struct Globals { next_name: NumCell, registry: CopyHashMap>, + removed: CopyHashMap>, pub outputs: CopyHashMap>, pub seats: CopyHashMap>, } @@ -136,6 +137,7 @@ impl Globals { let slf = Self { next_name: NumCell::new(1), registry: CopyHashMap::new(), + removed: CopyHashMap::new(), outputs: Default::default(), seats: Default::default(), }; @@ -241,9 +243,17 @@ impl Globals { Ok(global) } - pub fn remove(&self, state: &State, global: &T) -> Result<(), GlobalsError> { + pub fn remove( + &self, + state: &State, + global: &T, + ) -> Result<(), GlobalsError> { let _global = self.take(global.name(), true)?; global.remove(self); + let replacement = global.create_replacement(); + assert_eq!(global.name(), replacement.name()); + assert_eq!(global.interface().0, replacement.interface().0); + self.removed.set(global.name(), replacement); self.broadcast(state, global.required_caps(), global.xwayland_only(), |r| { r.send_global_remove(global.name()) }); @@ -295,7 +305,10 @@ impl Globals { let res = if remove { self.registry.remove(&name) } else { - self.registry.get(&name) + match self.registry.get(&name) { + Some(res) => Some(res), + _ => self.removed.get(&name), + } }; match res { Some(g) => Ok(g), @@ -330,3 +343,7 @@ pub trait WaylandGlobal: Global + 'static { let _ = globals; } } + +pub trait RemovableWaylandGlobal: WaylandGlobal { + fn create_replacement(&self) -> Rc; +} diff --git a/src/ifs/wl_output.rs b/src/ifs/wl_output.rs index 52cee8cd..0e9c5ea8 100644 --- a/src/ifs/wl_output.rs +++ b/src/ifs/wl_output.rs @@ -1,3 +1,5 @@ +mod removed_output; + use { crate::{ backend, @@ -229,13 +231,15 @@ impl WlOutputGlobal { global_base!(WlOutputGlobal, WlOutput, WlOutputError); +const OUTPUT_VERSION: u32 = 4; + impl Global for WlOutputGlobal { fn singleton(&self) -> bool { false } fn version(&self) -> u32 { - 4 + OUTPUT_VERSION } fn break_loops(&self) { diff --git a/src/ifs/wl_output/removed_output.rs b/src/ifs/wl_output/removed_output.rs new file mode 100644 index 00000000..67072aec --- /dev/null +++ b/src/ifs/wl_output/removed_output.rs @@ -0,0 +1,63 @@ +use { + crate::{ + client::{Client, ClientError}, + globals::{Global, GlobalName, RemovableWaylandGlobal}, + ifs::wl_output::{WlOutput, WlOutputGlobal, OUTPUT_VERSION}, + object::Version, + wire::WlOutputId, + }, + std::rc::Rc, + thiserror::Error, +}; + +struct RemovedOutputGlobal { + name: GlobalName, +} + +impl RemovedOutputGlobal { + fn bind_( + self: Rc, + id: WlOutputId, + client: &Rc, + version: Version, + ) -> Result<(), RemovedOutputError> { + let obj = Rc::new(WlOutput { + global: Default::default(), + id, + xdg_outputs: Default::default(), + client: client.clone(), + version, + tracker: Default::default(), + }); + track!(client, obj); + client.add_client_obj(&obj)?; + Ok(()) + } +} + +global_base!(RemovedOutputGlobal, WlOutput, RemovedOutputError); + +impl Global for RemovedOutputGlobal { + fn singleton(&self) -> bool { + false + } + + fn version(&self) -> u32 { + OUTPUT_VERSION + } +} + +simple_add_global!(RemovedOutputGlobal); + +impl RemovableWaylandGlobal for WlOutputGlobal { + fn create_replacement(&self) -> Rc { + Rc::new(RemovedOutputGlobal { name: self.name }) + } +} + +#[derive(Debug, Error)] +enum RemovedOutputError { + #[error(transparent)] + ClientError(Box), +} +efrom!(RemovedOutputError, ClientError); diff --git a/src/state.rs b/src/state.rs index fe49b79e..be8797f7 100644 --- a/src/state.rs +++ b/src/state.rs @@ -22,7 +22,7 @@ use { SyncFile, }, gfx_apis::create_gfx_context, - globals::{Globals, GlobalsError, WaylandGlobal}, + globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal}, ifs::{ ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1, ext_session_lock_v1::ExtSessionLockV1, @@ -511,7 +511,7 @@ impl State { self.globals.add_global(self, global) } - pub fn remove_global(&self, global: &T) -> Result<(), GlobalsError> { + pub fn remove_global(&self, global: &T) -> Result<(), GlobalsError> { self.globals.remove(self, global) }