From be6b799b5178342c05b8c238b5657459e34940d0 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 1 May 2025 13:52:04 -0400 Subject: [PATCH] chore(accessibility): use settings subscription for color filter --- Cargo.lock | 6 +- cosmic-settings/Cargo.toml | 2 +- .../src/pages/accessibility/magnifier.rs | 2 +- .../src/pages/accessibility/mod.rs | 12 +- .../src/pages/accessibility/wayland.rs | 241 ------------------ 5 files changed, 13 insertions(+), 250 deletions(-) delete mode 100644 cosmic-settings/src/pages/accessibility/wayland.rs diff --git a/Cargo.lock b/Cargo.lock index 43d1d87..71d04c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1792,19 +1792,23 @@ dependencies = [ [[package]] name = "cosmic-settings-subscriptions" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-settings-subscriptions#650f0bc1dbfdce2e541c104674257d1621b2de4c" +source = "git+https://github.com/pop-os/cosmic-settings-subscriptions#6c36b82d5f7264f3b06ca83e1b2d01c9f979d104" dependencies = [ "bluez-zbus", "cosmic-dbus-a11y", "cosmic-dbus-networkmanager", + "cosmic-protocols", "futures", "iced_futures", "itertools 0.14.0", "libpulse-binding", "log", + "num-derive", + "num-traits", "pipewire", "rustix 1.0.5", "secure-string", + "smithay-client-toolkit", "thiserror 2.0.12", "tokio", "tokio-stream", diff --git a/cosmic-settings/Cargo.toml b/cosmic-settings/Cargo.toml index 1ec5e19..e6a72ad 100644 --- a/cosmic-settings/Cargo.toml +++ b/cosmic-settings/Cargo.toml @@ -93,7 +93,7 @@ pwhash = "1" [dependencies.cosmic-settings-subscriptions] git = "https://github.com/pop-os/cosmic-settings-subscriptions" #TODO: only select features as needed -features = ["accessibility", "network_manager", "pipewire", "pulse", "bluetooth"] +features = ["cosmic_a11y_manager", "accessibility", "network_manager", "pipewire", "pulse", "bluetooth"] optional = true [dependencies.icu] diff --git a/cosmic-settings/src/pages/accessibility/magnifier.rs b/cosmic-settings/src/pages/accessibility/magnifier.rs index 3da2e63..63ff85c 100644 --- a/cosmic-settings/src/pages/accessibility/magnifier.rs +++ b/cosmic-settings/src/pages/accessibility/magnifier.rs @@ -18,7 +18,7 @@ use cosmic_settings_page::{ use slotmap::SlotMap; use tracing::error; -use super::{AccessibilityEvent, AccessibilityRequest, wayland}; +use super::{AccessibilityEvent, AccessibilityRequest, cosmic_a11y_manager as wayland}; #[derive(Debug)] pub struct Page { diff --git a/cosmic-settings/src/pages/accessibility/mod.rs b/cosmic-settings/src/pages/accessibility/mod.rs index c31e938..966e16b 100644 --- a/cosmic-settings/src/pages/accessibility/mod.rs +++ b/cosmic-settings/src/pages/accessibility/mod.rs @@ -14,13 +14,13 @@ use cosmic_settings_page::{ section::{self, Section}, }; use cosmic_settings_subscriptions::accessibility::{self, DBusRequest, DBusUpdate}; +use cosmic_settings_subscriptions::cosmic_a11y_manager; use num_traits::FromPrimitive; use slotmap::SlotMap; pub mod magnifier; -mod wayland; +pub use cosmic_a11y_manager::{AccessibilityEvent, AccessibilityRequest, ColorFilter}; use tokio::sync::mpsc::UnboundedSender; -pub use wayland::{AccessibilityEvent, AccessibilityRequest, ColorFilter}; #[derive(Debug)] pub struct Page { @@ -32,7 +32,7 @@ pub struct Page { screen_filter_selections: Vec, wayland_available: Option, - wayland_thread: Option, + wayland_thread: Option, theme: Box, high_contrast: Option, daemon_config: CosmicSettingsDaemonConfig, @@ -74,7 +74,7 @@ impl Default for Page { #[derive(Debug, Clone)] pub enum Message { - Event(wayland::AccessibilityEvent), + Event(cosmic_a11y_manager::AccessibilityEvent), ProtocolUnavailable, Return, HighContrast(bool), @@ -110,7 +110,7 @@ impl page::Page for Page { fn on_enter(&mut self) -> cosmic::Task { if self.wayland_thread.is_none() { - match wayland::spawn_wayland_connection() { + match cosmic_a11y_manager::spawn_wayland_connection() { Ok((tx, mut rx)) => { self.wayland_thread = Some(tx); @@ -385,7 +385,7 @@ impl Page { if let Some(sender) = self.wayland_thread.as_ref() { let _ = sender.send(AccessibilityRequest::ScreenFilter { inverted, - filter: Some(wayland::ColorFilter::Unknown), + filter: Some(cosmic_a11y_manager::ColorFilter::Unknown), }); } } diff --git a/cosmic-settings/src/pages/accessibility/wayland.rs b/cosmic-settings/src/pages/accessibility/wayland.rs deleted file mode 100644 index 486f7fa..0000000 --- a/cosmic-settings/src/pages/accessibility/wayland.rs +++ /dev/null @@ -1,241 +0,0 @@ -use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1; -use num_derive::{FromPrimitive, ToPrimitive}; -use sctk::{ - reexports::{ - calloop::{self, LoopSignal, channel}, - calloop_wayland_source::WaylandSource, - client::{ - ConnectError, Connection, Dispatch, Proxy, WEnum, - globals::{GlobalListContents, registry_queue_init}, - protocol::wl_registry, - }, - }, - registry::RegistryState, -}; -use tokio::sync::mpsc; - -#[derive(Debug, Clone, Copy)] -pub enum AccessibilityEvent { - Bound(u32), - Magnifier(bool), - ScreenFilter { - inverted: bool, - filter: Option, - }, - Closed, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] -pub enum ColorFilter { - Greyscale, - Deuteranopia, - Protanopia, - Tritanopia, - Unknown, -} - -impl Default for ColorFilter { - fn default() -> Self { - ColorFilter::Unknown - } -} - -#[derive(Debug, Clone, Copy)] -pub enum AccessibilityRequest { - Magnifier(bool), - ScreenFilter { - inverted: bool, - filter: Option, - }, -} - -pub type Sender = calloop::channel::Sender; - -pub fn spawn_wayland_connection() -> Result< - ( - channel::Sender, - mpsc::Receiver, - ), - ConnectError, -> { - let (event_tx, event_rx) = mpsc::channel(10); - let (request_tx, request_rx) = channel::channel(); - let conn = Connection::connect_to_env()?; - - std::thread::spawn(move || { - if let Err(err) = wayland_thread(conn, event_tx.clone(), request_rx) { - tracing::warn!("Accessibility protocol wayland thread crashed: {}", err); - let _ = event_tx.blocking_send(AccessibilityEvent::Closed); - } - }); - - Ok((request_tx, event_rx)) -} - -fn wayland_thread( - conn: Connection, - tx: mpsc::Sender, - rx: channel::Channel, -) -> anyhow::Result<()> { - struct State { - loop_signal: LoopSignal, - tx: mpsc::Sender, - global: cosmic_a11y_manager_v1::CosmicA11yManagerV1, - - magnifier: bool, - screen_inverted: bool, - screen_filter: Option, - } - - impl Dispatch for State { - fn event( - state: &mut Self, - _proxy: &cosmic_a11y_manager_v1::CosmicA11yManagerV1, - event: ::Event, - _data: &(), - _conn: &Connection, - _qhandle: &sctk::reexports::client::QueueHandle, - ) { - match event { - cosmic_a11y_manager_v1::Event::Magnifier { active } => { - let magnifier = active - .into_result() - .unwrap_or(cosmic_a11y_manager_v1::ActiveState::Disabled) - == cosmic_a11y_manager_v1::ActiveState::Enabled; - if magnifier != state.magnifier { - if state - .tx - .blocking_send(AccessibilityEvent::Magnifier(magnifier)) - .is_err() - { - state.loop_signal.stop(); - state.loop_signal.wakeup(); - }; - state.magnifier = magnifier; - } - } - cosmic_a11y_manager_v1::Event::ScreenFilter { inverted, filter } => { - let inverted = inverted - .into_result() - .unwrap_or(cosmic_a11y_manager_v1::ActiveState::Disabled) - == cosmic_a11y_manager_v1::ActiveState::Enabled; - let filter = match filter { - WEnum::Value(cosmic_a11y_manager_v1::Filter::Disabled) => None, - WEnum::Value(cosmic_a11y_manager_v1::Filter::Greyscale) => { - Some(ColorFilter::Greyscale) - } - WEnum::Value(cosmic_a11y_manager_v1::Filter::DaltonizeProtanopia) => { - Some(ColorFilter::Protanopia) - } - WEnum::Value(cosmic_a11y_manager_v1::Filter::DaltonizeDeuteranopia) => { - Some(ColorFilter::Deuteranopia) - } - WEnum::Value(cosmic_a11y_manager_v1::Filter::DaltonizeTritanopia) => { - Some(ColorFilter::Tritanopia) - } - WEnum::Value(_) | WEnum::Unknown(_) => Some(ColorFilter::Unknown), - }; - - if inverted != state.screen_inverted || filter != state.screen_filter { - if state - .tx - .blocking_send(AccessibilityEvent::ScreenFilter { inverted, filter }) - .is_err() - { - state.loop_signal.stop(); - state.loop_signal.wakeup(); - }; - state.screen_inverted = inverted; - state.screen_filter = filter; - } - } - _ => unreachable!(), - } - } - } - impl Dispatch for State { - fn event( - _state: &mut Self, - _proxy: &wl_registry::WlRegistry, - _event: ::Event, - _data: &GlobalListContents, - _conn: &Connection, - _qhandle: &sctk::reexports::client::QueueHandle, - ) { - // We don't care about any dynamic globals - } - } - - let mut event_loop = calloop::EventLoop::::try_new().unwrap(); - - let loop_handle = event_loop.handle(); - let (globals, event_queue) = registry_queue_init(&conn).unwrap(); - let qhandle = event_queue.handle(); - - WaylandSource::new(conn, event_queue) - .insert(loop_handle.clone()) - .map_err(|err| err.error)?; - - let registry_state = RegistryState::new(&globals); - let Ok(global) = registry_state.bind_one::( - &qhandle, - 1..=2, - (), - ) else { - return Ok(()); - }; - - let _ = tx.blocking_send(AccessibilityEvent::Bound(global.version())); - - loop_handle - .insert_source(rx, |request, _, state| match request { - channel::Event::Msg(AccessibilityRequest::Magnifier(val)) => { - state.global.set_magnifier(if val { - cosmic_a11y_manager_v1::ActiveState::Enabled - } else { - cosmic_a11y_manager_v1::ActiveState::Disabled - }); - } - channel::Event::Msg(AccessibilityRequest::ScreenFilter { inverted, filter }) => { - state.global.set_screen_filter( - if inverted { - cosmic_a11y_manager_v1::ActiveState::Enabled - } else { - cosmic_a11y_manager_v1::ActiveState::Disabled - }, - match filter { - None => cosmic_a11y_manager_v1::Filter::Disabled, - Some(ColorFilter::Greyscale) => cosmic_a11y_manager_v1::Filter::Greyscale, - Some(ColorFilter::Protanopia) => { - cosmic_a11y_manager_v1::Filter::DaltonizeProtanopia - } - Some(ColorFilter::Deuteranopia) => { - cosmic_a11y_manager_v1::Filter::DaltonizeDeuteranopia - } - Some(ColorFilter::Tritanopia) => { - cosmic_a11y_manager_v1::Filter::DaltonizeTritanopia - } - Some(ColorFilter::Unknown) => cosmic_a11y_manager_v1::Filter::Unknown, - }, - ); - } - channel::Event::Closed => { - state.loop_signal.stop(); - state.loop_signal.wakeup(); - } - }) - .map_err(|err| err.error)?; - - let mut state = State { - loop_signal: event_loop.get_signal(), - tx, - global, - - magnifier: false, - screen_inverted: false, - screen_filter: None, - }; - - event_loop.run(None, &mut state, |_| {})?; - Ok(()) -}