feat(accessiblity): high contrast and color filter toggles
This commit is contained in:
parent
e6722d20e2
commit
9eb4053d31
7 changed files with 317 additions and 395 deletions
379
Cargo.lock
generated
379
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -27,9 +27,8 @@ anyhow = "1.0.95"
|
||||||
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "178eb0b" }
|
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "178eb0b" }
|
||||||
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [
|
||||||
"client",
|
"client",
|
||||||
], rev = "178eb0b" }
|
], rev = "1425bd4" }
|
||||||
cosmic-settings-subscriptions = { git = "https://github.com/pop-os/cosmic-settings-subscriptions" }
|
cosmic-settings-subscriptions = { git = "https://github.com/pop-os/cosmic-settings-subscriptions" }
|
||||||
# cosmic-settings-subscriptions = { path = "../cosmic-settings-subscriptions" }
|
|
||||||
|
|
||||||
cosmic-time = { git = "https://github.com/pop-os/cosmic-time", default-features = false, features = [
|
cosmic-time = { git = "https://github.com/pop-os/cosmic-time", default-features = false, features = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
cosmic-settings-subscriptions.workspace = true
|
cosmic-settings-subscriptions.workspace = true
|
||||||
cosmic-settings-subscriptions.default_features = false
|
cosmic-settings-subscriptions.default_features = false
|
||||||
cosmic-settings-subscriptions.accessibility = true
|
cosmic-settings-subscriptions.accessibility = true
|
||||||
|
cosmic-settings-subscriptions.cosmic_a11y_manager = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
cctk.workspace = true
|
cctk.workspace = true
|
||||||
cosmic-protocols.workspace = true
|
cosmic-protocols.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,5 @@ screen-reader = Screen reader
|
||||||
magnifier = Magnifier
|
magnifier = Magnifier
|
||||||
invert-colors = Invert colors
|
invert-colors = Invert colors
|
||||||
settings = Accessibility settings...
|
settings = Accessibility settings...
|
||||||
|
filter-colors = Filter colors
|
||||||
|
high-contrast = High contrast
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,10 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{
|
backend::{self, wayland::WaylandUpdate},
|
||||||
self,
|
|
||||||
wayland::{AccessibilityEvent, AccessibilityRequest, WaylandUpdate},
|
|
||||||
},
|
|
||||||
fl,
|
fl,
|
||||||
};
|
};
|
||||||
|
use cctk::sctk::reexports::calloop;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app,
|
app,
|
||||||
applet::{
|
applet::{
|
||||||
|
|
@ -15,21 +13,27 @@ use cosmic::{
|
||||||
token::subscription::{activation_token_subscription, TokenRequest, TokenUpdate},
|
token::subscription::{activation_token_subscription, TokenRequest, TokenUpdate},
|
||||||
},
|
},
|
||||||
cctk::sctk::reexports::calloop::channel,
|
cctk::sctk::reexports::calloop::channel,
|
||||||
cosmic_theme::Spacing,
|
cosmic_config::{self, CosmicConfigEntry},
|
||||||
|
cosmic_theme::{CosmicPalette, Spacing, ThemeBuilder},
|
||||||
iced::{
|
iced::{
|
||||||
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
||||||
window, Length, Subscription,
|
window, Length, Subscription,
|
||||||
},
|
},
|
||||||
surface, theme,
|
surface,
|
||||||
|
theme::{self, CosmicTheme},
|
||||||
widget::{divider, text, Column},
|
widget::{divider, text, Column},
|
||||||
Element, Task,
|
Element, Task,
|
||||||
};
|
};
|
||||||
use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1::Filter;
|
use cosmic_settings_subscriptions::{
|
||||||
use cosmic_settings_subscriptions::accessibility::{self, DBusRequest, DBusUpdate};
|
accessibility::{self, DBusRequest, DBusUpdate},
|
||||||
|
cosmic_a11y_manager::{AccessibilityEvent, AccessibilityRequest, ColorFilter},
|
||||||
|
};
|
||||||
use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
|
use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
static READER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
static READER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
|
static FILTER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
|
static HC_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
static MAGNIFIER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
static MAGNIFIER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
static INVERT_COLORS_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
static INVERT_COLORS_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
|
|
||||||
|
|
@ -40,24 +44,28 @@ pub fn run() -> cosmic::iced::Result {
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
struct CosmicA11yApplet {
|
struct CosmicA11yApplet {
|
||||||
core: cosmic::app::Core,
|
core: cosmic::app::Core,
|
||||||
|
high_contrast: Option<bool>,
|
||||||
reader_enabled: bool,
|
reader_enabled: bool,
|
||||||
magnifier_enabled: bool,
|
magnifier_enabled: bool,
|
||||||
inverted_colors_enabled: bool,
|
inverted_colors_enabled: bool,
|
||||||
popup: Option<window::Id>,
|
popup: Option<window::Id>,
|
||||||
dbus_sender: Option<UnboundedSender<DBusRequest>>,
|
dbus_sender: Option<UnboundedSender<DBusRequest>>,
|
||||||
wayland_sender: Option<channel::SyncSender<AccessibilityRequest>>,
|
wayland_sender: Option<calloop::channel::Sender<AccessibilityRequest>>,
|
||||||
wayland_protocol_version: Option<u32>,
|
wayland_protocol_version: Option<u32>,
|
||||||
timeline: Timeline,
|
timeline: Timeline,
|
||||||
token_tx: Option<channel::Sender<TokenRequest>>,
|
token_tx: Option<channel::Sender<TokenRequest>>,
|
||||||
|
screen_filter_active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
TogglePopup,
|
TogglePopup,
|
||||||
CloseRequested(window::Id),
|
CloseRequested(window::Id),
|
||||||
|
HighContrastEnabled(chain::Toggler, bool),
|
||||||
ScreenReaderEnabled(chain::Toggler, bool),
|
ScreenReaderEnabled(chain::Toggler, bool),
|
||||||
MagnifierEnabled(chain::Toggler, bool),
|
MagnifierEnabled(chain::Toggler, bool),
|
||||||
InvertedColorsEnabled(chain::Toggler, bool),
|
InvertedColorsEnabled(chain::Toggler, bool),
|
||||||
|
FilterColorsEnabled(chain::Toggler, bool),
|
||||||
Frame(Instant),
|
Frame(Instant),
|
||||||
Token(TokenUpdate),
|
Token(TokenUpdate),
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
|
|
@ -119,12 +127,22 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
self.inverted_colors_enabled = enabled;
|
self.inverted_colors_enabled = enabled;
|
||||||
let _ = tx.send(AccessibilityRequest::ScreenFilter {
|
let _ = tx.send(AccessibilityRequest::ScreenFilter {
|
||||||
inverted: enabled,
|
inverted: enabled,
|
||||||
filter: Filter::Unknown,
|
filter: None,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.inverted_colors_enabled = false;
|
self.inverted_colors_enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::FilterColorsEnabled(chain, enabled) => {
|
||||||
|
if let Some(sender) = self.wayland_sender.as_ref() {
|
||||||
|
self.timeline.set_chain(chain).start();
|
||||||
|
self.screen_filter_active = enabled;
|
||||||
|
let _ = sender.send(AccessibilityRequest::ScreenFilter {
|
||||||
|
inverted: self.inverted_colors_enabled,
|
||||||
|
filter: enabled.then_some(ColorFilter::Unknown),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
return destroy_popup(p);
|
return destroy_popup(p);
|
||||||
|
|
@ -150,6 +168,63 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
self.popup = None;
|
self.popup = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::HighContrastEnabled(chain, enabled) => {
|
||||||
|
if self.core.system_theme().cosmic().is_high_contrast == enabled
|
||||||
|
|| self.high_contrast.is_some_and(|hc| hc == enabled)
|
||||||
|
{
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
self.timeline.set_chain(chain).start();
|
||||||
|
self.high_contrast = Some(enabled);
|
||||||
|
|
||||||
|
_ = std::thread::spawn(move || {
|
||||||
|
let set_hc = |is_dark: bool| {
|
||||||
|
let builder_config = if is_dark {
|
||||||
|
ThemeBuilder::dark_config()?
|
||||||
|
} else {
|
||||||
|
ThemeBuilder::light_config()?
|
||||||
|
};
|
||||||
|
let mut builder = match ThemeBuilder::get_entry(&builder_config) {
|
||||||
|
Ok(b) => b,
|
||||||
|
Err((errs, b)) => {
|
||||||
|
tracing::warn!("{errs:?}");
|
||||||
|
b
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.palette = if is_dark {
|
||||||
|
if enabled {
|
||||||
|
CosmicPalette::HighContrastDark(builder.palette.inner())
|
||||||
|
} else {
|
||||||
|
CosmicPalette::Dark(builder.palette.inner())
|
||||||
|
}
|
||||||
|
} else if enabled {
|
||||||
|
CosmicPalette::HighContrastLight(builder.palette.inner())
|
||||||
|
} else {
|
||||||
|
CosmicPalette::Light(builder.palette.inner())
|
||||||
|
};
|
||||||
|
builder.write_entry(&builder_config)?;
|
||||||
|
|
||||||
|
let new_theme = builder.build();
|
||||||
|
|
||||||
|
let theme_config = if is_dark {
|
||||||
|
CosmicTheme::dark_config()?
|
||||||
|
} else {
|
||||||
|
CosmicTheme::light_config()?
|
||||||
|
};
|
||||||
|
|
||||||
|
new_theme.write_entry(&theme_config)?;
|
||||||
|
|
||||||
|
Result::<(), cosmic_config::Error>::Ok(())
|
||||||
|
};
|
||||||
|
if let Err(err) = set_hc(true) {
|
||||||
|
tracing::warn!("{err:?}");
|
||||||
|
}
|
||||||
|
if let Err(err) = set_hc(false) {
|
||||||
|
tracing::warn!("{err:?}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Message::OpenSettings => {
|
Message::OpenSettings => {
|
||||||
let exec = "cosmic-settings accessibility".to_string();
|
let exec = "cosmic-settings accessibility".to_string();
|
||||||
if let Some(tx) = self.token_tx.as_ref() {
|
if let Some(tx) = self.token_tx.as_ref() {
|
||||||
|
|
@ -209,6 +284,11 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
WaylandUpdate::State(AccessibilityEvent::ScreenFilter { inverted, .. }) => {
|
WaylandUpdate::State(AccessibilityEvent::ScreenFilter { inverted, .. }) => {
|
||||||
self.inverted_colors_enabled = inverted;
|
self.inverted_colors_enabled = inverted;
|
||||||
}
|
}
|
||||||
|
WaylandUpdate::State(AccessibilityEvent::Closed) => {
|
||||||
|
self.screen_filter_active = false;
|
||||||
|
self.wayland_sender = None;
|
||||||
|
self.wayland_protocol_version = None;
|
||||||
|
}
|
||||||
WaylandUpdate::Started(tx) => {
|
WaylandUpdate::Started(tx) => {
|
||||||
self.wayland_sender = Some(tx);
|
self.wayland_sender = Some(tx);
|
||||||
}
|
}
|
||||||
|
|
@ -269,6 +349,31 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let hc_colors_toggle = padded_control(
|
||||||
|
anim!(
|
||||||
|
HC_TOGGLE,
|
||||||
|
&self.timeline,
|
||||||
|
fl!("high-contrast"),
|
||||||
|
self.high_contrast
|
||||||
|
.unwrap_or(self.core.system_theme().cosmic().is_high_contrast),
|
||||||
|
Message::HighContrastEnabled,
|
||||||
|
)
|
||||||
|
.text_size(14)
|
||||||
|
.width(Length::Fill),
|
||||||
|
);
|
||||||
|
|
||||||
|
let filter_colors_toggle = padded_control(
|
||||||
|
anim!(
|
||||||
|
FILTER_TOGGLE,
|
||||||
|
&self.timeline,
|
||||||
|
fl!("filter-colors"),
|
||||||
|
self.screen_filter_active,
|
||||||
|
Message::FilterColorsEnabled,
|
||||||
|
)
|
||||||
|
.text_size(14)
|
||||||
|
.width(Length::Fill),
|
||||||
|
);
|
||||||
|
|
||||||
let content_list = Column::with_capacity(5)
|
let content_list = Column::with_capacity(5)
|
||||||
.push(reader_toggle)
|
.push(reader_toggle)
|
||||||
.push_maybe(
|
.push_maybe(
|
||||||
|
|
@ -281,6 +386,12 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
.is_some_and(|ver| ver >= 2)
|
.is_some_and(|ver| ver >= 2)
|
||||||
.then_some(invert_colors_toggle),
|
.then_some(invert_colors_toggle),
|
||||||
)
|
)
|
||||||
|
.push_maybe(
|
||||||
|
self.wayland_protocol_version
|
||||||
|
.is_some_and(|ver| ver >= 3)
|
||||||
|
.then_some(filter_colors_toggle),
|
||||||
|
)
|
||||||
|
.push(hc_colors_toggle)
|
||||||
.push(padded_control(divider::horizontal::default()).padding([space_xxs, space_s]))
|
.push(padded_control(divider::horizontal::default()).padding([space_xxs, space_s]))
|
||||||
.push(menu_button(text::body(fl!("settings"))).on_press(Message::OpenSettings))
|
.push(menu_button(text::body(fl!("settings"))).on_press(Message::OpenSettings))
|
||||||
.padding([8, 0]);
|
.padding([8, 0]);
|
||||||
|
|
|
||||||
|
|
@ -2,41 +2,29 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use anyhow;
|
use anyhow;
|
||||||
use cctk::sctk::reexports::calloop::channel::SyncSender;
|
use cctk::sctk::reexports::calloop::{self, channel::SyncSender};
|
||||||
use cosmic::iced::{
|
use cosmic::iced::{
|
||||||
self,
|
self,
|
||||||
futures::{self, channel::mpsc, SinkExt, StreamExt},
|
futures::{self, channel::mpsc, SinkExt, StreamExt},
|
||||||
stream, Subscription,
|
stream, Subscription,
|
||||||
};
|
};
|
||||||
use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1::Filter;
|
use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1::Filter;
|
||||||
|
use cosmic_settings_subscriptions::cosmic_a11y_manager::{
|
||||||
|
self as thread, AccessibilityEvent, AccessibilityRequest,
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
mod thread;
|
pub static WAYLAND_RX: Lazy<Mutex<Option<tokio::sync::mpsc::Receiver<AccessibilityEvent>>>> =
|
||||||
|
|
||||||
pub static WAYLAND_RX: Lazy<Mutex<Option<mpsc::Receiver<AccessibilityEvent>>>> =
|
|
||||||
Lazy::new(|| Mutex::new(None));
|
Lazy::new(|| Mutex::new(None));
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum WaylandUpdate {
|
pub enum WaylandUpdate {
|
||||||
State(AccessibilityEvent),
|
State(AccessibilityEvent),
|
||||||
Started(SyncSender<AccessibilityRequest>),
|
Started(calloop::channel::Sender<AccessibilityRequest>),
|
||||||
Errored,
|
Errored,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum AccessibilityEvent {
|
|
||||||
Bound(u32),
|
|
||||||
Magnifier(bool),
|
|
||||||
ScreenFilter { inverted: bool, filter: Filter },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum AccessibilityRequest {
|
|
||||||
Magnifier(bool),
|
|
||||||
ScreenFilter { inverted: bool, filter: Filter },
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn a11y_subscription() -> iced::Subscription<WaylandUpdate> {
|
pub fn a11y_subscription() -> iced::Subscription<WaylandUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with_id(
|
||||||
std::any::TypeId::of::<WaylandUpdate>(),
|
std::any::TypeId::of::<WaylandUpdate>(),
|
||||||
|
|
@ -69,7 +57,7 @@ async fn start_listening(
|
||||||
}
|
}
|
||||||
guard.as_mut().unwrap()
|
guard.as_mut().unwrap()
|
||||||
};
|
};
|
||||||
if let Some(w) = rx.next().await {
|
if let Some(w) = rx.recv().await {
|
||||||
_ = output.send(WaylandUpdate::State(w)).await;
|
_ = output.send(WaylandUpdate::State(w)).await;
|
||||||
State::Waiting
|
State::Waiting
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -87,14 +75,13 @@ pub enum State {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WaylandWatcher {
|
pub struct WaylandWatcher {
|
||||||
rx: mpsc::Receiver<AccessibilityEvent>,
|
rx: tokio::sync::mpsc::Receiver<AccessibilityEvent>,
|
||||||
tx: SyncSender<AccessibilityRequest>,
|
tx: calloop::channel::Sender<AccessibilityRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WaylandWatcher {
|
impl WaylandWatcher {
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
let (tx, rx) = mpsc::channel(20);
|
let (tx, rx) = thread::spawn_wayland_connection(1)?;
|
||||||
let tx = thread::spawn_a11y(tx)?;
|
|
||||||
Ok(Self { tx, rx })
|
Ok(Self { tx, rx })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
// Copyright 2025 System76 <info@system76.com>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
use calloop::channel::*;
|
|
||||||
use cctk::{
|
|
||||||
sctk::{
|
|
||||||
self,
|
|
||||||
reexports::{
|
|
||||||
calloop::{self, channel},
|
|
||||||
calloop_wayland_source::WaylandSource,
|
|
||||||
},
|
|
||||||
registry::RegistryState,
|
|
||||||
},
|
|
||||||
wayland_client::{self, globals::GlobalListContents, protocol::wl_registry, Dispatch, Proxy},
|
|
||||||
};
|
|
||||||
use cosmic::iced::futures::{self, SinkExt};
|
|
||||||
use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1::{self, Filter};
|
|
||||||
use futures::{channel::mpsc, executor::block_on};
|
|
||||||
use wayland_client::{globals::registry_queue_init, Connection};
|
|
||||||
|
|
||||||
use super::{AccessibilityEvent, AccessibilityRequest};
|
|
||||||
|
|
||||||
pub fn spawn_a11y(
|
|
||||||
mut tx: mpsc::Sender<AccessibilityEvent>,
|
|
||||||
) -> anyhow::Result<SyncSender<AccessibilityRequest>> {
|
|
||||||
let (a11y_tx, a11y_rx) = calloop::channel::sync_channel(100);
|
|
||||||
let conn = Connection::connect_to_env()?;
|
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
|
||||||
struct State {
|
|
||||||
loop_signal: calloop::LoopSignal,
|
|
||||||
tx: mpsc::Sender<AccessibilityEvent>,
|
|
||||||
global: cosmic_a11y_manager_v1::CosmicA11yManagerV1,
|
|
||||||
|
|
||||||
magnifier: bool,
|
|
||||||
screen_inverted: bool,
|
|
||||||
screen_filter: Filter,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, ()> for State {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
_proxy: &cosmic_a11y_manager_v1::CosmicA11yManagerV1,
|
|
||||||
event: <cosmic_a11y_manager_v1::CosmicA11yManagerV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &Connection,
|
|
||||||
_qhandle: &sctk::reexports::client::QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
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 block_on(state.tx.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 = filter.into_result().unwrap_or(Filter::Unknown);
|
|
||||||
|
|
||||||
if inverted != state.screen_inverted || filter != state.screen_filter {
|
|
||||||
if block_on(
|
|
||||||
state
|
|
||||||
.tx
|
|
||||||
.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<wl_registry::WlRegistry, GlobalListContents> for State {
|
|
||||||
fn event(
|
|
||||||
_state: &mut Self,
|
|
||||||
_proxy: &wl_registry::WlRegistry,
|
|
||||||
_event: <wl_registry::WlRegistry as Proxy>::Event,
|
|
||||||
_data: &GlobalListContents,
|
|
||||||
_conn: &Connection,
|
|
||||||
_qhandle: &sctk::reexports::client::QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
// We don't care about any dynamic globals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut event_loop = calloop::EventLoop::<State>::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())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let registry_state = RegistryState::new(&globals);
|
|
||||||
let global = registry_state
|
|
||||||
.bind_one::<cosmic_a11y_manager_v1::CosmicA11yManagerV1, _, _>(&qhandle, 1..=2, ())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let _ = block_on(tx.send(AccessibilityEvent::Bound(global.version())));
|
|
||||||
|
|
||||||
loop_handle
|
|
||||||
.insert_source(a11y_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
|
|
||||||
},
|
|
||||||
filter,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
channel::Event::Closed => {
|
|
||||||
state.loop_signal.stop();
|
|
||||||
state.loop_signal.wakeup();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut state = State {
|
|
||||||
loop_signal: event_loop.get_signal(),
|
|
||||||
tx,
|
|
||||||
global,
|
|
||||||
|
|
||||||
magnifier: false,
|
|
||||||
screen_inverted: false,
|
|
||||||
screen_filter: Filter::Unknown,
|
|
||||||
};
|
|
||||||
|
|
||||||
event_loop.run(None, &mut state, |_| {}).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(a11y_tx)
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue