Detailed changes
@@ -431,6 +431,9 @@ impl<E: Element> Drawable<E> {
}
fn push_a11y_node(&self, global_id: &GlobalElementId, window: &mut Window) -> bool {
+ if !window.is_a11y_active() {
+ return false;
+ }
if let Some(role) = self.element.a11y_role() {
let global_id = global_id.accesskit_node_id();
@@ -1968,10 +1968,12 @@ impl Interactivity {
if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
window.set_focus_handle(focus_handle, cx);
- if let Some(global_id) = global_id {
- window
- .a11y_focus_ids
- .insert(global_id.accesskit_node_id(), focus_handle.id);
+ if window.is_a11y_active() {
+ if let Some(global_id) = global_id {
+ window
+ .a11y_focus_ids
+ .insert(global_id.accesskit_node_id(), focus_handle.id);
+ }
}
}
window.with_optional_element_state::<InteractiveElementState, _>(
@@ -2465,12 +2467,14 @@ impl Interactivity {
let aux_click_listeners = mem::take(&mut self.aux_click_listeners);
let can_drop_predicate = mem::take(&mut self.can_drop_predicate);
- if let Some(global_id) = global_id {
- if !click_listeners.is_empty() {
- let node_id = global_id.accesskit_node_id();
- window
- .a11y_click_listeners
- .insert(node_id, click_listeners.clone());
+ if window.is_a11y_active() {
+ if let Some(global_id) = global_id {
+ if !click_listeners.is_empty() {
+ let node_id = global_id.accesskit_node_id();
+ window
+ .a11y_click_listeners
+ .insert(node_id, click_listeners.clone());
+ }
}
}
@@ -508,6 +508,12 @@ pub trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
/// Inform the accesskit adapter of the bounds of the window.
fn a11y_update_window_bounds(&self);
+ /// Whether the platform's accessibility adapter is currently active. Always
+ /// returns false on platforms that don't support accesskit.
+ fn is_a11y_active(&self) -> bool {
+ false
+ }
+
// macOS specific methods
fn get_title(&self) -> String {
String::new()
@@ -2427,8 +2427,11 @@ impl Window {
fn draw_roots(&mut self, cx: &mut App) {
self.invalidator.set_phase(DrawPhase::Prepaint);
self.tooltip_bounds.take();
- self.a11y_click_listeners.clear();
- self.a11y_focus_ids.clear();
+
+ if self.is_a11y_active() {
+ self.a11y_click_listeners.clear();
+ self.a11y_focus_ids.clear();
+ }
let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
let root_size = {
@@ -2449,7 +2452,9 @@ impl Window {
};
// Layout all root elements.
- self.a11y_nodes.push_root();
+ if self.is_a11y_active() {
+ self.a11y_nodes.push_root();
+ }
let mut root_element = self.root.as_ref().unwrap().clone().into_any();
root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
@@ -2501,8 +2506,16 @@ impl Window {
#[cfg(any(feature = "inspector", debug_assertions))]
self.paint_inspector_hitbox(cx);
- let tree_update = self.a11y_nodes.finalize();
- self.platform_window.a11y_tree_update(tree_update);
+ if self.is_a11y_active() {
+ let tree_update = self.a11y_nodes.finalize();
+ self.platform_window.a11y_tree_update(tree_update);
+ }
+ }
+
+ /// Whether accessibility information is currently being requested by an
+ /// a11y tool. If false, we can skip building the a11y tree altogether.
+ pub fn is_a11y_active(&self) -> bool {
+ self.platform_window.is_a11y_active()
}
fn handle_a11y_action(&mut self, request: ActionRequest, cx: &mut App) {
@@ -3844,8 +3857,10 @@ impl Window {
self.invalidator.debug_assert_prepaint();
if focus_handle.is_focused(self) {
self.next_frame.focus = Some(focus_handle.id);
- if let Some(node_id) = self.a11y_nodes.current_node_id() {
- self.a11y_nodes.set_focused(node_id);
+ if self.is_a11y_active() {
+ if let Some(node_id) = self.a11y_nodes.current_node_id() {
+ self.a11y_nodes.set_focused(node_id);
+ }
}
}
self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
@@ -3,7 +3,10 @@ use std::{
ffi::c_void,
ptr::NonNull,
rc::Rc,
- sync::Arc,
+ sync::{
+ Arc,
+ atomic::{AtomicBool, Ordering::SeqCst},
+ },
};
use accesskit::TreeUpdate;
@@ -34,7 +37,8 @@ use gpui::{
AnyWindowHandle, Bounds, Capslock, Decorations, DevicePixels, GpuSpecs, Modifiers, Pixels,
PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point,
PromptButton, PromptLevel, RequestFrameOptions, ResizeEdge, Scene, Size, Tiling,
- WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls,
+ TrivialActivationHandler, TrivialDeactivationHandler, WindowAppearance,
+ WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls,
WindowDecorations, WindowKind, WindowParams, layer_shell::LayerShellNotSupportedError, px,
size,
};
@@ -120,7 +124,7 @@ pub struct WaylandWindowState {
in_progress_window_controls: Option<WindowControls>,
window_controls: WindowControls,
client_inset: Option<Pixels>,
- // todo! document initialization reqs
+ a11y_active: Arc<AtomicBool>,
accesskit: Option<accesskit_unix::Adapter>,
}
@@ -393,6 +397,7 @@ impl WaylandWindowState {
in_progress_window_controls: None,
window_controls: WindowControls::default(),
client_inset: None,
+ a11y_active: Arc::new(AtomicBool::new(false)),
accesskit: None,
})
}
@@ -1481,10 +1486,31 @@ impl PlatformWindow for WaylandWindow {
panic!("cannot initialize accesskit twice");
}
+ let original_activation = callbacks.activation;
+ let activation = TrivialActivationHandler(Box::new({
+ let a11y_active = state.a11y_active.clone();
+ move || {
+ let tree = (original_activation.0)();
+ if tree.is_some() {
+ a11y_active.store(true, SeqCst);
+ }
+ tree
+ }
+ }));
+
+ let original_deactivation = callbacks.deactivation;
+ let deactivation = TrivialDeactivationHandler(Box::new({
+ let a11y_active = state.a11y_active.clone();
+ move || {
+ a11y_active.store(false, SeqCst);
+ (original_deactivation.0)();
+ }
+ }));
+
state.accesskit = Some(accesskit_unix::Adapter::new(
- callbacks.activation,
+ activation,
callbacks.action,
- callbacks.deactivation,
+ deactivation,
));
}
@@ -1501,6 +1527,10 @@ impl PlatformWindow for WaylandWindow {
fn a11y_update_window_bounds(&self) {
// no-op - wayland does not let us get bounds for our window
}
+
+ fn is_a11y_active(&self) -> bool {
+ self.0.state.borrow().a11y_active.load(SeqCst)
+ }
}
fn update_window(mut state: RefMut<WaylandWindowState>) {
@@ -7,8 +7,9 @@ use gpui::{
AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GpuSpecs, Modifiers,
Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
Point, PromptButton, PromptLevel, RequestFrameOptions, ResizeEdge, ScaledPixels, Scene, Size,
- Tiling, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea,
- WindowDecorations, WindowKind, WindowParams, px,
+ Tiling, TrivialActivationHandler, TrivialDeactivationHandler, WindowAppearance,
+ WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowDecorations, WindowKind,
+ WindowParams, px,
};
use gpui_wgpu::{CompositorGpuHint, WgpuRenderer, WgpuSurfaceConfig};
@@ -30,7 +31,16 @@ use x11rb::{
};
use std::{
- cell::RefCell, ffi::c_void, fmt::Display, num::NonZeroU32, ptr::NonNull, rc::Rc, sync::Arc,
+ cell::RefCell,
+ ffi::c_void,
+ fmt::Display,
+ num::NonZeroU32,
+ ptr::NonNull,
+ rc::Rc,
+ sync::{
+ Arc,
+ atomic::{AtomicBool, Ordering::SeqCst},
+ },
};
use super::{X11Display, XINPUT_ALL_DEVICE_GROUPS, XINPUT_ALL_DEVICES};
@@ -282,7 +292,7 @@ pub struct X11WindowState {
edge_constraints: Option<EdgeConstraints>,
pub handle: AnyWindowHandle,
last_insets: [u32; 4],
- // todo! document initialization reqs
+ a11y_active: Arc<AtomicBool>,
accesskit: Option<accesskit_unix::Adapter>,
}
@@ -755,6 +765,7 @@ impl X11WindowState {
edge_constraints: None,
counter_id: sync_request_counter,
last_sync_counter: None,
+ a11y_active: Arc::new(AtomicBool::new(false)),
accesskit: None,
})
});
@@ -1834,11 +1845,32 @@ impl PlatformWindow for X11Window {
panic!("cannot initialize accesskit twice");
}
+ let original_activation = callbacks.activation;
+ let activation = TrivialActivationHandler(Box::new({
+ let a11y_active = state.a11y_active.clone();
+ move || {
+ let tree = (original_activation.0)();
+ if tree.is_some() {
+ a11y_active.store(true, SeqCst);
+ }
+ tree
+ }
+ }));
+
+ let original_deactivation = callbacks.deactivation;
+ let deactivation = TrivialDeactivationHandler(Box::new({
+ let a11y_active = state.a11y_active.clone();
+ move || {
+ a11y_active.store(false, SeqCst);
+ (original_deactivation.0)();
+ }
+ }));
+
state.accesskit = Some(accesskit_unix::Adapter::new(
- callbacks.activation,
+ activation,
callbacks.action,
- callbacks.deactivation,
- ))
+ deactivation,
+ ));
}
fn a11y_tree_update(&mut self, tree_update: TreeUpdate) {
@@ -1851,6 +1883,10 @@ impl PlatformWindow for X11Window {
adapter.update_if_active(|| tree_update);
}
+ fn is_a11y_active(&self) -> bool {
+ self.0.state.borrow().a11y_active.load(SeqCst)
+ }
+
fn a11y_update_window_bounds(&self) {
let mut state = self.0.state.borrow_mut();