From 1570ba6b58bce87ce9ab57b30b267eafadfd3bee Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 5 Mar 2026 15:59:59 +0100 Subject: [PATCH] globals: send to old registries when exposed changes --- src/config/handler.rs | 6 ++--- src/globals.rs | 45 ++++++++++++++++++++++++++------- src/ifs/jay_color_management.rs | 3 +-- src/ifs/wl_registry.rs | 27 +++++++++++++++----- src/state.rs | 21 +++++++++++++++ 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/config/handler.rs b/src/config/handler.rs index 5208def1..4ff91fe0 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -1155,11 +1155,11 @@ impl ConfigProxyHandler { } fn handle_set_explicit_sync_enabled(&self, enabled: bool) { - self.state.explicit_sync_enabled.set(enabled); + self.state.set_explicit_sync_enabled(enabled); } fn handle_set_color_management_enabled(&self, enabled: bool) { - self.state.color_management_enabled.set(enabled); + self.state.set_color_management_enabled(enabled); } fn handle_get_socket_path(&self) { @@ -2366,7 +2366,7 @@ impl ConfigProxyHandler { } fn handle_set_middle_click_paste_enabled(&self, enabled: bool) { - self.state.enable_primary_selection.set(enabled); + self.state.set_primary_selection_enabled(enabled); } fn handle_seat_create_mark(&self, seat: Seat, kc: Option) -> Result<(), CphError> { diff --git a/src/globals.rs b/src/globals.rs index be9538d2..aabb986c 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -80,6 +80,7 @@ use { numcell::NumCell, }, }, + arrayvec::ArrayVec, linearize::{Linearize, StaticMap}, std::{ error::Error, @@ -150,6 +151,12 @@ pub trait Global: GlobalBase { let _ = state; true } + fn permitted(&self, caps: ClientCaps, xwayland: bool) -> bool { + caps.contains(self.required_caps()) && (xwayland || !self.xwayland_only()) + } + fn not_permitted(&self, caps: ClientCaps, xwayland: bool) -> bool { + !self.permitted(caps, xwayland) + } } macro_rules! singletons { @@ -248,7 +255,7 @@ pub struct Globals { removed: CopyHashMap>, pub outputs: CopyHashMap>, pub seats: CopyHashMap>, - pub singletons: StaticMap, + singletons: StaticMap, } impl Globals { @@ -290,7 +297,7 @@ impl Globals { fn insert(&self, state: &State, global: Rc) { self.insert_no_broadcast_(&global); self.broadcast(state, global.required_caps(), global.xwayland_only(), |r| { - r.send_global(&global) + r.handle_global(&global) }); } @@ -301,9 +308,7 @@ impl Globals { allow_xwayland_only: bool, ) -> Result, GlobalsError> { let global = self.take(name, false)?; - if client_caps.not_contains(global.required_caps()) - || (global.xwayland_only() && !allow_xwayland_only) - { + if global.not_permitted(client_caps, allow_xwayland_only) { return Err(GlobalsError::GlobalDoesNotExist(name)); } Ok(global) @@ -321,7 +326,7 @@ impl Globals { 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()) + r.handle_global_removed(&**global) }); Ok(()) } @@ -339,10 +344,9 @@ impl Globals { for global in globals.values() { if global.singleton().is_some() == $singleton { if global.exposed(®istry.client.state) - && caps.contains(global.required_caps()) - && (xwayland || !global.xwayland_only()) + && global.permitted(caps, xwayland) { - registry.send_global(global); + registry.handle_global(global); } } } @@ -400,6 +404,29 @@ impl Globals { global.clone().add(self); self.insert_no_broadcast(global.clone()); } + + pub fn expose_new_singletons(&self, state: &State) { + let mut singletons = ArrayVec::<_, { Singleton::LENGTH }>::new(); + for name in self.singletons.values() { + if let Some(global) = self.registry.get(name) + && global.exposed(state) + { + singletons.push(global); + } + } + for client in state.clients.clients.borrow().values() { + let client = &client.data; + let caps = client.effective_caps.get(); + let xwayland = client.is_xwayland; + for global in &singletons { + if global.permitted(caps, xwayland) { + for registry in client.objects.registries.lock().values() { + registry.handle_global(global); + } + } + } + } + } } pub trait WaylandGlobal: Global + 'static { diff --git a/src/ifs/jay_color_management.rs b/src/ifs/jay_color_management.rs index 5d5194e9..12990d00 100644 --- a/src/ifs/jay_color_management.rs +++ b/src/ifs/jay_color_management.rs @@ -49,8 +49,7 @@ impl JayColorManagementRequestHandler for JayColorManagement { fn set_enabled(&self, req: SetEnabled, _slf: &Rc) -> Result<(), Self::Error> { self.client .state - .color_management_enabled - .set(req.enabled != 0); + .set_color_management_enabled(req.enabled != 0); Ok(()) } } diff --git a/src/ifs/wl_registry.rs b/src/ifs/wl_registry.rs index 66d4628b..f0dfda67 100644 --- a/src/ifs/wl_registry.rs +++ b/src/ifs/wl_registry.rs @@ -1,12 +1,13 @@ use { crate::{ client::Client, - globals::{Global, GlobalName, GlobalsError}, + globals::{Global, GlobalName, GlobalsError, Singleton}, leaks::Tracker, object::{Interface, Object, Version}, wire::{WlRegistryId, wl_registry::*}, }, - std::rc::Rc, + linearize::StaticMap, + std::{cell::Cell, rc::Rc}, thiserror::Error, }; @@ -14,6 +15,7 @@ pub struct WlRegistry { id: WlRegistryId, pub client: Rc, pub tracker: Tracker, + advertised: StaticMap>, } impl WlRegistry { @@ -22,23 +24,34 @@ impl WlRegistry { id, client: client.clone(), tracker: Default::default(), + advertised: Default::default(), } } - pub fn send_global(self: &Rc, global: &Rc) { + pub fn handle_global(&self, global: &Rc) { + if let Some(singleton) = global.singleton() + && self.advertised[singleton].replace(true) + { + return; + } self.client.event(crate::wire::wl_registry::Global { self_id: self.id, name: global.name().raw(), interface: global.interface().name(), version: global.version(), - }) + }); } - pub fn send_global_remove(self: &Rc, name: GlobalName) { + pub fn handle_global_removed(&self, global: &dyn Global) { + if let Some(singleton) = global.singleton() + && !self.advertised[singleton].replace(false) + { + return; + } self.client.event(GlobalRemove { self_id: self.id, - name: name.raw(), - }) + name: global.name().raw(), + }); } } diff --git a/src/state.rs b/src/state.rs index 49c703e9..7a67d293 100644 --- a/src/state.rs +++ b/src/state.rs @@ -736,6 +736,8 @@ impl State { for sc in scs { sc.do_destroy(); } + + self.expose_new_singletons(); } fn reload_cursors(&self) { @@ -1667,6 +1669,25 @@ impl State { ws.desired_output.set(output.global.output_id.clone()); self.tree_changed(); } + + fn expose_new_singletons(&self) { + self.globals.expose_new_singletons(self); + } + + pub fn set_color_management_enabled(&self, enabled: bool) { + self.color_management_enabled.set(enabled); + self.expose_new_singletons(); + } + + pub fn set_primary_selection_enabled(&self, enabled: bool) { + self.enable_primary_selection.set(enabled); + self.expose_new_singletons(); + } + + pub fn set_explicit_sync_enabled(&self, enabled: bool) { + self.explicit_sync_enabled.set(enabled); + self.expose_new_singletons(); + } } #[derive(Debug, Error)]