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]]
|
[[package]]
|
||||||
name = "cosmic-client-toolkit"
|
name = "cosmic-client-toolkit"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"cosmic-protocols",
|
"cosmic-protocols",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -906,7 +906,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-protocols"
|
name = "cosmic-protocols"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"bitflags 2.7.0",
|
"bitflags 2.7.0",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
|
|
@ -1466,7 +1466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2911,7 +2911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4385,7 +4385,7 @@ dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.4.15",
|
"linux-raw-sys 0.4.15",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4985,7 +4985,7 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -5278,7 +5278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f"
|
checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ bytemuck = "1.12"
|
||||||
calloop = {version = "0.14.1", features = ["executor"]}
|
calloop = {version = "0.14.1", features = ["executor"]}
|
||||||
cosmic-comp-config = {path = "cosmic-comp-config"}
|
cosmic-comp-config = {path = "cosmic-comp-config"}
|
||||||
cosmic-config = {git = "https://github.com/pop-os/libcosmic/", features = ["calloop", "macro"]}
|
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" }
|
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon" }
|
||||||
libdisplay-info = "0.2.0"
|
libdisplay-info = "0.2.0"
|
||||||
egui = {version = "0.30.0", optional = true}
|
egui = {version = "0.30.0", optional = true}
|
||||||
|
|
@ -116,3 +116,7 @@ lto = "fat"
|
||||||
|
|
||||||
[patch.crates-io]
|
[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.
|
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 {
|
self.zoom_state = Some(ZoomState {
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
level,
|
level,
|
||||||
|
|
|
||||||
33
src/state.rs
33
src/state.rs
|
|
@ -11,18 +11,21 @@ use crate::{
|
||||||
input::{gestures::GestureState, PointerFocusState},
|
input::{gestures::GestureState, PointerFocusState},
|
||||||
shell::{grabs::SeatMoveGrabState, CosmicSurface, SeatExt, Shell},
|
shell::{grabs::SeatMoveGrabState, CosmicSurface, SeatExt, Shell},
|
||||||
utils::prelude::OutputExt,
|
utils::prelude::OutputExt,
|
||||||
wayland::handlers::screencopy::SessionHolder,
|
wayland::{
|
||||||
wayland::protocols::{
|
handlers::screencopy::SessionHolder,
|
||||||
atspi::AtspiState,
|
protocols::{
|
||||||
drm::WlDrmState,
|
a11y::A11yState,
|
||||||
image_source::ImageSourceState,
|
atspi::AtspiState,
|
||||||
output_configuration::OutputConfigurationState,
|
drm::WlDrmState,
|
||||||
output_power::OutputPowerState,
|
image_source::ImageSourceState,
|
||||||
overlap_notify::OverlapNotifyState,
|
output_configuration::OutputConfigurationState,
|
||||||
screencopy::ScreencopyState,
|
output_power::OutputPowerState,
|
||||||
toplevel_info::ToplevelInfoState,
|
overlap_notify::OverlapNotifyState,
|
||||||
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
|
screencopy::ScreencopyState,
|
||||||
workspace::{WorkspaceClientState, WorkspaceState, WorkspaceUpdateGuard},
|
toplevel_info::ToplevelInfoState,
|
||||||
|
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
|
||||||
|
workspace::{WorkspaceClientState, WorkspaceState, WorkspaceUpdateGuard},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
xwayland::XWaylandState,
|
xwayland::XWaylandState,
|
||||||
};
|
};
|
||||||
|
|
@ -223,6 +226,7 @@ pub struct Common {
|
||||||
pub kde_decoration_state: KdeDecorationState,
|
pub kde_decoration_state: KdeDecorationState,
|
||||||
pub xdg_decoration_state: XdgDecorationState,
|
pub xdg_decoration_state: XdgDecorationState,
|
||||||
pub overlap_notify_state: OverlapNotifyState,
|
pub overlap_notify_state: OverlapNotifyState,
|
||||||
|
pub a11y_state: A11yState,
|
||||||
|
|
||||||
// shell-related wayland state
|
// shell-related wayland state
|
||||||
pub xdg_shell_state: XdgShellState,
|
pub xdg_shell_state: XdgShellState,
|
||||||
|
|
@ -581,8 +585,10 @@ impl State {
|
||||||
tracing::warn!(?err, "Failed to initialize dbus handlers");
|
tracing::warn!(?err, "Failed to initialize dbus handlers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let a11y_state = A11yState::new::<State, _>(dh, client_is_privileged);
|
||||||
|
|
||||||
// TODO: Restrict to only specific client?
|
// 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 {
|
State {
|
||||||
common: Common {
|
common: Common {
|
||||||
|
|
@ -638,6 +644,7 @@ impl State {
|
||||||
xdg_activation_state,
|
xdg_activation_state,
|
||||||
xdg_foreign_state,
|
xdg_foreign_state,
|
||||||
workspace_state,
|
workspace_state,
|
||||||
|
a11y_state,
|
||||||
xwayland_scale: None,
|
xwayland_scale: None,
|
||||||
xwayland_state: None,
|
xwayland_state: None,
|
||||||
xwayland_shell_state,
|
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
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
pub mod a11y;
|
||||||
pub mod alpha_modifier;
|
pub mod alpha_modifier;
|
||||||
pub mod atspi;
|
pub mod atspi;
|
||||||
pub mod buffer;
|
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
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
pub mod a11y;
|
||||||
pub mod atspi;
|
pub mod atspi;
|
||||||
pub mod drm;
|
pub mod drm;
|
||||||
pub mod image_source;
|
pub mod image_source;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue