wayland: Implement cosmic-a11y-v1
This commit is contained in:
parent
7af3650b83
commit
c45a58c16c
8 changed files with 223 additions and 22 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
|
@ -786,7 +786,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cosmic-client-toolkit"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/cosmic-protocols?rev=178eb0b#178eb0b14a0e5c192f64f6dee6c40341a8e5ee51"
|
||||
source = "git+https://github.com/pop-os//cosmic-protocols?rev=ed2a481#ed2a48143cd6dc63274aa04461de3d341e50b16b"
|
||||
dependencies = [
|
||||
"cosmic-protocols",
|
||||
"libc",
|
||||
|
|
@ -906,7 +906,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cosmic-protocols"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/cosmic-protocols?rev=178eb0b#178eb0b14a0e5c192f64f6dee6c40341a8e5ee51"
|
||||
source = "git+https://github.com/pop-os//cosmic-protocols?rev=ed2a481#ed2a48143cd6dc63274aa04461de3d341e50b16b"
|
||||
dependencies = [
|
||||
"bitflags 2.7.0",
|
||||
"wayland-backend",
|
||||
|
|
@ -1466,7 +1466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2911,7 +2911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.48.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4385,7 +4385,7 @@ dependencies = [
|
|||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4985,7 +4985,7 @@ dependencies = [
|
|||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5278,7 +5278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"windows-targets 0.48.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ bytemuck = "1.12"
|
|||
calloop = {version = "0.14.1", features = ["executor"]}
|
||||
cosmic-comp-config = {path = "cosmic-comp-config"}
|
||||
cosmic-config = {git = "https://github.com/pop-os/libcosmic/", features = ["calloop", "macro"]}
|
||||
cosmic-protocols = {git = "https://github.com/pop-os/cosmic-protocols", rev = "178eb0b", default-features = false, features = ["server"]}
|
||||
cosmic-protocols = {git = "https://github.com/pop-os/cosmic-protocols", rev = "ed2a481", default-features = false, features = ["server"]}
|
||||
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon" }
|
||||
libdisplay-info = "0.2.0"
|
||||
egui = {version = "0.30.0", optional = true}
|
||||
|
|
@ -115,4 +115,8 @@ inherits = "release"
|
|||
lto = "fat"
|
||||
|
||||
[patch.crates-io]
|
||||
smithay = { git = "https://github.com/smithay/smithay.git", rev = "f93476c" }
|
||||
smithay = { git = "https://github.com/smithay/smithay.git", rev = "f93476c" }
|
||||
|
||||
[patch."https://github.com/pop-os/cosmic-protocols"]
|
||||
cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", rev = "ed2a481" }
|
||||
cosmic-client-toolkit = { git = "https://github.com/pop-os//cosmic-protocols", rev = "ed2a481" }
|
||||
|
|
@ -2034,6 +2034,14 @@ impl Shell {
|
|||
1.
|
||||
};
|
||||
|
||||
let toggled = previous_level != level && (previous_level == 1.0 || level == 1.0);
|
||||
if toggled {
|
||||
let value = previous_level == 1.0;
|
||||
let _ = loop_handle.insert_idle(move |state| {
|
||||
state.common.a11y_state.set_screen_magnifier(value);
|
||||
});
|
||||
}
|
||||
|
||||
self.zoom_state = Some(ZoomState {
|
||||
seat: seat.clone(),
|
||||
level,
|
||||
|
|
|
|||
33
src/state.rs
33
src/state.rs
|
|
@ -11,18 +11,21 @@ use crate::{
|
|||
input::{gestures::GestureState, PointerFocusState},
|
||||
shell::{grabs::SeatMoveGrabState, CosmicSurface, SeatExt, Shell},
|
||||
utils::prelude::OutputExt,
|
||||
wayland::handlers::screencopy::SessionHolder,
|
||||
wayland::protocols::{
|
||||
atspi::AtspiState,
|
||||
drm::WlDrmState,
|
||||
image_source::ImageSourceState,
|
||||
output_configuration::OutputConfigurationState,
|
||||
output_power::OutputPowerState,
|
||||
overlap_notify::OverlapNotifyState,
|
||||
screencopy::ScreencopyState,
|
||||
toplevel_info::ToplevelInfoState,
|
||||
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
|
||||
workspace::{WorkspaceClientState, WorkspaceState, WorkspaceUpdateGuard},
|
||||
wayland::{
|
||||
handlers::screencopy::SessionHolder,
|
||||
protocols::{
|
||||
a11y::A11yState,
|
||||
atspi::AtspiState,
|
||||
drm::WlDrmState,
|
||||
image_source::ImageSourceState,
|
||||
output_configuration::OutputConfigurationState,
|
||||
output_power::OutputPowerState,
|
||||
overlap_notify::OverlapNotifyState,
|
||||
screencopy::ScreencopyState,
|
||||
toplevel_info::ToplevelInfoState,
|
||||
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
|
||||
workspace::{WorkspaceClientState, WorkspaceState, WorkspaceUpdateGuard},
|
||||
},
|
||||
},
|
||||
xwayland::XWaylandState,
|
||||
};
|
||||
|
|
@ -223,6 +226,7 @@ pub struct Common {
|
|||
pub kde_decoration_state: KdeDecorationState,
|
||||
pub xdg_decoration_state: XdgDecorationState,
|
||||
pub overlap_notify_state: OverlapNotifyState,
|
||||
pub a11y_state: A11yState,
|
||||
|
||||
// shell-related wayland state
|
||||
pub xdg_shell_state: XdgShellState,
|
||||
|
|
@ -581,8 +585,10 @@ impl State {
|
|||
tracing::warn!(?err, "Failed to initialize dbus handlers");
|
||||
}
|
||||
|
||||
let a11y_state = A11yState::new::<State, _>(dh, client_is_privileged);
|
||||
|
||||
// TODO: Restrict to only specific client?
|
||||
let atspi_state = AtspiState::new::<State, _>(dh, client_is_privileged);
|
||||
let atspi_state = AtspiState::new::<State, _>(dh, |_| true);
|
||||
|
||||
State {
|
||||
common: Common {
|
||||
|
|
@ -638,6 +644,7 @@ impl State {
|
|||
xdg_activation_state,
|
||||
xdg_foreign_state,
|
||||
workspace_state,
|
||||
a11y_state,
|
||||
xwayland_scale: None,
|
||||
xwayland_state: None,
|
||||
xwayland_shell_state,
|
||||
|
|
|
|||
38
src/wayland/handlers/a11y.rs
Normal file
38
src/wayland/handlers/a11y.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use crate::{
|
||||
state::State,
|
||||
wayland::protocols::a11y::{delegate_a11y, A11yHandler, A11yState},
|
||||
};
|
||||
|
||||
impl A11yHandler for State {
|
||||
fn a11y_state(&mut self) -> &mut A11yState {
|
||||
&mut self.common.a11y_state
|
||||
}
|
||||
|
||||
fn request_screen_magnifier(&mut self, enabled: bool) {
|
||||
let mut shell = self.common.shell.write().unwrap();
|
||||
|
||||
if shell
|
||||
.zoom_state()
|
||||
.is_some_and(|state| state.current_level() != 1.0)
|
||||
!= enabled
|
||||
{
|
||||
let seat = shell.seats.last_active().clone();
|
||||
let level = if enabled {
|
||||
self.common.config.dynamic_conf.zoom_state().last_level
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
let zoom_config = &self.common.config.cosmic_conf.accessibility_zoom;
|
||||
|
||||
shell.trigger_zoom(
|
||||
&seat,
|
||||
level,
|
||||
zoom_config,
|
||||
true,
|
||||
&self.common.event_loop_handle,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate_a11y!(State);
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
pub mod a11y;
|
||||
pub mod alpha_modifier;
|
||||
pub mod atspi;
|
||||
pub mod buffer;
|
||||
|
|
|
|||
142
src/wayland/protocols/a11y.rs
Normal file
142
src/wayland/protocols/a11y.rs
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use cosmic_protocols::a11y::v1::server::cosmic_a11y_manager_v1;
|
||||
use smithay::reexports::wayland_server::{
|
||||
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New,
|
||||
};
|
||||
use wayland_backend::server::GlobalId;
|
||||
|
||||
pub trait A11yHandler {
|
||||
fn a11y_state(&mut self) -> &mut A11yState;
|
||||
|
||||
fn request_screen_magnifier(&mut self, enabled: bool);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct A11yState {
|
||||
global: GlobalId,
|
||||
instances: Vec<cosmic_a11y_manager_v1::CosmicA11yManagerV1>,
|
||||
|
||||
magnifier_state: bool,
|
||||
}
|
||||
|
||||
impl A11yState {
|
||||
pub fn new<D, F>(dh: &DisplayHandle, client_filter: F) -> A11yState
|
||||
where
|
||||
D: GlobalDispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, A11yGlobalData> + 'static,
|
||||
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
||||
{
|
||||
let global = dh.create_global::<D, cosmic_a11y_manager_v1::CosmicA11yManagerV1, _>(
|
||||
1,
|
||||
A11yGlobalData {
|
||||
filter: Box::new(client_filter),
|
||||
},
|
||||
);
|
||||
A11yState {
|
||||
global,
|
||||
instances: Vec::new(),
|
||||
|
||||
magnifier_state: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn global_id(&self) -> GlobalId {
|
||||
self.global.clone()
|
||||
}
|
||||
|
||||
pub fn set_screen_magnifier(&mut self, enabled: bool) {
|
||||
self.magnifier_state = enabled;
|
||||
|
||||
for instance in &self.instances {
|
||||
instance.magnifier(if enabled {
|
||||
cosmic_a11y_manager_v1::ActiveState::Enabled
|
||||
} else {
|
||||
cosmic_a11y_manager_v1::ActiveState::Disabled
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct A11yGlobalData {
|
||||
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
|
||||
}
|
||||
|
||||
impl<D> GlobalDispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, A11yGlobalData, D> for A11yState
|
||||
where
|
||||
D: GlobalDispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, A11yGlobalData>
|
||||
+ Dispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, ()>
|
||||
+ A11yHandler
|
||||
+ 'static,
|
||||
{
|
||||
fn bind(
|
||||
state: &mut D,
|
||||
_handle: &DisplayHandle,
|
||||
_client: &Client,
|
||||
resource: New<cosmic_a11y_manager_v1::CosmicA11yManagerV1>,
|
||||
_global_data: &A11yGlobalData,
|
||||
data_init: &mut DataInit<'_, D>,
|
||||
) {
|
||||
let instance = data_init.init(resource, ());
|
||||
let state = state.a11y_state();
|
||||
|
||||
instance.magnifier(if state.magnifier_state {
|
||||
cosmic_a11y_manager_v1::ActiveState::Enabled
|
||||
} else {
|
||||
cosmic_a11y_manager_v1::ActiveState::Disabled
|
||||
});
|
||||
|
||||
state.instances.push(instance);
|
||||
}
|
||||
|
||||
fn can_view(client: Client, global_data: &A11yGlobalData) -> bool {
|
||||
(global_data.filter)(&client)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> Dispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, (), D> for A11yState
|
||||
where
|
||||
D: Dispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, ()> + A11yHandler + 'static,
|
||||
{
|
||||
fn request(
|
||||
state: &mut D,
|
||||
_client: &Client,
|
||||
_resource: &cosmic_a11y_manager_v1::CosmicA11yManagerV1,
|
||||
request: <cosmic_a11y_manager_v1::CosmicA11yManagerV1 as smithay::reexports::wayland_server::Resource>::Request,
|
||||
_data: &(),
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, D>,
|
||||
) {
|
||||
match request {
|
||||
cosmic_a11y_manager_v1::Request::SetMagnifier { active } => {
|
||||
state.request_screen_magnifier(
|
||||
active
|
||||
.into_result()
|
||||
.unwrap_or(cosmic_a11y_manager_v1::ActiveState::Disabled)
|
||||
== cosmic_a11y_manager_v1::ActiveState::Enabled,
|
||||
);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn destroyed(
|
||||
state: &mut D,
|
||||
_client: wayland_backend::server::ClientId,
|
||||
resource: &cosmic_a11y_manager_v1::CosmicA11yManagerV1,
|
||||
_data: &(),
|
||||
) {
|
||||
state.a11y_state().instances.retain(|i| i != resource);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! delegate_a11y {
|
||||
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
|
||||
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||
cosmic_protocols::a11y::v1::server::cosmic_a11y_manager_v1::CosmicA11yManagerV1: $crate::wayland::protocols::a11y::A11yGlobalData
|
||||
] => $crate::wayland::protocols::a11y::A11yState);
|
||||
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||
cosmic_protocols::a11y::v1::server::cosmic_a11y_manager_v1::CosmicA11yManagerV1: ()
|
||||
] => $crate::wayland::protocols::a11y::A11yState);
|
||||
};
|
||||
}
|
||||
pub(crate) use delegate_a11y;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
pub mod a11y;
|
||||
pub mod atspi;
|
||||
pub mod drm;
|
||||
pub mod image_source;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue