Skip to content
This repository has been archived by the owner on Jul 15, 2024. It is now read-only.

Commit

Permalink
Update to AccessKit 0.12 (#173)
Browse files Browse the repository at this point in the history
* Update to AccessKit 0.12

* Add boilerplate in the other examples for constructing a valid, but empty, TreeUpdate, since TreeUpdate::default is no longer an option
  • Loading branch information
mwcampbell authored Nov 23, 2023
1 parent 3c942e5 commit b79dd1b
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 41 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ memchr = "2.5"

# Optional dependencies
raw-window-handle = { version = "0.5.0", default_features = false }
accesskit = { version = "0.11.0", optional = true }
accesskit = { version = "0.12.0", optional = true }
once_cell = { version = "1", optional = true }

[target.'cfg(target_os="windows")'.dependencies]
scopeguard = "1.1.0"
wio = "0.2.2"
accesskit_windows = { version = "0.14.0", optional = true }
accesskit_windows = { version = "0.15.0", optional = true }
once_cell = "1"

[target.'cfg(target_os="windows")'.dependencies.winapi]
Expand Down Expand Up @@ -93,7 +93,7 @@ cocoa = "0.25.0"
objc = "0.2.7"
core-graphics = "0.23.0"
bitflags = "2.0.0"
accesskit_macos = { version = "0.9.0", optional = true }
accesskit_macos = { version = "0.10.0", optional = true }

[target.'cfg(any(target_os = "freebsd", target_os="linux", target_os="openbsd"))'.dependencies]
ashpd = { version = "0.5", optional = true }
Expand Down
43 changes: 12 additions & 31 deletions examples/accesskit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{any::Any, num::NonZeroU128};
use std::any::Any;

use accesskit::{
Action, ActionRequest, CheckedState, DefaultActionVerb, Node, NodeBuilder, NodeClassSet,
NodeId, Rect, Role, Tree, TreeUpdate,
Action, ActionRequest, Checked, DefaultActionVerb, Node, NodeBuilder, NodeClassSet, NodeId,
Rect, Role, Tree, TreeUpdate,
};

use glazier::kurbo::Size;
Expand All @@ -25,9 +25,9 @@ use glazier::{Application, KbKey, KeyEvent, Region, WinHandler, WindowBuilder, W

const WINDOW_TITLE: &str = "Hello world";

const WINDOW_ID: NodeId = NodeId(unsafe { NonZeroU128::new_unchecked(1) });
const CHECKBOX_1_ID: NodeId = NodeId(unsafe { NonZeroU128::new_unchecked(2) });
const CHECKBOX_2_ID: NodeId = NodeId(unsafe { NonZeroU128::new_unchecked(3) });
const WINDOW_ID: NodeId = NodeId(0);
const CHECKBOX_1_ID: NodeId = NodeId(1);
const CHECKBOX_2_ID: NodeId = NodeId(2);
const INITIAL_FOCUS: NodeId = CHECKBOX_1_ID;

const CHECKBOX_1_NAME: &str = "Checkbox 1";
Expand Down Expand Up @@ -59,18 +59,17 @@ fn build_checkbox(id: NodeId, checked: bool, classes: &mut NodeClassSet) -> Node
builder.set_name(name);
builder.add_action(Action::Focus);
builder.set_default_action_verb(DefaultActionVerb::Click);
builder.set_checked_state(if checked {
CheckedState::True
builder.set_checked(if checked {
Checked::True
} else {
CheckedState::False
Checked::False
});
builder.build(classes)
}

struct HelloState {
size: Size,
focus: NodeId,
is_window_focused: bool,
checkbox_1_checked: bool,
checkbox_2_checked: bool,
handle: WindowHandle,
Expand All @@ -82,23 +81,18 @@ impl HelloState {
Self {
size: Default::default(),
focus: INITIAL_FOCUS,
is_window_focused: false,
checkbox_1_checked: false,
checkbox_2_checked: false,
handle: Default::default(),
node_classes: NodeClassSet::new(),
}
}

fn accesskit_focus(&self) -> Option<NodeId> {
self.is_window_focused.then_some(self.focus)
}

fn update_accesskit_focus(&self) {
self.handle.update_accesskit_if_active(|| TreeUpdate {
nodes: vec![],
tree: None,
focus: self.accesskit_focus(),
focus: self.focus,
});
}

Expand All @@ -114,10 +108,7 @@ impl HelloState {
}
_ => unreachable!(),
};
// We have to be slightly less lazy here than we'd like because we can't
// borrow self immutably inside the closure while we have a mutable
// borrow of self.node_classes. TBD: Does this indicate a design flaw?
let focus = self.accesskit_focus();
let focus = self.focus;
let node_classes = &mut self.node_classes;
self.handle.update_accesskit_if_active(|| {
let node = build_checkbox(id, checked, node_classes);
Expand Down Expand Up @@ -163,7 +154,7 @@ impl WinHandler for HelloState {
(CHECKBOX_2_ID, checkbox_2),
],
tree: Some(Tree::new(WINDOW_ID)),
focus: self.accesskit_focus(),
focus: self.focus,
}
}

Expand All @@ -188,16 +179,6 @@ impl WinHandler for HelloState {
self.size = size;
}

fn got_focus(&mut self) {
self.is_window_focused = true;
self.update_accesskit_focus();
}

fn lost_focus(&mut self) {
self.is_window_focused = false;
self.update_accesskit_focus();
}

fn accesskit_action(&mut self, request: ActionRequest) {
if let ActionRequest {
action,
Expand Down
11 changes: 10 additions & 1 deletion examples/edit_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,16 @@ impl WinHandler for WindowState {
#[cfg(feature = "accesskit")]
fn accesskit_tree(&mut self) -> TreeUpdate {
// TODO: Construct a real TreeUpdate
TreeUpdate::default()
use accesskit::{NodeBuilder, NodeClassSet, NodeId, Role, Tree};
let builder = NodeBuilder::new(Role::Window);
let mut node_classes = NodeClassSet::new();
let node = builder.build(&mut node_classes);
const WINDOW_ID: NodeId = NodeId(0);
TreeUpdate {
nodes: vec![(WINDOW_ID, node)],
tree: Some(Tree::new(WINDOW_ID)),
focus: WINDOW_ID,
}
}

fn size(&mut self, size: Size) {
Expand Down
11 changes: 10 additions & 1 deletion examples/pen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,16 @@ impl WinHandler for WindowState {
#[cfg(feature = "accesskit")]
fn accesskit_tree(&mut self) -> TreeUpdate {
// TODO: Construct a real TreeUpdate
TreeUpdate::default()
use accesskit::{NodeBuilder, NodeClassSet, NodeId, Role, Tree};
let builder = NodeBuilder::new(Role::Window);
let mut node_classes = NodeClassSet::new();
let node = builder.build(&mut node_classes);
const WINDOW_ID: NodeId = NodeId(0);
TreeUpdate {
nodes: vec![(WINDOW_ID, node)],
tree: Some(Tree::new(WINDOW_ID)),
focus: WINDOW_ID,
}
}

fn idle(&mut self, _: IdleToken) {
Expand Down
11 changes: 10 additions & 1 deletion examples/shello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,16 @@ impl WinHandler for WindowState {
#[cfg(feature = "accesskit")]
fn accesskit_tree(&mut self) -> TreeUpdate {
// TODO: Construct a real TreeUpdate
TreeUpdate::default()
use accesskit::{NodeBuilder, NodeClassSet, NodeId, Role, Tree};
let builder = NodeBuilder::new(Role::Window);
let mut node_classes = NodeClassSet::new();
let node = builder.build(&mut node_classes);
const WINDOW_ID: NodeId = NodeId(0);
TreeUpdate {
nodes: vec![(WINDOW_ID, node)],
tree: Some(Tree::new(WINDOW_ID)),
focus: WINDOW_ID,
}
}

fn idle(&mut self, _: IdleToken) {}
Expand Down
11 changes: 10 additions & 1 deletion examples/wgpu-triangle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,16 @@ impl WinHandler for WindowState {
#[cfg(feature = "accesskit")]
fn accesskit_tree(&mut self) -> TreeUpdate {
// TODO: Construct a real TreeUpdate
TreeUpdate::default()
use accesskit::{NodeBuilder, NodeClassSet, NodeId, Role, Tree};
let builder = NodeBuilder::new(Role::Window);
let mut node_classes = NodeClassSet::new();
let node = builder.build(&mut node_classes);
const WINDOW_ID: NodeId = NodeId(0);
TreeUpdate {
nodes: vec![(WINDOW_ID, node)],
tree: Some(Tree::new(WINDOW_ID)),
focus: WINDOW_ID,
}
}

fn idle(&mut self, _: IdleToken) {}
Expand Down
26 changes: 24 additions & 2 deletions src/backend/mac/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ struct ViewState {
parent: Option<crate::WindowHandle>,
#[cfg(feature = "accesskit")]
accesskit_adapter: OnceCell<AccessKitAdapter>,
#[cfg(feature = "accesskit")]
is_focused: bool,
}

#[derive(Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -650,6 +652,8 @@ fn make_view(handler: Box<dyn WinHandler>) -> (id, Weak<Mutex<Vec<IdleKind>>>) {
parent: None,
#[cfg(feature = "accesskit")]
accesskit_adapter: OnceCell::new(),
#[cfg(feature = "accesskit")]
is_focused: false,
};
let state_ptr = Box::into_raw(Box::new(state));
(*view).set_ivar("viewState", state_ptr as *mut c_void);
Expand Down Expand Up @@ -1105,6 +1109,14 @@ extern "C" fn window_did_become_key(this: &mut Object, _: Sel, _notification: id
let view_state: *mut c_void = *this.get_ivar("viewState");
let view_state = &mut *(view_state as *mut ViewState);
view_state.handler.got_focus();
#[cfg(feature = "accesskit")]
{
view_state.is_focused = true;
if let Some(adapter) = view_state.accesskit_adapter.get() {
let events = adapter.update_view_focus_state(true);
events.raise();
}
}
}
}

Expand All @@ -1113,6 +1125,14 @@ extern "C" fn window_did_resign_key(this: &mut Object, _: Sel, _notification: id
let view_state: *mut c_void = *this.get_ivar("viewState");
let view_state = &mut *(view_state as *mut ViewState);
view_state.handler.lost_focus();
#[cfg(feature = "accesskit")]
{
view_state.is_focused = false;
if let Some(adapter) = view_state.accesskit_adapter.get() {
let events = adapter.update_view_focus_state(false);
events.raise();
}
}
}
}

Expand Down Expand Up @@ -1596,7 +1616,7 @@ impl IdleHandle {

#[cfg(feature = "accesskit")]
impl accesskit::ActionHandler for AccessKitActionHandler {
fn do_action(&self, request: accesskit::ActionRequest) {
fn do_action(&mut self, request: accesskit::ActionRequest) {
self.idle_handle.add_idle_callback(move |handler| {
handler.accesskit_action(request);
});
Expand All @@ -1616,14 +1636,16 @@ impl ViewState {
}
let view = view as *mut Object as *mut c_void;
let initial_state = self.handler.accesskit_tree();
let is_focused = self.is_focused;
let idle_handle = IdleHandle {
nsview: self.nsview.clone(),
idle_queue: Arc::downgrade(&self.idle_queue),
};
let action_handler = Box::new(AccessKitActionHandler { idle_handle });
// SAFETY: The view pointer is based on a valid borrowed reference
// to the view.
let adapter = unsafe { AccessKitAdapter::new(view, initial_state, action_handler) };
let adapter =
unsafe { AccessKitAdapter::new(view, initial_state, is_focused, action_handler) };
match self.accesskit_adapter.try_insert(adapter) {
Ok(adapter) => adapter,
Err((old_adapter, _)) => {
Expand Down
32 changes: 31 additions & 1 deletion src/backend/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ struct WindowState {
uia_init_marker: UiaInitMarker, // zero size
#[cfg(feature = "accesskit")]
accesskit_adapter: OnceCell<AccessKitAdapter>,
#[cfg(feature = "accesskit")]
is_focused: Cell<bool>,
}

impl std::fmt::Debug for WindowState {
Expand Down Expand Up @@ -737,10 +739,34 @@ impl WndProc for MyWndProc {
WM_ERASEBKGND => Some(0),
WM_SETFOCUS => {
self.with_wnd_state(|s| s.handler.got_focus());
#[cfg(feature = "accesskit")]
{
let handle = self.handle.borrow();
if let Some(state) = handle.state.upgrade() {
state.is_focused.set(true);
if let Some(adapter) = state.accesskit_adapter.get() {
let events = adapter.update_window_focus_state(true);
drop(handle);
events.raise();
}
}
}
Some(0)
}
WM_KILLFOCUS => {
self.with_wnd_state(|s| s.handler.lost_focus());
#[cfg(feature = "accesskit")]
{
let handle = self.handle.borrow();
if let Some(state) = handle.state.upgrade() {
state.is_focused.set(false);
if let Some(adapter) = state.accesskit_adapter.get() {
let events = adapter.update_window_focus_state(false);
drop(handle);
events.raise();
}
}
}
Some(0)
}
WM_PAINT => unsafe {
Expand Down Expand Up @@ -1187,6 +1213,7 @@ impl WndProc for MyWndProc {
let wparam = accesskit_windows::WPARAM(wparam);
let lparam = accesskit_windows::LPARAM(lparam);
let idle_queue = &state.idle_queue;
let is_focused = state.is_focused.get();
let uia_init_marker = state.uia_init_marker; // zero size and Copy
state
.accesskit_adapter
Expand All @@ -1202,6 +1229,7 @@ impl WndProc for MyWndProc {
AccessKitAdapter::new(
hwnd,
initial_tree_state,
is_focused,
action_handler,
uia_init_marker,
)
Expand Down Expand Up @@ -1391,6 +1419,8 @@ impl WindowBuilder {
uia_init_marker: UiaInitMarker::new(),
#[cfg(feature = "accesskit")]
accesskit_adapter: OnceCell::new(),
#[cfg(feature = "accesskit")]
is_focused: Cell::new(false),
};
let win = Rc::new(window);
let handle = WindowHandle {
Expand Down Expand Up @@ -2087,7 +2117,7 @@ impl IdleHandle {

#[cfg(feature = "accesskit")]
impl accesskit::ActionHandler for AccessKitActionHandler {
fn do_action(&self, request: accesskit::ActionRequest) {
fn do_action(&mut self, request: accesskit::ActionRequest) {
self.idle_handle.add_idle_callback(move |handler| {
handler.accesskit_action(request);
});
Expand Down

0 comments on commit b79dd1b

Please sign in to comment.