feat: accessibility menu
This commit is contained in:
parent
b848d52d58
commit
9c1306d8c7
7 changed files with 658 additions and 305 deletions
676
Cargo.lock
generated
676
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
19
Cargo.toml
19
Cargo.toml
|
|
@ -44,6 +44,21 @@ xdg = "2.5.2"
|
||||||
#TODO: reduce features
|
#TODO: reduce features
|
||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
wayland-client = "0.31.8"
|
wayland-client = "0.31.8"
|
||||||
|
cosmic-settings-subscriptions = { git = "https://github.com/pop-os/cosmic-settings-subscriptions", default-features = false, features = [
|
||||||
|
"accessibility",
|
||||||
|
"cosmic_a11y_manager",
|
||||||
|
] }
|
||||||
|
# cosmic-settings-daemon-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", default-features = false, features = [
|
||||||
|
# "greeter",
|
||||||
|
# ] }
|
||||||
|
cosmic-settings-daemon-config = { path = "../cosmic-settings-daemon/cosmic-settings-daemon-config", default-features = false, features = [
|
||||||
|
"greeter",
|
||||||
|
] }
|
||||||
|
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 = [
|
||||||
|
"client",
|
||||||
|
], rev = "1425bd4" }
|
||||||
|
|
||||||
# For network status using networkmanager feature
|
# For network status using networkmanager feature
|
||||||
cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
|
cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
|
||||||
# For logind integration using logind feature
|
# For logind integration using logind feature
|
||||||
|
|
@ -131,7 +146,9 @@ default-features = false
|
||||||
git = "https://github.com/pop-os/libcosmic"
|
git = "https://github.com/pop-os/libcosmic"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
# [patch.'https://github.com/pop-os/libcosmic']
|
|
||||||
|
[patch."https://github.com/smithay/client-toolkit.git"]
|
||||||
|
sctk = { package = "smithay-client-toolkit", version = "=0.19.2" }
|
||||||
# libcosmic = { path = "../libcosmic" }
|
# libcosmic = { path = "../libcosmic" }
|
||||||
# cosmic-config = { path = "../libcosmic/cosmic-config" }
|
# cosmic-config = { path = "../libcosmic/cosmic-config" }
|
||||||
# cosmic-theme = { path = "../libcosmic/cosmic-theme" }
|
# cosmic-theme = { path = "../libcosmic/cosmic-theme" }
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
accessibility = Accessibility
|
||||||
|
.screen-reader = Screen Reader
|
||||||
|
.magnifier = Magnifier
|
||||||
|
.high-contrast = High contrast
|
||||||
|
.invert-colors = Invert Colors
|
||||||
cancel = Cancel
|
cancel = Cancel
|
||||||
caps-lock = Caps Lock is active.
|
caps-lock = Caps Lock is active.
|
||||||
enter-user = Enter name manually...
|
enter-user = Enter name manually...
|
||||||
|
|
|
||||||
165
src/greeter.rs
165
src/greeter.rs
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
mod ipc;
|
mod ipc;
|
||||||
|
|
||||||
|
use crate::wayland::{self, WaylandUpdate};
|
||||||
|
use cctk::sctk::reexports::calloop;
|
||||||
use cosmic::app::{Core, Settings, Task};
|
use cosmic::app::{Core, Settings, Task};
|
||||||
use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity;
|
use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity;
|
||||||
use cosmic::iced::{Point, Size};
|
use cosmic::iced::{Point, Size};
|
||||||
|
|
@ -29,6 +31,10 @@ use cosmic::{
|
||||||
};
|
};
|
||||||
use cosmic_greeter_config::Config as CosmicGreeterConfig;
|
use cosmic_greeter_config::Config as CosmicGreeterConfig;
|
||||||
use cosmic_greeter_daemon::UserData;
|
use cosmic_greeter_daemon::UserData;
|
||||||
|
use cosmic_settings_subscriptions::{
|
||||||
|
accessibility::{self, DBusRequest, DBusUpdate},
|
||||||
|
cosmic_a11y_manager::{AccessibilityEvent, AccessibilityRequest, ColorFilter},
|
||||||
|
};
|
||||||
use greetd_ipc::Request;
|
use greetd_ipc::Request;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -41,7 +47,7 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use tokio::time;
|
use tokio::{sync::mpsc::UnboundedSender, time};
|
||||||
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
||||||
use zbus::{Connection, proxy};
|
use zbus::{Connection, proxy};
|
||||||
|
|
||||||
|
|
@ -316,6 +322,7 @@ impl DialogPage {
|
||||||
///TODO: this is custom code that should be better handled by libcosmic
|
///TODO: this is custom code that should be better handled by libcosmic
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum Dropdown {
|
pub enum Dropdown {
|
||||||
|
Accessibility,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
User,
|
User,
|
||||||
Session,
|
Session,
|
||||||
|
|
@ -332,6 +339,7 @@ struct NameIndexPair {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
Common(common::Message),
|
Common(common::Message),
|
||||||
|
DBusUpdate(DBusUpdate),
|
||||||
OutputEvent(OutputEvent, WlOutput),
|
OutputEvent(OutputEvent, WlOutput),
|
||||||
Auth(Option<String>),
|
Auth(Option<String>),
|
||||||
ConfigUpdateUser,
|
ConfigUpdateUser,
|
||||||
|
|
@ -354,6 +362,11 @@ pub enum Message {
|
||||||
Suspend,
|
Suspend,
|
||||||
Username(String),
|
Username(String),
|
||||||
EnterUser(bool, String),
|
EnterUser(bool, String),
|
||||||
|
ScreenReader(bool),
|
||||||
|
Magnifier(bool),
|
||||||
|
HighContrast(bool),
|
||||||
|
InvertColors(bool),
|
||||||
|
WaylandUpdate(WaylandUpdate),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<common::Message> for Message {
|
impl From<common::Message> for Message {
|
||||||
|
|
@ -376,6 +389,23 @@ pub struct App {
|
||||||
dropdown_opt: Option<Dropdown>,
|
dropdown_opt: Option<Dropdown>,
|
||||||
heartbeat_handle: Option<cosmic::iced::task::Handle>,
|
heartbeat_handle: Option<cosmic::iced::task::Handle>,
|
||||||
entering_name: bool,
|
entering_name: bool,
|
||||||
|
|
||||||
|
accessibility: Accessibility,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Accessibility {
|
||||||
|
pub dbus_sender: Option<UnboundedSender<DBusRequest>>,
|
||||||
|
pub wayland_sender: Option<calloop::channel::Sender<AccessibilityRequest>>,
|
||||||
|
pub wayland_protocol_version: Option<u32>,
|
||||||
|
|
||||||
|
pub state: cosmic_settings_daemon_config::greeter::GreeterAccessibilityState,
|
||||||
|
pub helper: Option<cosmic::cosmic_config::Config>,
|
||||||
|
|
||||||
|
pub screen_reader: bool,
|
||||||
|
pub magnifier: bool,
|
||||||
|
pub high_contrast: bool,
|
||||||
|
pub invert_colors: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
|
@ -414,7 +444,11 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: move code for custom dropdowns to libcosmic
|
//TODO: move code for custom dropdowns to libcosmic
|
||||||
let menu_checklist = |label, value, message| {
|
fn menu_checklist<'a>(
|
||||||
|
label: impl Into<std::borrow::Cow<'a, str>> + 'a,
|
||||||
|
value: bool,
|
||||||
|
message: Message,
|
||||||
|
) -> Element<'a, Message> {
|
||||||
Element::from(
|
Element::from(
|
||||||
widget::menu::menu_button(vec![
|
widget::menu::menu_button(vec![
|
||||||
if value {
|
if value {
|
||||||
|
|
@ -433,7 +467,7 @@ impl App {
|
||||||
])
|
])
|
||||||
.on_press(message),
|
.on_press(message),
|
||||||
)
|
)
|
||||||
};
|
}
|
||||||
let dropdown_menu = |items: Vec<_>| {
|
let dropdown_menu = |items: Vec<_>| {
|
||||||
let item_cnt = items.len();
|
let item_cnt = items.len();
|
||||||
|
|
||||||
|
|
@ -544,14 +578,49 @@ impl App {
|
||||||
session_button = session_button.popup(dropdown_menu(items));
|
session_button = session_button.popup(dropdown_menu(items));
|
||||||
}
|
}
|
||||||
|
|
||||||
let button_row = iced::widget::row![
|
// Accessibility menu as a popup dialog
|
||||||
/*TODO: greeter accessibility options
|
let mut accessibility_dropdown = widget::popover(
|
||||||
widget::button(widget::icon::from_name(
|
widget::button::custom(widget::icon::from_name(
|
||||||
"applications-accessibility-symbolic"
|
"applications-accessibility-symbolic",
|
||||||
))
|
))
|
||||||
.padding(12.0)
|
.padding(12.0)
|
||||||
.on_press(Message::None),
|
.on_press(Message::DropdownToggle(Dropdown::Accessibility)), // We'll use Dropdown::Keyboard as a dummy, since we don't have a dedicated Dropdown for accessibility
|
||||||
*/
|
)
|
||||||
|
.position(widget::popover::Position::Bottom);
|
||||||
|
|
||||||
|
if matches!(self.dropdown_opt, Some(Dropdown::Accessibility)) {
|
||||||
|
let mut items = Vec::new();
|
||||||
|
items.push(menu_checklist(
|
||||||
|
fl!("accessibility", "screen-reader"),
|
||||||
|
self.accessibility.screen_reader,
|
||||||
|
Message::ScreenReader(!self.accessibility.screen_reader),
|
||||||
|
));
|
||||||
|
items.push(menu_checklist(
|
||||||
|
fl!("accessibility", "magnifier"),
|
||||||
|
self.accessibility.magnifier,
|
||||||
|
Message::Magnifier(!self.accessibility.magnifier),
|
||||||
|
));
|
||||||
|
items.push(menu_checklist(
|
||||||
|
fl!("accessibility", "high-contrast"),
|
||||||
|
self.accessibility.high_contrast,
|
||||||
|
Message::HighContrast(!self.accessibility.high_contrast),
|
||||||
|
));
|
||||||
|
items.push(menu_checklist(
|
||||||
|
fl!("accessibility", "invert-colors"),
|
||||||
|
self.accessibility.invert_colors,
|
||||||
|
Message::InvertColors(!self.accessibility.invert_colors),
|
||||||
|
));
|
||||||
|
accessibility_dropdown = accessibility_dropdown.popup(dropdown_menu(items));
|
||||||
|
}
|
||||||
|
|
||||||
|
let accessibility_button = accessibility_dropdown;
|
||||||
|
|
||||||
|
let button_row = iced::widget::row![
|
||||||
|
widget::tooltip(
|
||||||
|
accessibility_button,
|
||||||
|
text(fl!("accessibility")),
|
||||||
|
widget::tooltip::Position::Top
|
||||||
|
),
|
||||||
widget::tooltip(
|
widget::tooltip(
|
||||||
input_button,
|
input_button,
|
||||||
text(fl!("keyboard-layout")),
|
text(fl!("keyboard-layout")),
|
||||||
|
|
@ -871,6 +940,10 @@ impl cosmic::Application for App {
|
||||||
|
|
||||||
/// Creates the application, and optionally emits command on initialize.
|
/// Creates the application, and optionally emits command on initialize.
|
||||||
fn init(core: Core, flags: Self::Flags) -> (Self, Task<Message>) {
|
fn init(core: Core, flags: Self::Flags) -> (Self, Task<Message>) {
|
||||||
|
// init state that is communicated to cosmic session
|
||||||
|
if let Err(err) = crate::state::init() {
|
||||||
|
log::error!("{err:?}");
|
||||||
|
}
|
||||||
let (mut common, common_task) = Common::init(core);
|
let (mut common, common_task) = Common::init(core);
|
||||||
common.on_output_event = Some(Box::new(|output_event, output| {
|
common.on_output_event = Some(Box::new(|output_event, output| {
|
||||||
Message::OutputEvent(output_event, output)
|
Message::OutputEvent(output_event, output)
|
||||||
|
|
@ -917,6 +990,9 @@ impl cosmic::Application for App {
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let data_idx = Some(0);
|
let data_idx = Some(0);
|
||||||
let selected_username = NameIndexPair { username, data_idx };
|
let selected_username = NameIndexPair { username, data_idx };
|
||||||
|
let mut accessibility = Accessibility::default();
|
||||||
|
accessibility.helper =
|
||||||
|
cosmic_settings_daemon_config::greeter::GreeterAccessibilityState::config().ok();
|
||||||
|
|
||||||
let app = App {
|
let app = App {
|
||||||
common,
|
common,
|
||||||
|
|
@ -931,6 +1007,7 @@ impl cosmic::Application for App {
|
||||||
dropdown_opt: None,
|
dropdown_opt: None,
|
||||||
heartbeat_handle: None,
|
heartbeat_handle: None,
|
||||||
entering_name: false,
|
entering_name: false,
|
||||||
|
accessibility,
|
||||||
};
|
};
|
||||||
(app, common_task)
|
(app, common_task)
|
||||||
}
|
}
|
||||||
|
|
@ -941,6 +1018,20 @@ impl cosmic::Application for App {
|
||||||
Message::Common(common_message) => {
|
Message::Common(common_message) => {
|
||||||
return self.common.update(common_message);
|
return self.common.update(common_message);
|
||||||
}
|
}
|
||||||
|
Message::DBusUpdate(update) => match update {
|
||||||
|
DBusUpdate::Error(err) => {
|
||||||
|
log::error!("{err}");
|
||||||
|
let _ = self.accessibility.dbus_sender.take();
|
||||||
|
self.accessibility.screen_reader = false;
|
||||||
|
}
|
||||||
|
DBusUpdate::Status(enabled) => {
|
||||||
|
self.accessibility.screen_reader = enabled;
|
||||||
|
}
|
||||||
|
DBusUpdate::Init(enabled, tx) => {
|
||||||
|
self.accessibility.screen_reader = enabled;
|
||||||
|
self.accessibility.dbus_sender = Some(tx);
|
||||||
|
}
|
||||||
|
},
|
||||||
Message::OutputEvent(output_event, output) => {
|
Message::OutputEvent(output_event, output) => {
|
||||||
match output_event {
|
match output_event {
|
||||||
OutputEvent::Created(output_info_opt) => {
|
OutputEvent::Created(output_info_opt) => {
|
||||||
|
|
@ -1366,6 +1457,60 @@ impl cosmic::Application for App {
|
||||||
cosmic::app::Action::Surface(a),
|
cosmic::app::Action::Surface(a),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Message::ScreenReader(enabled) => {
|
||||||
|
if let Some(tx) = &self.accessibility.dbus_sender.as_ref() {
|
||||||
|
self.accessibility.screen_reader = enabled;
|
||||||
|
let _ = tx.send(DBusRequest::Status(enabled));
|
||||||
|
} else {
|
||||||
|
self.accessibility.screen_reader = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::Magnifier(enabled) => {
|
||||||
|
if let Some(tx) = &self.accessibility.wayland_sender {
|
||||||
|
self.accessibility.magnifier = enabled;
|
||||||
|
let _ = tx.send(AccessibilityRequest::Magnifier(enabled));
|
||||||
|
} else {
|
||||||
|
self.accessibility.magnifier = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::HighContrast(enabled) => {
|
||||||
|
self.accessibility.high_contrast = enabled;
|
||||||
|
}
|
||||||
|
Message::InvertColors(enabled) => {
|
||||||
|
if let Some(tx) = &self.accessibility.wayland_sender {
|
||||||
|
self.accessibility.invert_colors = enabled;
|
||||||
|
let _ = tx.send(AccessibilityRequest::ScreenFilter {
|
||||||
|
inverted: enabled,
|
||||||
|
filter: None,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.accessibility.invert_colors = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::WaylandUpdate(update) => match update {
|
||||||
|
WaylandUpdate::Errored => {
|
||||||
|
let _ = self.accessibility.wayland_sender.take();
|
||||||
|
self.accessibility.wayland_protocol_version = None;
|
||||||
|
self.accessibility.magnifier = false;
|
||||||
|
self.accessibility.invert_colors = false;
|
||||||
|
}
|
||||||
|
WaylandUpdate::State(AccessibilityEvent::Bound(ver)) => {
|
||||||
|
self.accessibility.wayland_protocol_version = Some(ver);
|
||||||
|
}
|
||||||
|
WaylandUpdate::State(AccessibilityEvent::Magnifier(enabled)) => {
|
||||||
|
self.accessibility.magnifier = enabled;
|
||||||
|
}
|
||||||
|
WaylandUpdate::State(AccessibilityEvent::ScreenFilter { inverted, .. }) => {
|
||||||
|
self.accessibility.invert_colors = inverted;
|
||||||
|
}
|
||||||
|
WaylandUpdate::State(AccessibilityEvent::Closed) => {
|
||||||
|
self.accessibility.wayland_sender = None;
|
||||||
|
self.accessibility.wayland_protocol_version = None;
|
||||||
|
}
|
||||||
|
WaylandUpdate::Started(tx) => {
|
||||||
|
self.accessibility.wayland_sender = Some(tx);
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -1393,6 +1538,8 @@ impl cosmic::Application for App {
|
||||||
Subscription::batch([
|
Subscription::batch([
|
||||||
self.common.subscription().map(Message::from),
|
self.common.subscription().map(Message::from),
|
||||||
ipc::subscription(),
|
ipc::subscription(),
|
||||||
|
wayland::a11y_subscription().map(Message::WaylandUpdate),
|
||||||
|
accessibility::subscription().map(Message::DBusUpdate),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
pub mod greeter;
|
pub mod greeter;
|
||||||
pub mod locker;
|
pub mod locker;
|
||||||
|
|
||||||
|
mod wayland;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
mod localize;
|
mod localize;
|
||||||
|
|
@ -17,4 +19,6 @@ mod networkmanager;
|
||||||
#[cfg(feature = "upower")]
|
#[cfg(feature = "upower")]
|
||||||
mod upower;
|
mod upower;
|
||||||
|
|
||||||
|
mod state;
|
||||||
|
|
||||||
mod time;
|
mod time;
|
||||||
|
|
|
||||||
8
src/state.rs
Normal file
8
src/state.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
use std::os::unix::fs::PermissionsExt as _;
|
||||||
|
|
||||||
|
pub fn init() -> anyhow::Result<()> {
|
||||||
|
let path = cosmic_settings_daemon_config::greeter::GreeterAccessibilityState::path();
|
||||||
|
std::fs::create_dir_all(&path)?;
|
||||||
|
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o755))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
86
src/wayland/mod.rs
Normal file
86
src/wayland/mod.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use anyhow;
|
||||||
|
use cctk::sctk::reexports::calloop;
|
||||||
|
use cosmic::iced::{
|
||||||
|
self, Subscription,
|
||||||
|
futures::{self, SinkExt},
|
||||||
|
stream,
|
||||||
|
};
|
||||||
|
use cosmic_settings_subscriptions::cosmic_a11y_manager::{
|
||||||
|
self as thread, AccessibilityEvent, AccessibilityRequest,
|
||||||
|
};
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub static WAYLAND_RX: LazyLock<Mutex<Option<tokio::sync::mpsc::Receiver<AccessibilityEvent>>>> =
|
||||||
|
LazyLock::new(|| Mutex::new(None));
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum WaylandUpdate {
|
||||||
|
State(AccessibilityEvent),
|
||||||
|
Started(calloop::channel::Sender<AccessibilityRequest>),
|
||||||
|
Errored,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn a11y_subscription() -> iced::Subscription<WaylandUpdate> {
|
||||||
|
Subscription::run_with_id(
|
||||||
|
std::any::TypeId::of::<WaylandUpdate>(),
|
||||||
|
stream::channel(50, move |mut output| async move {
|
||||||
|
let mut state = State::Waiting;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
state = start_listening(state, &mut output).await;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_listening(
|
||||||
|
state: State,
|
||||||
|
output: &mut futures::channel::mpsc::Sender<WaylandUpdate>,
|
||||||
|
) -> State {
|
||||||
|
match state {
|
||||||
|
State::Waiting => {
|
||||||
|
let mut guard = WAYLAND_RX.lock().await;
|
||||||
|
let rx = {
|
||||||
|
if guard.is_none() {
|
||||||
|
if let Ok(WaylandWatcher { rx, tx }) = WaylandWatcher::new() {
|
||||||
|
*guard = Some(rx);
|
||||||
|
_ = output.send(WaylandUpdate::Started(tx)).await;
|
||||||
|
} else {
|
||||||
|
_ = output.send(WaylandUpdate::Errored).await;
|
||||||
|
return State::Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guard.as_mut().unwrap()
|
||||||
|
};
|
||||||
|
if let Some(w) = rx.recv().await {
|
||||||
|
_ = output.send(WaylandUpdate::State(w)).await;
|
||||||
|
State::Waiting
|
||||||
|
} else {
|
||||||
|
_ = output.send(WaylandUpdate::Errored).await;
|
||||||
|
State::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
State::Error => cosmic::iced::futures::future::pending().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum State {
|
||||||
|
Waiting,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WaylandWatcher {
|
||||||
|
rx: tokio::sync::mpsc::Receiver<AccessibilityEvent>,
|
||||||
|
tx: calloop::channel::Sender<AccessibilityRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WaylandWatcher {
|
||||||
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
|
let (tx, rx) = thread::spawn_wayland_connection(1)?;
|
||||||
|
Ok(Self { tx, rx })
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue