From a3904af03ce38df9b50dd2b3ece4c5a46879bbaf Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 14 Nov 2025 14:45:36 -0800 Subject: [PATCH] wayland: Remove `atspi` protocol If we want to use the `org.freedesktop.a11y.KeyboardMonitor` protocol on Pop!_OS, there is no need to support the Cosmic-specific protocol that requires an `at-spi2-core` patch. --- Cargo.lock | 11 -- Cargo.toml | 1 - src/config/mod.rs | 1 - src/input/mod.rs | 36 +--- src/state.rs | 10 -- src/wayland/handlers/atspi.rs | 304 --------------------------------- src/wayland/handlers/mod.rs | 1 - src/wayland/protocols/atspi.rs | 162 ------------------ src/wayland/protocols/mod.rs | 1 - 9 files changed, 8 insertions(+), 519 deletions(-) delete mode 100644 src/wayland/handlers/atspi.rs delete mode 100644 src/wayland/protocols/atspi.rs diff --git a/Cargo.lock b/Cargo.lock index 46f9128a..91f8f8b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -853,7 +853,6 @@ dependencies = [ "profiling", "rand 0.9.2", "regex", - "reis", "ron", "rust-embed", "rustix 1.1.2", @@ -4511,16 +4510,6 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" -[[package]] -name = "reis" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00939c5c526a1b4054ef8d9d96b3f92227f08ca355965e986741b556eda6d289" -dependencies = [ - "calloop 0.14.3", - "rustix 0.38.44", -] - [[package]] name = "renderdoc-sys" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 409f3e32..041ecd43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,7 +82,6 @@ zbus = "5.12.0" profiling = { version = "1.0" } rustix = { version = "1.1.2", features = ["process"] } rand = "0.9.2" -reis = { version = "0.5", features = ["calloop"] } # CLI arguments clap_lex = "0.7" parking_lot = "0.12.5" diff --git a/src/config/mod.rs b/src/config/mod.rs index ea5428ef..99b8780f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -805,7 +805,6 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut } } } - state.common.atspi_ei.update_keymap(value.clone()); state.common.config.cosmic_conf.xkb_config = value; } "keyboard_config" => { diff --git a/src/input/mod.rs b/src/input/mod.rs index a50b967c..0fcfa936 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1592,9 +1592,6 @@ impl State { .unwrap_or(false) }); - self.common - .atspi_ei - .input(modifiers, &handle, event.state(), event.time() * 1000); self.common .a11y_keyboard_monitor_state .key_event(modifiers, &handle, event.state()); @@ -1762,12 +1759,7 @@ impl State { } if event.state() == KeyState::Released { - let mut removed = self - .common - .atspi_ei - .active_virtual_mods - .remove(&event.key_code()); - removed |= self + let removed = self .common .a11y_keyboard_monitor_state .remove_active_virtual_mod(handle.modified_sym()); @@ -1797,27 +1789,20 @@ impl State { ); } } else if event.state() == KeyState::Pressed - && (self + && self .common - .atspi_ei - .virtual_mods - .contains(&event.key_code()) - || self - .common - .a11y_keyboard_monitor_state - .has_virtual_mod(handle.modified_sym())) + .a11y_keyboard_monitor_state + .has_virtual_mod(handle.modified_sym()) { - self.common - .atspi_ei - .active_virtual_mods - .insert(event.key_code()); self.common .a11y_keyboard_monitor_state .add_active_virtual_mod(handle.modified_sym()); tracing::debug!( "active virtual mods: {:?}", - self.common.atspi_ei.active_virtual_mods + self.common + .a11y_keyboard_monitor_state + .active_virtual_mods() ); seat.supressed_keys().add(&handle, None); @@ -1848,12 +1833,7 @@ impl State { return FilterResult::Intercept(None); } - if self.common.atspi_ei.has_keyboard_grab() - || self.common.a11y_keyboard_monitor_state.has_keyboard_grab() - || self - .common - .atspi_ei - .has_key_grab(modifiers.serialized.layout_effective, event.key_code()) + if self.common.a11y_keyboard_monitor_state.has_keyboard_grab() || self .common .a11y_keyboard_monitor_state diff --git a/src/state.rs b/src/state.rs index 596cce2d..0ab568f0 100644 --- a/src/state.rs +++ b/src/state.rs @@ -16,7 +16,6 @@ use crate::{ handlers::{data_device::get_dnd_icon, screencopy::SessionHolder}, protocols::{ a11y::A11yState, - atspi::AtspiState, corner_radius::CornerRadiusState, drm::WlDrmState, image_capture_source::ImageCaptureSourceState, @@ -271,9 +270,6 @@ pub struct Common { pub xwayland_shell_state: XWaylandShellState, pub pointer_focus_state: Option, - pub atspi_state: AtspiState, - pub atspi_ei: crate::wayland::handlers::atspi::AtspiEiState, - #[cfg(feature = "systemd")] pub inhibit_lid_fd: Option, } @@ -708,9 +704,6 @@ impl State { let a11y_keyboard_monitor_state = A11yKeyboardMonitorState::new(&async_executor); - // TODO: Restrict to only specific client? - let atspi_state = AtspiState::new::(dh, client_has_no_security_context); - State { common: Common { config, @@ -774,9 +767,6 @@ impl State { xwayland_shell_state, pointer_focus_state: None, - atspi_state, - atspi_ei: Default::default(), - #[cfg(feature = "systemd")] inhibit_lid_fd: None, }, diff --git a/src/wayland/handlers/atspi.rs b/src/wayland/handlers/atspi.rs deleted file mode 100644 index 774055ed..00000000 --- a/src/wayland/handlers/atspi.rs +++ /dev/null @@ -1,304 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -use cosmic_comp_config::XkbConfig; -use cosmic_protocols::atspi::v1::server::cosmic_atspi_manager_v1::CosmicAtspiManagerV1; -use reis::{ - calloop::{EisRequestSource, EisRequestSourceEvent}, - eis::{self, device::DeviceType}, - request::{Connection, Device, DeviceCapability, EisRequest, Seat}, -}; -use smithay::{ - backend::input::{KeyState, Keycode}, - input::keyboard::ModifiersState, - utils::SealedFile, -}; -use std::{ - collections::{HashMap, HashSet}, - ffi::CString, - mem, - os::unix::{io::AsFd, net::UnixStream}, -}; -use xkbcommon::xkb; - -use crate::{ - state::State, - wayland::protocols::atspi::{AtspiHandler, delegate_atspi}, -}; - -#[derive(PartialEq, Debug)] -pub struct AtspiKeyGrab { - pub mods: u32, - pub virtual_mods: HashSet, - pub key: Keycode, -} - -#[derive(Debug, Default)] -struct AtspiClient { - key_grabs: Vec, - has_keyboard_grab: bool, - // TODO: purge old instances - keyboards: Vec<(Connection, Device, eis::Keyboard)>, -} - -impl AtspiClient { - fn add_keyboard( - &mut self, - connection: &Connection, - seat: &Seat, - keymap: &xkb::Keymap, - modifiers: &ModifiersState, - ) { - let keymap_text = keymap.get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1); - let name = c"eis-keymap"; - let file = SealedFile::with_content(name, &CString::new(keymap_text).unwrap()).unwrap(); - - let device = seat.add_device( - Some("keyboard"), - DeviceType::Virtual, - &[DeviceCapability::Keyboard], - |device| { - let keyboard = device.interface::().unwrap(); - keyboard.keymap( - eis::keyboard::KeymapType::Xkb, - file.size() as u32 - 1, - file.as_fd(), - ); - }, - ); - device.resumed(); - - let keyboard = device.interface::().unwrap(); - - connection.with_next_serial(|serial| { - keyboard.modifiers( - serial, - modifiers.serialized.depressed, - modifiers.serialized.locked, - modifiers.serialized.latched, - modifiers.serialized.layout_effective, - ) - }); - - device.start_emulating(0); - - self.keyboards.push((connection.clone(), device, keyboard)); - } -} - -#[derive(Debug, Default)] -pub struct AtspiEiState { - modifiers: ModifiersState, - clients: HashMap, - pub virtual_mods: HashSet, - pub active_virtual_mods: HashSet, -} - -impl AtspiEiState { - pub fn input( - &mut self, - modifiers: &smithay::input::keyboard::ModifiersState, - keysym: &smithay::input::keyboard::KeysymHandle, - state: KeyState, - time: u64, - ) { - let state = match state { - KeyState::Pressed => eis::keyboard::KeyState::Press, - KeyState::Released => eis::keyboard::KeyState::Released, - }; - if &self.modifiers != modifiers { - self.modifiers = *modifiers; - for client in self.clients.values() { - for (connection, _, keyboard) in &client.keyboards { - connection.with_next_serial(|serial| { - keyboard.modifiers( - serial, - modifiers.serialized.depressed, - modifiers.serialized.locked, - modifiers.serialized.latched, - modifiers.serialized.layout_effective, - ) - }); - } - } - } - for client in self.clients.values() { - for (connection, device, keyboard) in &client.keyboards { - keyboard.key(keysym.raw_code().raw() - 8, state); - device.frame(time); - let _ = connection.flush(); - } - } - } - - pub fn has_keyboard_grab(&self) -> bool { - self.clients.values().any(|client| client.has_keyboard_grab) - } - - /// Key grab exists for mods, key, with active virtual mods - pub fn has_key_grab(&self, mods: u32, key: Keycode) -> bool { - self.clients - .values() - .flat_map(|client| &client.key_grabs) - .any(|grab| { - grab.mods == mods - && grab.virtual_mods == self.active_virtual_mods - && grab.key == key - }) - } - - fn update_virtual_mods(&mut self) { - self.virtual_mods.clear(); - self.virtual_mods.extend( - self.clients - .values() - .flat_map(|client| &client.key_grabs) - .flat_map(|grab| &grab.virtual_mods), - ); - } - - pub fn update_keymap(&mut self, xkb_config: XkbConfig) { - let keymap = keymap_or_default(xkb_config); - for client in self.clients.values_mut() { - let old_keyboards = mem::take(&mut client.keyboards); - for (connection, device, _keyboard) in old_keyboards { - device.remove(); - client.add_keyboard(&connection, device.seat(), &keymap, &self.modifiers); - let _ = connection.flush(); - } - } - } -} - -impl AtspiHandler for State { - fn client_connected(&mut self, manager: &CosmicAtspiManagerV1, socket: UnixStream) { - self.common - .atspi_ei - .clients - .insert(manager.clone(), AtspiClient::default()); - - let context = eis::Context::new(socket).unwrap(); - let source = EisRequestSource::new(context, 0); - let manager = manager.clone(); - self.common - .event_loop_handle - .insert_source(source, move |event, connected_state, state| { - Ok(handle_event(&manager, event, connected_state, state)) - }) - .unwrap(); - } - - fn client_disconnected(&mut self, manager: &CosmicAtspiManagerV1) { - self.common.atspi_ei.clients.remove(manager); - self.common.atspi_ei.update_virtual_mods(); - } - - fn add_key_grab( - &mut self, - manager: &CosmicAtspiManagerV1, - mods: u32, - virtual_mods: Vec, - key: Keycode, - ) { - let grab = AtspiKeyGrab { - mods, - virtual_mods: virtual_mods.into_iter().collect(), - key, - }; - let client = self.common.atspi_ei.clients.get_mut(manager).unwrap(); - client.key_grabs.push(grab); - self.common.atspi_ei.update_virtual_mods(); - } - - fn remove_key_grab( - &mut self, - manager: &CosmicAtspiManagerV1, - mods: u32, - virtual_mods: Vec, - key: Keycode, - ) { - let grab = AtspiKeyGrab { - mods, - virtual_mods: virtual_mods.into_iter().collect(), - key, - }; - let client = self.common.atspi_ei.clients.get_mut(manager).unwrap(); - if let Some(idx) = client.key_grabs.iter().position(|x| *x == grab) { - client.key_grabs.remove(idx); - } - self.common.atspi_ei.update_virtual_mods(); - } - - fn grab_keyboard(&mut self, manager: &CosmicAtspiManagerV1) { - let client = self.common.atspi_ei.clients.get_mut(manager).unwrap(); - client.has_keyboard_grab = true; - } - - fn ungrab_keyboard(&mut self, manager: &CosmicAtspiManagerV1) { - let client = self.common.atspi_ei.clients.get_mut(manager).unwrap(); - client.has_keyboard_grab = false; - } -} - -fn handle_event( - manager: &CosmicAtspiManagerV1, - event: Result, - connection: &Connection, - state: &mut State, -) -> calloop::PostAction { - let Some(client) = state.common.atspi_ei.clients.get_mut(manager) else { - return calloop::PostAction::Remove; - }; - match event { - Ok(EisRequestSourceEvent::Connected) => { - if connection.context_type() != reis::ei::handshake::ContextType::Receiver { - return calloop::PostAction::Remove; - } - let _seat = connection.add_seat(Some("default"), &[DeviceCapability::Keyboard]); - } - Ok(EisRequestSourceEvent::Request(EisRequest::Disconnect)) => { - return calloop::PostAction::Remove; - } - Ok(EisRequestSourceEvent::Request(EisRequest::Bind(request))) => { - if connection.has_interface("ei_keyboard") - && request.capabilities & (2 << DeviceCapability::Keyboard as u64) != 0 - { - let keymap = keymap_or_default(state.common.config.xkb_config()); - client.add_keyboard( - connection, - &request.seat, - &keymap, - &state.common.atspi_ei.modifiers, - ); - } - } - Ok(EisRequestSourceEvent::Request(_request)) => { - // seat / keyboard / device release? - } - Ok(EisRequestSourceEvent::InvalidObject(_)) => {} - Err(_) => { - // TODO - } - } - let _ = connection.flush(); - calloop::PostAction::Continue -} - -// TODO: use keymap of seat? -fn keymap_or_default(xkb_config: XkbConfig) -> xkb::Keymap { - keymap(xkb_config).unwrap_or_else(|| keymap(XkbConfig::default()).unwrap()) -} - -fn keymap(xkb_config: XkbConfig) -> Option { - let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); - xkb::Keymap::new_from_names( - &context, - &xkb_config.rules, - &xkb_config.model, - &xkb_config.layout, - &xkb_config.variant, - xkb_config.options.clone(), - xkb::KEYMAP_COMPILE_NO_FLAGS, - ) -} - -delegate_atspi!(State); diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index 6f4344a4..b057c8c2 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -2,7 +2,6 @@ pub mod a11y; pub mod alpha_modifier; -pub mod atspi; pub mod buffer; pub mod compositor; pub mod corner_radius; diff --git a/src/wayland/protocols/atspi.rs b/src/wayland/protocols/atspi.rs deleted file mode 100644 index a85d9ab3..00000000 --- a/src/wayland/protocols/atspi.rs +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -use cosmic_protocols::atspi::v1::server::cosmic_atspi_manager_v1; - -use smithay::{ - backend::input::Keycode, - reexports::wayland_server::{ - Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, backend::GlobalId, - }, -}; -use std::os::unix::{io::AsFd, net::UnixStream}; -use wayland_backend::server::ClientId; - -pub trait AtspiHandler { - fn client_connected( - &mut self, - manager: &cosmic_atspi_manager_v1::CosmicAtspiManagerV1, - key_event_socket: UnixStream, - ); - fn client_disconnected(&mut self, manager: &cosmic_atspi_manager_v1::CosmicAtspiManagerV1); - fn add_key_grab( - &mut self, - manager: &cosmic_atspi_manager_v1::CosmicAtspiManagerV1, - mods: u32, - virtual_mods: Vec, - key: Keycode, - ); - fn remove_key_grab( - &mut self, - manager: &cosmic_atspi_manager_v1::CosmicAtspiManagerV1, - mods: u32, - virtual_mods: Vec, - key: Keycode, - ); - fn grab_keyboard(&mut self, manager: &cosmic_atspi_manager_v1::CosmicAtspiManagerV1); - fn ungrab_keyboard(&mut self, manager: &cosmic_atspi_manager_v1::CosmicAtspiManagerV1); -} - -#[derive(Debug)] -pub struct AtspiState { - global: GlobalId, -} - -impl AtspiState { - pub fn new(dh: &DisplayHandle, client_filter: F) -> AtspiState - where - D: GlobalDispatch + 'static, - F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static, - { - let global = dh.create_global::( - 1, - AtspiGlobalData { - filter: Box::new(client_filter), - }, - ); - AtspiState { global } - } - - pub fn global_id(&self) -> GlobalId { - self.global.clone() - } -} - -pub struct AtspiGlobalData { - filter: Box Fn(&'a Client) -> bool + Send + Sync>, -} - -impl GlobalDispatch - for AtspiState -where - D: GlobalDispatch - + Dispatch - + AtspiHandler - + 'static, -{ - fn bind( - state: &mut D, - _dh: &DisplayHandle, - _client: &Client, - resource: New, - _global_data: &AtspiGlobalData, - data_init: &mut DataInit<'_, D>, - ) { - let instance = data_init.init(resource, ()); - let (client_socket, server_socket) = UnixStream::pair().unwrap(); - state.client_connected(&instance, server_socket); - instance.key_events_eis(client_socket.as_fd()); - } - - fn can_view(client: Client, global_data: &AtspiGlobalData) -> bool { - (global_data.filter)(&client) - } -} - -impl Dispatch for AtspiState -where - D: Dispatch + AtspiHandler + 'static, -{ - fn request( - state: &mut D, - _client: &Client, - manager: &cosmic_atspi_manager_v1::CosmicAtspiManagerV1, - request: cosmic_atspi_manager_v1::Request, - _data: &(), - _dh: &DisplayHandle, - _data_init: &mut DataInit<'_, D>, - ) { - match request { - cosmic_atspi_manager_v1::Request::AddKeyGrab { - mods, - virtual_mods, - key, - } => { - let virtual_mods = virtual_mods - .chunks_exact(4) - .map(|x| (u32::from_ne_bytes(<[u8; 4]>::try_from(x).unwrap()) + 8).into()) - .collect(); - state.add_key_grab(manager, mods, virtual_mods, (key + 8).into()); - } - cosmic_atspi_manager_v1::Request::RemoveKeyGrab { - mods, - virtual_mods, - key, - } => { - let virtual_mods = virtual_mods - .chunks_exact(4) - .map(|x| (u32::from_ne_bytes(<[u8; 4]>::try_from(x).unwrap()) + 8).into()) - .collect(); - state.remove_key_grab(manager, mods, virtual_mods, (key + 8).into()); - } - cosmic_atspi_manager_v1::Request::GrabKeyboard => { - state.grab_keyboard(manager); - } - cosmic_atspi_manager_v1::Request::UngrabKeyboard => { - state.ungrab_keyboard(manager); - } - cosmic_atspi_manager_v1::Request::Destroy => {} - _ => unreachable!(), - } - } - - fn destroyed( - state: &mut D, - _client: ClientId, - manager: &cosmic_atspi_manager_v1::CosmicAtspiManagerV1, - _data: &(), - ) { - state.client_disconnected(manager); - } -} - -macro_rules! delegate_atspi { - ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { - smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - cosmic_protocols::atspi::v1::server::cosmic_atspi_manager_v1::CosmicAtspiManagerV1: $crate::wayland::protocols::atspi::AtspiGlobalData - ] => $crate::wayland::protocols::atspi::AtspiState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - cosmic_protocols::atspi::v1::server::cosmic_atspi_manager_v1::CosmicAtspiManagerV1: () - ] => $crate::wayland::protocols::atspi::AtspiState); - }; -} -pub(crate) use delegate_atspi; diff --git a/src/wayland/protocols/mod.rs b/src/wayland/protocols/mod.rs index 851c58a4..99e39592 100644 --- a/src/wayland/protocols/mod.rs +++ b/src/wayland/protocols/mod.rs @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pub mod a11y; -pub mod atspi; pub mod corner_radius; pub mod drm; pub mod image_capture_source;