Skip to content

Commit

Permalink
bevy_winit changes
Browse files Browse the repository at this point in the history
  • Loading branch information
maniwani committed Sep 21, 2023
1 parent 1a0da46 commit 34091b1
Show file tree
Hide file tree
Showing 7 changed files with 1,865 additions and 888 deletions.
163 changes: 88 additions & 75 deletions crates/bevy_winit/src/accessibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@ use bevy_a11y::{
use bevy_app::{App, Plugin, PostUpdate};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
prelude::{DetectChanges, Entity, EventReader, EventWriter},
prelude::{DetectChanges, Entity, EventReader, EventWriter, ThreadLocal, ThreadLocalResource},
query::With,
system::{NonSend, NonSendMut, Query, Res, ResMut, Resource},
system::{Query, Res, ResMut, Resource},
};
use bevy_hierarchy::{Children, Parent};
use bevy_utils::{default, HashMap};
use bevy_window::{PrimaryWindow, Window, WindowClosed, WindowFocused};

/// Maps window entities to their `AccessKit` [`Adapter`]s.
#[derive(Default, Deref, DerefMut)]
/// Maps each window entity to its `AccessKit` [`Adapter`].
///
/// **Note:** This is a [`ThreadLocalResource`] because the macOS implementation of [`Adapter`]
/// is not [`Send`](Send).
#[derive(ThreadLocalResource, Default, Deref, DerefMut)]
pub struct AccessKitAdapters(pub HashMap<Entity, Adapter>);

/// Maps window entities to their respective [`WinitActionHandler`]s.
Expand All @@ -43,35 +46,41 @@ impl ActionHandler for WinitActionHandler {

fn handle_window_focus(
focus: Res<Focus>,
adapters: NonSend<AccessKitAdapters>,
mut focused: EventReader<WindowFocused>,
mut main_thread: ThreadLocal,
) {
for event in focused.read() {
if let Some(adapter) = adapters.get(&event.window) {
adapter.update_if_active(|| {
let focus_id = (*focus).unwrap_or_else(|| event.window);
TreeUpdate {
focus: if event.focused {
Some(focus_id.to_node_id())
} else {
None
},
..default()
}
});
main_thread.run(|tls| {
let adapters = tls.resource::<AccessKitAdapters>();
for event in focused.read() {
if let Some(adapter) = adapters.get(&event.window) {
adapter.update_if_active(|| {
let focus_id = (*focus).unwrap_or_else(|| event.window);
TreeUpdate {
focus: if event.focused {
Some(focus_id.to_node_id())
} else {
None
},
..default()
}
});
}
}
}
});
}

fn window_closed(
mut adapters: NonSendMut<AccessKitAdapters>,
mut receivers: ResMut<WinitActionHandlers>,
mut events: EventReader<WindowClosed>,
mut main_thread: ThreadLocal,
) {
for WindowClosed { window, .. } in events.read() {
adapters.remove(window);
receivers.remove(window);
}
main_thread.run(|tls| {
let mut adapters = tls.resource_mut::<AccessKitAdapters>();
for WindowClosed { window, .. } in events.read() {
adapters.remove(window);
receivers.remove(window);
}
});
}

fn poll_receivers(
Expand All @@ -87,7 +96,6 @@ fn poll_receivers(
}

fn update_accessibility_nodes(
adapters: NonSend<AccessKitAdapters>,
focus: Res<Focus>,
accessibility_requested: Res<AccessibilityRequested>,
primary_window: Query<(Entity, &Window), With<PrimaryWindow>>,
Expand All @@ -98,70 +106,75 @@ fn update_accessibility_nodes(
Option<&Parent>,
)>,
node_entities: Query<Entity, With<AccessibilityNode>>,
mut main_thread: ThreadLocal,
) {
if !accessibility_requested.load(Ordering::SeqCst) {
return;
}

if let Ok((primary_window_id, primary_window)) = primary_window.get_single() {
if let Some(adapter) = adapters.get(&primary_window_id) {
let should_run = focus.is_changed() || !nodes.is_empty();
if should_run {
adapter.update_if_active(|| {
let mut to_update = vec![];
let mut has_focus = false;
let mut name = None;
if primary_window.focused {
has_focus = true;
let title = primary_window.title.clone();
name = Some(title.into_boxed_str());
}
let focus_id = if has_focus {
(*focus).or_else(|| Some(primary_window_id))
} else {
None
};
let mut root_children = vec![];
for (entity, node, children, parent) in &nodes {
let mut node = (**node).clone();
if let Some(parent) = parent {
if node_entities.get(**parent).is_err() {
main_thread.run(|tls| {
let adapters = tls.resource::<AccessKitAdapters>();
if let Some(adapter) = adapters.get(&primary_window_id) {
let should_run = focus.is_changed() || !nodes.is_empty();
if should_run {
adapter.update_if_active(|| {
let mut to_update = vec![];
let mut has_focus = false;
let mut name = None;
if primary_window.focused {
has_focus = true;
let title = primary_window.title.clone();
name = Some(title.into_boxed_str());
}
let focus_id = if has_focus {
(*focus).or_else(|| Some(primary_window_id))
} else {
None
};
let mut root_children = vec![];
for (entity, node, children, parent) in &nodes {
let mut node = (**node).clone();
if let Some(parent) = parent {
if node_entities.get(**parent).is_err() {
root_children.push(entity.to_node_id());
}
} else {
root_children.push(entity.to_node_id());
}
} else {
root_children.push(entity.to_node_id());
}
if let Some(children) = children {
for child in children {
if node_entities.get(*child).is_ok() {
node.push_child(child.to_node_id());
if let Some(children) = children {
for child in children {
if node_entities.get(*child).is_ok() {
node.push_child(child.to_node_id());
}
}
}
to_update.push((
entity.to_node_id(),
node.build(&mut NodeClassSet::lock_global()),
));
}
to_update.push((
entity.to_node_id(),
node.build(&mut NodeClassSet::lock_global()),
));
}
let mut root = NodeBuilder::new(Role::Window);
if let Some(name) = name {
root.set_name(name);
}
root.set_children(root_children);
let root = root.build(&mut NodeClassSet::lock_global());
let window_update = (primary_window_id.to_node_id(), root);
to_update.insert(0, window_update);
TreeUpdate {
nodes: to_update,
focus: focus_id.map(|v| v.to_node_id()),
..default()
}
});
let mut root = NodeBuilder::new(Role::Window);
if let Some(name) = name {
root.set_name(name);
}
root.set_children(root_children);
let root = root.build(&mut NodeClassSet::lock_global());
let window_update = (primary_window_id.to_node_id(), root);
to_update.insert(0, window_update);
TreeUpdate {
nodes: to_update,
focus: focus_id.map(|v| v.to_node_id()),
..default()
}
});
}
}
}
});
}
}

/// Implements winit-specific `AccessKit` functionality.
/// Implements [`winit`]-specific `AccessKit` functionality.
pub struct AccessibilityPlugin;

impl Plugin for AccessibilityPlugin {
Expand Down
Loading

0 comments on commit 34091b1

Please sign in to comment.