a11y refactor

This commit is contained in:
Ashley Wulber 2026-02-04 15:38:07 -05:00
parent c40264a6ed
commit b4346ff3ca
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
6 changed files with 107 additions and 232 deletions

View file

@ -28,7 +28,7 @@ wgpu-bare = ["iced_renderer/wgpu-bare", "iced_widget/wgpu"]
# Enables the `tiny-skia` software renderer # Enables the `tiny-skia` software renderer
default = ["tiny-skia", "tokio", "wayland", "x11"] default = ["a11y", "tiny-skia", "tokio", "wayland", "x11"]
# Enable the `tiny-skia` software renderer backend # Enable the `tiny-skia` software renderer backend
tiny-skia = ["iced_renderer/tiny-skia"] tiny-skia = ["iced_renderer/tiny-skia"]
# Enables the `image` widget # Enables the `image` widget
@ -245,7 +245,6 @@ cosmic-text = { git = "https://github.com/pop-os/cosmic-text.git" }
dark-light = "1.0" dark-light = "1.0"
cryoglyph = { package = "cryoglyph", git = "https://github.com/pop-os/glyphon.git", branch = "iced-0.14" } cryoglyph = { package = "cryoglyph", git = "https://github.com/pop-os/glyphon.git", branch = "iced-0.14" }
resvg = "0.45" resvg = "0.45"
# glyphon = { package = "iced_glyphon", path = "../../../glyphon" }
web-sys = "0.3.69" web-sys = "0.3.69"
guillotiere = "0.6" guillotiere = "0.6"
half = "2.2" half = "2.2"
@ -308,16 +307,9 @@ winapi = "0.3"
window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", tag = "pop-0.13-2" } window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", tag = "pop-0.13-2" }
dnd = { git = "https://github.com/pop-os/window_clipboard.git", tag = "pop-0.13-2" } dnd = { git = "https://github.com/pop-os/window_clipboard.git", tag = "pop-0.13-2" }
mime = { git = "https://github.com/pop-os/window_clipboard.git", tag = "pop-0.13-2" } mime = { git = "https://github.com/pop-os/window_clipboard.git", tag = "pop-0.13-2" }
# window_clipboard = { path = "../../window_clipboard", tag = "pop-0.13-2" } winit = { git = "https://github.com/pop-os/winit.git", branch = "iced-0.14-rebase" }
# dnd = { path = "../../window_clipboard/dnd", tag = "pop-0.13" } winit-core = { git = "https://github.com/pop-os/winit.git", branch = "iced-0.14-rebase" }
# mime = { path = "../../window_clipboard/mime", tag = "pop-0.13" }
# winit = { git = "https://github.com/pop-os/winit.git", tag = "iced-xdg-surface-0.13" }
winit = { path = "../../winit/winit" }
winit-core = { path = "../../winit/winit-core" }
cursor-icon = "1.1.0" cursor-icon = "1.1.0"
# winit = { git = "https://github.com/iced-rs/winit.git", rev = "254d6b3420ce4e674f516f7a2bd440665e05484d" }
# winit = { git = "https://github.com/rust-windowing/winit.git", rev = "241b7a80bba96c91fa3901729cd5dec66abb9be4" }
# winit = { path = "../../../winit" }
[workspace.lints.rust] [workspace.lints.rust]
@ -345,6 +337,3 @@ useless_conversion = "deny"
[workspace.lints.rustdoc] [workspace.lints.rustdoc]
broken_intra_doc_links = "forbid" broken_intra_doc_links = "forbid"
# [patch."https://github.com/rust-windowing/winit.git"]
# winit = { git = "https://github.com/rust-windowing/winit.git", rev = "241b7a80bba96c91fa3901729cd5dec66abb9be4" }
# winit = { path = "../../../winit" }

View file

@ -10,15 +10,15 @@ async-io = ["accesskit_winit?/async-io"]
tokio = ["accesskit_winit?/tokio"] tokio = ["accesskit_winit?/tokio"]
[dependencies] [dependencies]
# accesskit = { git = "https://github.com/wash2/accesskit", tag = "iced-xdg-surface-0.13" } accesskit = { git = "https://github.com/wash2/accesskit", branch = "iced-0.14" }
# accesskit_windows = { git = "https://github.com/wash2/accesskit", tag = "iced-xdg-surface-0.13", optional = true } accesskit_windows = { git = "https://github.com/wash2/accesskit", branch = "iced-0.14", optional = true }
# accesskit_macos = { git = "https://github.com/wash2/accesskit", tag = "iced-xdg-surface-0.13", optional = true } accesskit_macos = { git = "https://github.com/wash2/accesskit", branch = "iced-0.14", optional = true }
# accesskit_winit = { git = "https://github.com/wash2/accesskit", tag = "iced-xdg-surface-0.13", optional = true, default-features = false, features = [ accesskit_winit = { git = "https://github.com/wash2/accesskit", branch = "iced-0.14", optional = true, default-features = false, features = [
# "rwh_06",
# ] }
accesskit = { path = "../../../accesskit/common" }
accesskit_windows = { path = "../../../accesskit/platforms/windows", optional = true }
accesskit_macos = { path = "../../../accesskit/platforms/macos", optional = true }
accesskit_winit = { path = "../../../accesskit/platforms/winit", optional = true, default-features = false, features = [
"rwh_06", "rwh_06",
] } ] }
# accesskit = { path = "../../../accesskit/common" }
# accesskit_windows = { path = "../../../accesskit/platforms/windows", optional = true }
# accesskit_macos = { path = "../../../accesskit/platforms/macos", optional = true }
# accesskit_winit = { path = "../../../accesskit/platforms/winit", optional = true, default-features = false, features = [
# "rwh_06",
# ] }

View file

@ -15,5 +15,4 @@ iced = { path = "../..", default-features = false, features = [
"debug", "debug",
] } ] }
env_logger = "0.10" env_logger = "0.10"
# sctk = { package = "smithay-client-toolkit", path = "../../../fork/client-toolkit/" }
cctk.workspace = true cctk.workspace = true

View file

@ -170,7 +170,6 @@ where
sender: oneshot::Sender<()>, sender: oneshot::Sender<()>,
fonts: Vec<Cow<'static, [u8]>>, fonts: Vec<Cow<'static, [u8]>>,
graphics_settings: graphics::Settings, graphics_settings: graphics::Settings,
control_sender: mpsc::UnboundedSender<Control>,
is_wayland: bool, is_wayland: bool,
} }
struct Runner<Message: 'static, F> { struct Runner<Message: 'static, F> {
@ -182,6 +181,7 @@ where
receiver: mpsc::UnboundedReceiver<Control>, receiver: mpsc::UnboundedReceiver<Control>,
error: Option<Error>, error: Option<Error>,
system_theme: Option<oneshot::Sender<theme::Mode>>, system_theme: Option<oneshot::Sender<theme::Mode>>,
control_sender: mpsc::UnboundedSender<Control>,
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
is_booted: std::rc::Rc<std::cell::RefCell<bool>>, is_booted: std::rc::Rc<std::cell::RefCell<bool>>,
@ -196,12 +196,12 @@ where
sender: boot_sender, sender: boot_sender,
fonts: settings.fonts, fonts: settings.fonts,
graphics_settings, graphics_settings,
control_sender,
is_wayland, is_wayland,
}), }),
id: settings.id, id: settings.id,
sender: event_sender, sender: event_sender,
receiver: control_receiver, receiver: control_receiver,
control_sender: control_sender.clone(),
error: None, error: None,
system_theme: Some(system_theme_sender), system_theme: Some(system_theme_sender),
@ -284,7 +284,6 @@ where
sender, sender,
fonts, fonts,
graphics_settings, graphics_settings,
control_sender,
is_wayland, is_wayland,
}) = self.boot.take() }) = self.boot.take()
else { else {
@ -533,6 +532,53 @@ where
.start_send(Event::StartDnd) .start_send(Event::StartDnd)
.expect("Send event"); .expect("Send event");
} }
Control::InitAdapter(id, window) => {
#[cfg(feature = "a11y")]
{
use crate::a11y::*;
use iced_accessibility::accesskit::{
ActivationHandler, Node, NodeId, Role,
Tree, TreeUpdate,
};
use iced_accessibility::accesskit_winit::Adapter;
let node_id =
iced_runtime::core::id::window_node_id(
);
let activation_handler =
WinitActivationHandler {
proxy: self.control_sender.clone(),
title: String::new(),
};
let action_handler = WinitActionHandler {
id,
proxy: self.control_sender.clone(),
};
let deactivation_handler =
WinitDeactivationHandler {
proxy: self.control_sender.clone(),
};
self.sender
.start_send(Event::A11yAdapter(
id,
(
node_id,
Adapter::with_direct_handlers(
event_loop,
window.as_ref(),
activation_handler,
action_handler,
deactivation_handler,
),
),
))
.expect("send event");
}
}
}, },
_ => { _ => {
break; break;
@ -561,7 +607,6 @@ where
} }
} }
#[derive(Debug)]
enum Event<Message: 'static> { enum Event<Message: 'static> {
WindowCreated { WindowCreated {
id: window::Id, id: window::Id,
@ -576,6 +621,11 @@ enum Event<Message: 'static> {
Accessibility(window::Id, iced_accessibility::accesskit::ActionRequest), Accessibility(window::Id, iced_accessibility::accesskit::ActionRequest),
#[cfg(feature = "a11y")] #[cfg(feature = "a11y")]
AccessibilityEnabled(bool), AccessibilityEnabled(bool),
#[cfg(feature = "a11y")]
A11yAdapter(
window::Id,
(u64, iced_accessibility::accesskit_winit::Adapter),
),
Winit(winit::window::WindowId, winit::event::WindowEvent), Winit(winit::window::WindowId, winit::event::WindowEvent),
AboutToWait, AboutToWait,
UserEvent(Action<Message>), UserEvent(Action<Message>),
@ -584,7 +634,6 @@ enum Event<Message: 'static> {
StartDnd, StartDnd,
} }
#[derive(Debug)]
enum Control { enum Control {
ChangeFlow(winit::event_loop::ControlFlow), ChangeFlow(winit::event_loop::ControlFlow),
Exit, Exit,
@ -603,6 +652,8 @@ enum Control {
Accessibility(window::Id, iced_accessibility::accesskit::ActionRequest), Accessibility(window::Id, iced_accessibility::accesskit::ActionRequest),
#[cfg(feature = "a11y")] #[cfg(feature = "a11y")]
AccessibilityEnabled(bool), AccessibilityEnabled(bool),
#[cfg(feature = "a11y")]
InitAdapter(window::Id, Arc<dyn winit::window::Window>),
PlatformSpecific(crate::platform_specific::Event), PlatformSpecific(crate::platform_specific::Event),
AboutToWait, AboutToWait,
Winit(winit::window::WindowId, winit::event::WindowEvent), Winit(winit::window::WindowId, winit::event::WindowEvent),
@ -665,50 +716,6 @@ async fn run_instance<P>(
#[cfg(feature = "a11y")] #[cfg(feature = "a11y")]
let (mut adapters, mut a11y_enabled) = (Default::default(), false); let (mut adapters, mut a11y_enabled) = (Default::default(), false);
// let (mut adapters, mut a11y_enabled) = if let Some((main_id, title, raw)) =
// window_manager.ids().next().and_then(|id| {
// window_manager
// .get(id)
// .map(|w| (id, w.state.title.clone(), w.raw.clone()))
// }) {
// let node_id = core::id::window_node_id();
// use crate::a11y::*;
// use iced_accessibility::accesskit::{
// ActivationHandler, Node, NodeId, Role, Tree, TreeUpdate,
// };
// use iced_accessibility::accesskit_winit::Adapter;
// let activation_handler = WinitActivationHandler {
// proxy: control_sender.clone(),
// title: title.clone(),
// };
// let action_handler = WinitActionHandler {
// id: main_id,
// proxy: control_sender.clone(),
// };
// let deactivation_handler = WinitDeactivationHandler {
// proxy: control_sender.clone(),
// };
// (
// HashMap::from([(
// main_id,
// (
// node_id,
// Adapter::with_direct_handlers(
// raw.as_ref(),
// activation_handler,
// action_handler,
// deactivation_handler,
// ),
// ),
// )]),
// false,
// )
// } else {
// (Default::default(), false)
// };
#[cfg(all(feature = "linux-theme-detection", target_os = "linux"))] #[cfg(all(feature = "linux-theme-detection", target_os = "linux"))]
let mut system_theme = { let mut system_theme = {
@ -765,6 +772,10 @@ async fn run_instance<P>(
make_visible, make_visible,
on_open, on_open,
} => { } => {
#[cfg(feature = "a11y")]
control_sender
.start_send(Control::InitAdapter(id, window.clone()))
.expect("Send control message");
if compositor.is_none() { if compositor.is_none() {
let (compositor_sender, compositor_receiver) = let (compositor_sender, compositor_receiver) =
oneshot::channel(); oneshot::channel();
@ -1795,6 +1806,10 @@ async fn run_instance<P>(
} }
} }
} }
#[cfg(feature = "a11y")]
Event::A11yAdapter(id, adapter) => {
_ = adapters.insert(id, adapter);
}
_ => {} _ => {}
} }
} }

View file

@ -187,7 +187,7 @@ impl WaylandSpecific {
log::warn!("Missing calloop sender"); log::warn!("Missing calloop sender");
return Default::default(); return Default::default();
}; };
let Some(event_sender) = winit_event_sender.as_ref() else { let Some(event_sender) = winit_event_sender.as_mut() else {
log::warn!("Missing control sender"); log::warn!("Missing control sender");
return Default::default(); return Default::default();
}; };

View file

@ -353,7 +353,7 @@ impl SctkEvent {
>, >,
surface_ids: &mut HashMap<ObjectId, SurfaceIdWrapper>, surface_ids: &mut HashMap<ObjectId, SurfaceIdWrapper>,
sctk_tx: &channel::Sender<super::Action>, sctk_tx: &channel::Sender<super::Action>,
control_sender: &mpsc::UnboundedSender<Control>, control_sender: &mut mpsc::UnboundedSender<Control>,
proxy: &EventLoopProxy, proxy: &EventLoopProxy,
user_interfaces: &mut UserInterfaces<'a, P>, user_interfaces: &mut UserInterfaces<'a, P>,
events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>, events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
@ -759,45 +759,13 @@ impl SctkEvent {
display, display,
queue_handle, queue_handle,
); );
// TODO must move this to the winit handler, where we have access to the event loop #[cfg(feature = "a11y")]
// #[cfg(feature = "a11y")] control_sender
// { .start_send(Control::InitAdapter(
// use crate::a11y::*; surface_id,
// use iced_accessibility::accesskit::{ sctk_winit.clone(),
// ActivationHandler, Node, NodeId, Role, Tree, ))
// TreeUpdate, .expect("Send control message");
// };
// use iced_accessibility::accesskit_winit::Adapter;
// let node_id = iced_runtime::core::id::window_node_id();
// let activation_handler = WinitActivationHandler {
// proxy: control_sender.clone(),
// title: String::new(),
// };
// let action_handler = WinitActionHandler {
// id: surface_id,
// proxy: control_sender.clone(),
// };
// let deactivation_handler = WinitDeactivationHandler {
// proxy: control_sender.clone(),
// };
// _ = adapters.insert(
// surface_id,
// (
// node_id,
// Adapter::with_direct_handlers(
// event_loop,
// sctk_winit.as_ref(),
// activation_handler,
// action_handler,
// deactivation_handler,
// ),
// ),
// );
// }
let window = window_manager.insert( let window = window_manager.insert(
surface_id, surface_id,
@ -991,47 +959,13 @@ impl SctkEvent {
display, display,
queue_handle, queue_handle,
); );
// TODO must move this to the winit handler, where we have access to the event loop #[cfg(feature = "a11y")]
// #[cfg(feature = "a11y")] control_sender
// { .start_send(Control::InitAdapter(
// use crate::a11y::*; surface_id,
// use iced_accessibility::accesskit::{ sctk_winit.clone(),
// ActivationHandler, Node, NodeId, Role, Tree, ))
// TreeUpdate, .expect("Send control message");
// };
// use iced_accessibility::accesskit_winit::Adapter;
// let node_id =
// iced_runtime::core::id::window_node_id();
// let activation_handler = WinitActivationHandler {
// proxy: control_sender.clone(),
// title: String::new(),
// };
// let action_handler = WinitActionHandler {
// id: surface_id,
// proxy: control_sender.clone(),
// };
// let deactivation_handler =
// WinitDeactivationHandler {
// proxy: control_sender.clone(),
// };
// _ = adapters.insert(
// surface_id,
// (
// node_id,
// Adapter::with_direct_handlers(
// event_loop,
// sctk_winit.as_ref(),
// activation_handler,
// action_handler,
// deactivation_handler,
// ),
// ),
// );
// }
if clipboard.window_id().is_none() { if clipboard.window_id().is_none() {
*clipboard = Clipboard::connect( *clipboard = Clipboard::connect(
@ -1239,45 +1173,13 @@ impl SctkEvent {
display, display,
queue_handle, queue_handle,
); );
// TODO must move this to the winit handler, where we have access to the event loop #[cfg(feature = "a11y")]
// #[cfg(feature = "a11y")] control_sender
// { .start_send(Control::InitAdapter(
// use crate::a11y::*; surface_id,
// use iced_accessibility::accesskit::{ sctk_winit.clone(),
// ActivationHandler, Node, NodeId, Role, Tree, TreeUpdate, ))
// }; .expect("Send control message");
// use iced_accessibility::accesskit_winit::Adapter;
// let node_id = iced_runtime::core::id::window_node_id();
// let activation_handler = WinitActivationHandler {
// proxy: control_sender.clone(),
// // TODO lock screen title
// title: String::new(),
// };
// let action_handler = WinitActionHandler {
// id: surface_id,
// proxy: control_sender.clone(),
// };
// let deactivation_handler = WinitDeactivationHandler {
// proxy: control_sender.clone(),
// };
// _ = adapters.insert(
// surface_id,
// (
// node_id,
// Adapter::with_direct_handlers(
// event_loop,
// sctk_winit.as_ref(),
// activation_handler,
// action_handler,
// deactivation_handler,
// ),
// ),
// );
// }
if clipboard.window_id().is_none() { if clipboard.window_id().is_none() {
*clipboard = Clipboard::connect( *clipboard = Clipboard::connect(
@ -1515,43 +1417,13 @@ impl SctkEvent {
display, display,
qh, qh,
); );
// #[cfg(feature = "a11y")] #[cfg(feature = "a11y")]
// { control_sender
// use crate::a11y::*; .start_send(Control::InitAdapter(
// use iced_accessibility::accesskit::{ surface_id,
// ActivationHandler, NodeBuilder, NodeId, Role, Tree, sctk_winit.clone(),
// TreeUpdate, ))
// }; .expect("Send control message");
// use iced_accessibility::accesskit_winit::Adapter;
// let node_id = iced_runtime::core::id::window_node_id();
// let activation_handler = WinitActivationHandler {
// proxy: control_sender.clone(),
// title: String::new(),
// };
// let action_handler = WinitActionHandler {
// id: surface_id,
// proxy: control_sender.clone(),
// };
// let deactivation_handler = WinitDeactivationHandler {
// proxy: control_sender.clone(),
// };
// _ = adapters.insert(
// surface_id,
// (
// node_id,
// Adapter::with_direct_handlers(
// sctk_winit.as_ref(),
// activation_handler,
// action_handler,
// deactivation_handler,
// ),
// ),
// );
// }
if clipboard.window_id().is_none() { if clipboard.window_id().is_none() {
*clipboard = Clipboard::connect( *clipboard = Clipboard::connect(