Skip to content

Commit

Permalink
refactor!: New approach to lazy initialization (#375)
Browse files Browse the repository at this point in the history
  • Loading branch information
mwcampbell authored Mar 31, 2024
1 parent 1de7c63 commit 9baebdc
Show file tree
Hide file tree
Showing 42 changed files with 1,856 additions and 1,002 deletions.
2 changes: 2 additions & 0 deletions bindings/c/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ renaming_overrides_prefixing = true
[export.rename]
"Action" = "accesskit_action"
"ActionHandlerCallback" = "accesskit_action_handler_callback"
"ActivationHandlerCallback" = "accesskit_activation_handler_callback"
"Affine" = "accesskit_affine"
"AriaCurrent" = "accesskit_aria_current"
"AutoComplete" = "accesskit_auto_complete"
"Checked" = "accesskit_checked"
"DeactivationHandlerCallback" = "accesskit_deactivation_handler_callback"
"DefaultActionVerb" = "accesskit_default_action_verb"
"HWND" = "HWND"
"HasPopup" = "accesskit_has_popup"
Expand Down
46 changes: 29 additions & 17 deletions bindings/c/examples/sdl/hello_world.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,34 @@ struct accesskit_sdl_adapter {
#endif
};

void accesskit_sdl_adapter_init(struct accesskit_sdl_adapter *adapter,
SDL_Window *window,
accesskit_tree_update_factory source,
void *source_userdata,
accesskit_action_handler *handler) {
void accesskit_sdl_adapter_init(
struct accesskit_sdl_adapter *adapter, SDL_Window *window,
accesskit_activation_handler_callback activation_handler,
void *activation_handler_userdata,
accesskit_action_handler_callback action_handler,
void *action_handler_userdata,
accesskit_deactivation_handler_callback deactivation_handler,
void *deactivation_handler_userdata) {
#if defined(__APPLE__)
accesskit_macos_add_focus_forwarder_to_window_class("SDLWindow");
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(window, &wmInfo);
adapter->adapter = accesskit_macos_subclassing_adapter_for_window(
(void *)wmInfo.info.cocoa.window, source, source_userdata, handler);
(void *)wmInfo.info.cocoa.window, activation_handler,
activation_handler_userdata, action_handler, action_handler_userdata);
#elif defined(UNIX)
adapter->adapter =
accesskit_unix_adapter_new(source, source_userdata, handler);
adapter->adapter = accesskit_unix_adapter_new(
activation_handler, activation_handler_userdata, action_handler,
action_handler_userdata, deactivation_handler,
deactivation_handler_userdata);
#elif defined(_WIN32)
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(window, &wmInfo);
adapter->adapter = accesskit_windows_subclassing_adapter_new(
wmInfo.info.win.window, source, source_userdata, handler);
wmInfo.info.win.window, activation_handler, activation_handler_userdata,
action_handler, action_handler_userdata);
#endif
}

Expand All @@ -100,7 +107,7 @@ void accesskit_sdl_adapter_destroy(struct accesskit_sdl_adapter *adapter) {
}

void accesskit_sdl_adapter_update_if_active(
const struct accesskit_sdl_adapter *adapter,
struct accesskit_sdl_adapter *adapter,
accesskit_tree_update_factory update_factory,
void *update_factory_userdata) {
#if defined(__APPLE__)
Expand All @@ -124,7 +131,7 @@ void accesskit_sdl_adapter_update_if_active(
}

void accesskit_sdl_adapter_update_window_focus_state(
const struct accesskit_sdl_adapter *adapter, bool is_focused) {
struct accesskit_sdl_adapter *adapter, bool is_focused) {
#if defined(__APPLE__)
accesskit_macos_queued_events *events =
accesskit_macos_subclassing_adapter_update_view_focus_state(
Expand All @@ -140,7 +147,7 @@ void accesskit_sdl_adapter_update_window_focus_state(
}

void accesskit_sdl_adapter_update_root_window_bounds(
const struct accesskit_sdl_adapter *adapter, SDL_Window *window) {
struct accesskit_sdl_adapter *adapter, SDL_Window *window) {
#if defined(UNIX)
int x, y, width, height;
SDL_GetWindowPosition(window, &x, &y);
Expand Down Expand Up @@ -230,7 +237,7 @@ accesskit_tree_update *build_tree_update_for_button_press(void *userdata) {
}

void window_state_press_button(struct window_state *state,
const struct accesskit_sdl_adapter *adapter,
struct accesskit_sdl_adapter *adapter,
accesskit_node_id id) {
const char *text;
if (id == BUTTON_1_ID) {
Expand All @@ -251,7 +258,7 @@ accesskit_tree_update *build_tree_update_for_focus_update(void *userdata) {
}

void window_state_set_focus(struct window_state *state,
const struct accesskit_sdl_adapter *adapter,
struct accesskit_sdl_adapter *adapter,
accesskit_node_id focus) {
state->focus = focus;
accesskit_sdl_adapter_update_if_active(
Expand Down Expand Up @@ -287,6 +294,11 @@ accesskit_tree_update *build_initial_tree(void *userdata) {
return update;
}

void deactivate_accessibility(void *userdata) {
/* There's nothing in the state that depends on whether the adapter
is active, so there's nothing to do here. */
}

int main(int argc, char *argv[]) {
printf("This example has no visible GUI, and a keyboard interface:\n");
printf("- [Tab] switches focus between two logical buttons.\n");
Expand Down Expand Up @@ -318,9 +330,9 @@ int main(int argc, char *argv[]) {
Uint32 window_id = SDL_GetWindowID(window);
struct action_handler_state action_handler = {user_event, window_id};
struct accesskit_sdl_adapter adapter;
accesskit_sdl_adapter_init(
&adapter, window, build_initial_tree, &state,
accesskit_action_handler_new(do_action, &action_handler));
accesskit_sdl_adapter_init(&adapter, window, build_initial_tree, &state,
do_action, &action_handler,
deactivate_accessibility, &state);
SDL_ShowWindow(window);

SDL_Event event;
Expand Down
100 changes: 43 additions & 57 deletions bindings/c/examples/windows/hello_world.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,14 @@ accesskit_node *build_announcement(const char *text,
}

struct window_state {
accesskit_windows_uia_init_marker *uia_init_marker;
accesskit_windows_adapter *adapter;
accesskit_node_id focus;
bool is_window_focused;
const char *announcement;
accesskit_node_class_set *node_classes;
};

void window_state_free(struct window_state *state) {
if (state->uia_init_marker != NULL) {
accesskit_windows_uia_init_marker_free(state->uia_init_marker);
}
if (state->adapter != NULL) {
accesskit_windows_adapter_free(state->adapter);
}
accesskit_windows_adapter_free(state->adapter);
accesskit_node_class_set_free(state->node_classes);
free(state);
}
Expand All @@ -79,8 +72,8 @@ accesskit_node *window_state_build_root(struct window_state *state) {
return accesskit_node_builder_build(builder, state->node_classes);
}

accesskit_tree_update *window_state_build_initial_tree(
struct window_state *state) {
accesskit_tree_update *build_initial_tree(void *userdata) {
struct window_state *state = userdata;
accesskit_node *root = window_state_build_root(state);
accesskit_node *button_1 =
build_button(BUTTON_1_ID, "Button 1", state->node_classes);
Expand Down Expand Up @@ -113,34 +106,36 @@ void do_action(const accesskit_action_request *request, void *userdata) {
}
}

accesskit_windows_adapter *window_state_get_or_init_accesskit_adapter(
struct window_state *state, HWND window) {
if (state->adapter != NULL) {
return state->adapter;
} else {
accesskit_tree_update *initial_tree =
window_state_build_initial_tree(state);
accesskit_action_handler *action_handler =
accesskit_action_handler_new(do_action, (void *)window);
state->adapter = accesskit_windows_adapter_new(
window, initial_tree, state->is_window_focused, action_handler,
state->uia_init_marker);
state->uia_init_marker = NULL;
return state->adapter;
}
accesskit_tree_update *build_tree_update_for_focus_update(void *userdata) {
struct window_state *state = userdata;
accesskit_tree_update *update =
accesskit_tree_update_with_focus(state->focus);
return update;
}

void window_state_set_focus(struct window_state *state,
accesskit_node_id focus) {
state->focus = focus;
if (state->adapter != NULL) {
accesskit_tree_update *update = accesskit_tree_update_with_focus(focus);
accesskit_windows_queued_events *events =
accesskit_windows_adapter_update(state->adapter, update);
accesskit_windows_queued_events *events =
accesskit_windows_adapter_update_if_active(
state->adapter, build_tree_update_for_focus_update, state);
if (events != NULL) {
accesskit_windows_queued_events_raise(events);
}
}

accesskit_tree_update *build_tree_update_for_button_press(void *userdata) {
struct window_state *state = userdata;
accesskit_node *announcement =
build_announcement(state->announcement, state->node_classes);
accesskit_node *root = window_state_build_root(state);
accesskit_tree_update *update =
accesskit_tree_update_with_capacity_and_focus(2, state->focus);
accesskit_tree_update_push_node(update, ANNOUNCEMENT_ID, announcement);
accesskit_tree_update_push_node(update, WINDOW_ID, root);
return update;
}

void window_state_press_button(struct window_state *state,
accesskit_node_id id) {
const char *text;
Expand All @@ -150,16 +145,10 @@ void window_state_press_button(struct window_state *state,
text = "You pressed button 2";
}
state->announcement = text;
if (state->adapter != NULL) {
accesskit_node *announcement =
build_announcement(text, state->node_classes);
accesskit_node *root = window_state_build_root(state);
accesskit_tree_update *update =
accesskit_tree_update_with_capacity_and_focus(2, state->focus);
accesskit_tree_update_push_node(update, ANNOUNCEMENT_ID, announcement);
accesskit_tree_update_push_node(update, WINDOW_ID, root);
accesskit_windows_queued_events *events =
accesskit_windows_adapter_update(state->adapter, update);
accesskit_windows_queued_events *events =
accesskit_windows_adapter_update_if_active(
state->adapter, build_tree_update_for_button_press, state);
if (events != NULL) {
accesskit_windows_queued_events_raise(events);
}
}
Expand All @@ -170,11 +159,10 @@ struct window_state *get_window_state(HWND window) {

void update_window_focus_state(HWND window, bool is_focused) {
struct window_state *state = get_window_state(window);
state->is_window_focused = is_focused;
if (state->adapter != NULL) {
accesskit_windows_queued_events *events =
accesskit_windows_adapter_update_window_focus_state(state->adapter,
is_focused);
accesskit_windows_queued_events *events =
accesskit_windows_adapter_update_window_focus_state(state->adapter,
is_focused);
if (events != NULL) {
accesskit_windows_queued_events_raise(events);
}
}
Expand All @@ -189,10 +177,9 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
struct window_create_params *create_params =
(struct window_create_params *)create_struct->lpCreateParams;
struct window_state *state = malloc(sizeof(struct window_state));
state->uia_init_marker = accesskit_windows_uia_init_marker_new();
state->adapter = NULL;
state->adapter =
accesskit_windows_adapter_new(hwnd, false, do_action, (void *)hwnd);
state->focus = create_params->initial_focus;
state->is_window_focused = false;
state->announcement = NULL;
state->node_classes = accesskit_node_class_set_new();
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)state);
Expand All @@ -207,17 +194,16 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
}
PostQuitMessage(0);
} else if (msg == WM_GETOBJECT) {
struct window_state *window_state = get_window_state(hwnd);
if (window_state == NULL) {
struct window_state *state = get_window_state(hwnd);
if (state == NULL) {
// We need to be prepared to gracefully handle WM_GETOBJECT
// while the window is being destroyed; this can happen if
// the thread is using a COM STA.
return DefWindowProc(hwnd, msg, wParam, lParam);
}
accesskit_windows_adapter *adapter =
window_state_get_or_init_accesskit_adapter(window_state, hwnd);
accesskit_opt_lresult result =
accesskit_windows_adapter_handle_wm_getobject(adapter, wParam, lParam);
accesskit_windows_adapter_handle_wm_getobject(
state->adapter, wParam, lParam, build_initial_tree, state);
if (result.has_value) {
return result.value;
} else {
Expand All @@ -236,9 +222,9 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
(state->focus == BUTTON_1_ID) ? BUTTON_2_ID : BUTTON_1_ID;
window_state_set_focus(state, new_focus);
} else if (wParam == VK_SPACE) {
struct window_state *window_state = get_window_state(hwnd);
accesskit_node_id id = window_state->focus;
window_state_press_button(window_state, id);
struct window_state *state = get_window_state(hwnd);
accesskit_node_id id = state->focus;
window_state_press_button(state, id);
} else {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Expand All @@ -251,8 +237,8 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
} else if (msg == DO_DEFAULT_ACTION_MSG) {
accesskit_node_id id = (accesskit_node_id)lParam;
if (id == BUTTON_1_ID || id == BUTTON_2_ID) {
struct window_state *window_state = get_window_state(hwnd);
window_state_press_button(window_state, id);
struct window_state *state = get_window_state(hwnd);
window_state_press_button(state, id);
}
} else {
return DefWindowProc(hwnd, msg, wParam, lParam);
Expand Down
Loading

0 comments on commit 9baebdc

Please sign in to comment.