Commit 81caccbf authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Track HWNDs that need WinEvent translation.

parent 2a2c4cd7
......@@ -1870,6 +1870,9 @@ static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PT
&IID_IProxyProviderWinEventHandler, (void **)&winevent_handler)))
{
FIXME("MSAA to UIA event bridge currently unimplemented\n");
hr = uia_event_add_win_event_hwnd(event, prov->hwnd);
if (FAILED(hr))
WARN("Failed to add hwnd for win_event, hr %#lx\n", hr);
IProxyProviderWinEventHandler_Release(winevent_handler);
}
else if (SUCCEEDED(IRawElementProviderFragmentRoot_QueryInterface(elroot, &IID_IRawElementProviderAdviseEvents,
......@@ -1954,6 +1957,7 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid
prov->IWineUiaProvider_iface.lpVtbl = &uia_provider_vtbl;
prov->elprov = elprov;
prov->ref = 1;
prov->hwnd = node->hwnd;
node->prov[prov_type] = &prov->IWineUiaProvider_iface;
if (!node->prov_count)
node->creator_prov_type = prov_type;
......
......@@ -64,6 +64,29 @@ static int win_event_to_uia_event_id(int win_event)
return 0;
}
static BOOL CALLBACK uia_win_event_enum_top_level_hwnds(HWND hwnd, LPARAM lparam)
{
struct rb_tree *hwnd_map = (struct rb_tree *)lparam;
HRESULT hr;
if (!uia_hwnd_is_visible(hwnd))
return TRUE;
hr = uia_hwnd_map_add_hwnd(hwnd_map, hwnd);
if (FAILED(hr))
WARN("Failed to add hwnd to map, hr %#lx\n", hr);
return TRUE;
}
HRESULT uia_event_add_win_event_hwnd(struct uia_event *event, HWND hwnd)
{
if (hwnd == GetDesktopWindow())
EnumWindows(uia_win_event_enum_top_level_hwnds, (LPARAM)&event->u.clientside.win_event_hwnd_map);
return uia_hwnd_map_add_hwnd(&event->u.clientside.win_event_hwnd_map, hwnd);
}
/*
* UI Automation event map.
*/
......@@ -658,6 +681,7 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface)
uia_cache_request_destroy(&event->u.clientside.cache_req);
if (event->u.clientside.git_cookie)
uia_stop_event_thread();
uia_hwnd_map_destroy(&event->u.clientside.win_event_hwnd_map);
}
else
{
......@@ -834,6 +858,7 @@ static HRESULT create_clientside_uia_event(struct uia_event **out_event, int eve
event->scope = scope;
event->u.clientside.event_callback = cback;
event->u.clientside.callback_data = cback_data;
uia_hwnd_map_init(&event->u.clientside.win_event_hwnd_map);
*out_event = event;
return S_OK;
......
......@@ -95,6 +95,7 @@ struct uia_provider {
BOOL return_nested_node;
BOOL parent_check_ran;
BOOL has_parent;
HWND hwnd;
};
static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider *iface)
......@@ -140,6 +141,7 @@ struct uia_event
HRESULT (*event_callback)(struct uia_event *, struct uia_event_args *, SAFEARRAY *, BSTR);
void *callback_data;
struct rb_tree win_event_hwnd_map;
DWORD git_cookie;
} clientside;
struct {
......@@ -218,6 +220,7 @@ BOOL uia_condition_matched(HRESULT hr) DECLSPEC_HIDDEN;
HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN;
/* uia_event.c */
HRESULT uia_event_add_win_event_hwnd(struct uia_event *event, HWND hwnd) DECLSPEC_HIDDEN;
HRESULT create_serverside_uia_event(struct uia_event **out_event, LONG process_id, LONG event_cookie) DECLSPEC_HIDDEN;
HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events,
struct uia_event *event) DECLSPEC_HIDDEN;
......@@ -250,3 +253,7 @@ HRESULT uia_cache_request_clone(struct UiaCacheRequest *dst, struct UiaCacheRequ
HRESULT get_safearray_dim_bounds(SAFEARRAY *sa, UINT dim, LONG *lbound, LONG *elems) DECLSPEC_HIDDEN;
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;
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;
......@@ -384,3 +384,82 @@ int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type)
return 0;
}
/*
* HWND related helper functions.
*/
BOOL uia_hwnd_is_visible(HWND hwnd)
{
RECT rect;
if (!IsWindowVisible(hwnd))
return FALSE;
if (!GetWindowRect(hwnd, &rect))
return FALSE;
if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0)
return FALSE;
return TRUE;
}
/*
* rbtree to efficiently store a collection of HWNDs.
*/
struct uia_hwnd_map_entry
{
struct rb_entry entry;
HWND hwnd;
};
static int uia_hwnd_map_hwnd_compare(const void *key, const struct rb_entry *entry)
{
struct uia_hwnd_map_entry *hwnd_entry = RB_ENTRY_VALUE(entry, struct uia_hwnd_map_entry, entry);
HWND hwnd = (HWND)key;
return (hwnd_entry->hwnd > hwnd) - (hwnd_entry->hwnd < hwnd);
}
static void uia_hwnd_map_free(struct rb_entry *entry, void *context)
{
struct uia_hwnd_map_entry *hwnd_entry = RB_ENTRY_VALUE(entry, struct uia_hwnd_map_entry, entry);
TRACE("Removing hwnd %p from map %p\n", hwnd_entry->hwnd, context);
free(hwnd_entry);
}
static BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
{
return !!rb_get(hwnd_map, hwnd);
}
HRESULT uia_hwnd_map_add_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
{
struct uia_hwnd_map_entry *entry;
if (uia_hwnd_map_check_hwnd(hwnd_map, hwnd))
{
TRACE("hwnd %p already in map %p\n", hwnd, hwnd_map);
return S_OK;
}
if (!(entry = calloc(1, sizeof(*entry))))
return E_OUTOFMEMORY;
TRACE("Adding hwnd %p to map %p\n", hwnd, hwnd_map);
entry->hwnd = hwnd;
rb_put(hwnd_map, hwnd, &entry->entry);
return S_OK;
}
void uia_hwnd_map_init(struct rb_tree *hwnd_map)
{
rb_init(hwnd_map, uia_hwnd_map_hwnd_compare);
}
void uia_hwnd_map_destroy(struct rb_tree *hwnd_map)
{
rb_destroy(hwnd_map, uia_hwnd_map_free, hwnd_map);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment