Module: wine Branch: master Commit: bc063b67ab87695048a69636373ec9c3c71b0298 URL: https://gitlab.winehq.org/wine/wine/-/commit/bc063b67ab87695048a69636373ec9c...
Author: Connor McAdams cmcadams@codeweavers.com Date: Thu Sep 14 13:05:31 2023 -0400
uiautomationcore: Check if we should try to invoke IProxyProviderWinEventHandler::RespondToWinEvent for registered UIA events.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
---
dlls/uiautomationcore/tests/uiautomation.c | 14 ++++----- dlls/uiautomationcore/uia_event.c | 47 ++++++++++++++++++++++++++++++ dlls/uiautomationcore/uia_private.h | 2 ++ dlls/uiautomationcore/uia_provider.c | 11 ++----- dlls/uiautomationcore/uia_utils.c | 7 ++++- 5 files changed, 65 insertions(+), 16 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 0e623c9a2bf..2685aba1b15 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -16823,7 +16823,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, 2); /* Only called twice on Win11. */ test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles, 1, FALSE, FALSE, FALSE); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
/* * Get rid of our serverside provider and raise EVENT_OBJECT_FOCUS @@ -16848,7 +16848,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para 1, TRUE, FALSE, TRUE); if (CALLED_COUNT(winproc_GETOBJECT_CLIENT)) ok_method_sequence(win_event_handler_seq, "win_event_handler_seq"); - check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, TRUE, 1, TRUE); + check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, FALSE, 1, TRUE); method_sequences_enabled = FALSE;
/* @@ -16895,7 +16895,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles, 1, TRUE, FALSE, TRUE); check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE); - todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
/* * Child HWND now has a serverside provider, WinEvent is ignored. @@ -16906,7 +16906,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 2); /* Only sent 2 times on Win11. */ test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles, 1, FALSE, FALSE, FALSE); - todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); CHECK_CALLED_AT_MOST(winproc_GETOBJECT_UiaRoot, 1);
/* @@ -16940,7 +16940,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para set_uia_hwnd_expects(1, 1, 1, 4, 3); test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles, 1, TRUE, FALSE, TRUE); - check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, TRUE, 1, TRUE); + check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, FALSE, 1, TRUE);
/* Raise a WinEvent on our test child HWND, both event callbacks invoked. */ child_win_prov_root = NULL; @@ -16950,7 +16950,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 8); /* Only sent 8 times on Win11. */ test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles, ARRAY_SIZE(event_handles), TRUE, TRUE, TRUE); - todo_wine CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2); + CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2); check_uia_hwnd_expects_at_least(0, FALSE, 2, TRUE, 2, TRUE, 2, TRUE, 0, FALSE);
/* @@ -16970,7 +16970,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 12); /* Only sent 12 times on Win11. */ test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, tmp_hwnd2, OBJID_WINDOW, CHILDID_SELF, event_handles, ARRAY_SIZE(event_handles), TRUE, TRUE, TRUE); - todo_wine CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2); + CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2); check_uia_hwnd_expects_at_least(0, FALSE, 2, TRUE, 2, TRUE, 0, FALSE, 0, FALSE);
DestroyWindow(tmp_hwnd); diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index d493ab0a243..59f52cdcf3d 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -511,6 +511,44 @@ static HRESULT uia_raise_serverside_event(struct uia_queue_uia_event *event) return hr; }
+/* Check the parent chain of HWNDs, excluding the desktop. */ +static BOOL uia_win_event_hwnd_map_contains_ancestors(struct rb_tree *hwnd_map, HWND hwnd) +{ + HWND parent = GetAncestor(hwnd, GA_PARENT); + const HWND desktop = GetDesktopWindow(); + + while (parent && (parent != desktop)) + { + if (uia_hwnd_map_check_hwnd(hwnd_map, parent)) + return TRUE; + + parent = GetAncestor(parent, GA_PARENT); + } + + return FALSE; +} + +static HRESULT uia_win_event_for_each_callback(struct uia_event *event, void *data) +{ + struct uia_queue_win_event *win_event = (struct uia_queue_win_event *)data; + + /* + * Check if this HWND, or any of it's ancestors (excluding the desktop) + * are in our scope. + */ + if (!uia_hwnd_map_check_hwnd(&event->u.clientside.win_event_hwnd_map, win_event->hwnd) && + !uia_win_event_hwnd_map_contains_ancestors(&event->u.clientside.win_event_hwnd_map, win_event->hwnd)) + return S_OK; + + /* Has a native serverside provider, no need to do WinEvent translation. */ + if (UiaHasServerSideProvider(win_event->hwnd)) + return S_OK; + + FIXME("IProxyProviderWinEventHandler usage is currently unimplemented.\n"); + + return S_OK; +} + static void uia_event_thread_process_queue(struct list *event_queue) { while (1) @@ -538,6 +576,15 @@ static void uia_event_thread_process_queue(struct list *event_queue) break; }
+ case QUEUE_EVENT_TYPE_WIN_EVENT: + { + struct uia_queue_win_event *win_event = (struct uia_queue_win_event *)event; + + hr = uia_event_for_each(win_event_to_uia_event_id(win_event->event_id), uia_win_event_for_each_callback, + (void *)win_event, TRUE); + break; + } + default: break; } diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index c298967be00..218392ef06c 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -255,6 +255,8 @@ HRESULT get_safearray_dim_bounds(SAFEARRAY *sa, UINT dim, LONG *lbound, LONG *el HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems) DECLSPEC_HIDDEN; int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type) DECLSPEC_HIDDEN; BOOL uia_hwnd_is_visible(HWND hwnd) DECLSPEC_HIDDEN; +BOOL uia_is_top_level_hwnd(HWND hwnd) DECLSPEC_HIDDEN; +BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd) DECLSPEC_HIDDEN; HRESULT uia_hwnd_map_add_hwnd(struct rb_tree *hwnd_map, HWND hwnd) DECLSPEC_HIDDEN; void uia_hwnd_map_init(struct rb_tree *hwnd_map) DECLSPEC_HIDDEN; void uia_hwnd_map_destroy(struct rb_tree *hwnd_map) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 269ce63a2fd..6a3b2d061fe 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1545,11 +1545,6 @@ static HRESULT uia_send_message_timeout(HWND hwnd, UINT msg, WPARAM wparam, LPAR return S_OK; }
-static BOOL is_top_level_hwnd(HWND hwnd) -{ - return GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow(); -} - static HRESULT get_uia_control_type_for_hwnd(HWND hwnd, int *control_type) { LONG_PTR style, ex_style; @@ -1576,7 +1571,7 @@ static HRESULT get_uia_control_type_for_hwnd(HWND hwnd, int *control_type) }
/* Non top-level HWNDs are considered panes as well. */ - if (!is_top_level_hwnd(hwnd)) + if (!uia_is_top_level_hwnd(hwnd)) *control_type = UIA_PaneControlTypeId; else *control_type = UIA_WindowControlTypeId; @@ -1816,7 +1811,7 @@ static HRESULT WINAPI base_hwnd_fragment_Navigate(IRawElementProviderFragment *i * Top level owned windows have their owner window as a parent instead * of the desktop window. */ - if (is_top_level_hwnd(base_hwnd_prov->hwnd) && (owner = GetWindow(base_hwnd_prov->hwnd, GW_OWNER))) + if (uia_is_top_level_hwnd(base_hwnd_prov->hwnd) && (owner = GetWindow(base_hwnd_prov->hwnd, GW_OWNER))) parent = owner; else parent = GetAncestor(base_hwnd_prov->hwnd, GA_PARENT); @@ -1866,7 +1861,7 @@ static HRESULT WINAPI base_hwnd_fragment_get_BoundingRectangle(IRawElementProvid memset(ret_val, 0, sizeof(*ret_val));
/* Top level minimized window - Return empty rect. */ - if (is_top_level_hwnd(base_hwnd_prov->hwnd) && IsIconic(base_hwnd_prov->hwnd)) + if (uia_is_top_level_hwnd(base_hwnd_prov->hwnd) && IsIconic(base_hwnd_prov->hwnd)) return S_OK;
if (!GetWindowRect(base_hwnd_prov->hwnd, &rect)) diff --git a/dlls/uiautomationcore/uia_utils.c b/dlls/uiautomationcore/uia_utils.c index 9840fe4fe40..866358f97c8 100644 --- a/dlls/uiautomationcore/uia_utils.c +++ b/dlls/uiautomationcore/uia_utils.c @@ -404,6 +404,11 @@ BOOL uia_hwnd_is_visible(HWND hwnd) return TRUE; }
+BOOL uia_is_top_level_hwnd(HWND hwnd) +{ + return GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow(); +} + /* * rbtree to efficiently store a collection of HWNDs. */ @@ -429,7 +434,7 @@ static void uia_hwnd_map_free(struct rb_entry *entry, void *context) free(hwnd_entry); }
-static BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd) +BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd) { return !!rb_get(hwnd_map, hwnd); }