From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_event.c | 96 +++++++++++++++++++++++++++++ dlls/uiautomationcore/uia_private.h | 3 + 2 files changed, 99 insertions(+)
diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 7fd4eda8ead..fb3b40f3d1e 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -19,9 +19,86 @@ #include "uia_private.h"
#include "wine/debug.h" +#include "wine/rbtree.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+/* + * UI Automation event map. + */ +static struct uia_event_map +{ + struct rb_tree event_map; + LONG event_count; +} uia_event_map; + +struct uia_event_map_entry +{ + struct rb_entry entry; + + int event_id; + struct list events_list; +}; + +static CRITICAL_SECTION event_map_cs; +static CRITICAL_SECTION_DEBUG event_map_cs_debug = +{ + 0, 0, &event_map_cs, + { &event_map_cs_debug.ProcessLocksList, &event_map_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": event_map_cs") } +}; +static CRITICAL_SECTION event_map_cs = { &event_map_cs_debug, -1, 0, 0, 0, 0 }; + +static int uia_event_map_id_compare(const void *key, const struct rb_entry *entry) +{ + struct uia_event_map_entry *event_entry = RB_ENTRY_VALUE(entry, struct uia_event_map_entry, entry); + int event_id = *((int *)key); + + return (event_entry->event_id > event_id) - (event_entry->event_id < event_id); +} + +static struct uia_event_map_entry *uia_get_event_map_entry_for_event(int event_id) +{ + struct uia_event_map_entry *map_entry = NULL; + struct rb_entry *rb_entry; + + EnterCriticalSection(&event_map_cs); + + if (uia_event_map.event_count && (rb_entry = rb_get(&uia_event_map.event_map, &event_id))) + map_entry = RB_ENTRY_VALUE(rb_entry, struct uia_event_map_entry, entry); + + LeaveCriticalSection(&event_map_cs); + return map_entry; +} + +static HRESULT uia_event_map_add_event(struct uia_event *event) +{ + struct uia_event_map_entry *event_entry = uia_get_event_map_entry_for_event(event->event_id); + + EnterCriticalSection(&event_map_cs); + if (!event_entry) + { + if (!(event_entry = heap_alloc_zero(sizeof(*event_entry)))) + { + LeaveCriticalSection(&event_map_cs); + return E_OUTOFMEMORY; + } + + event_entry->event_id = event->event_id; + list_init(&event_entry->events_list); + + if (InterlockedIncrement(&uia_event_map.event_count) == 1) + rb_init(&uia_event_map.event_map, uia_event_map_id_compare); + rb_put(&uia_event_map.event_map, &event->event_id, &event_entry->entry); + } + + list_add_head(&event_entry->events_list, &event->event_list_entry); + event->event_map_entry = event_entry; + LeaveCriticalSection(&event_map_cs); + + return S_OK; +} + /* * IWineUiaEvent interface. */ @@ -61,6 +138,21 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) { int i;
+ if (event->event_map_entry) + { + EnterCriticalSection(&event_map_cs); + list_remove(&event->event_list_entry); + + /* Map entry has no more events for this event ID - destroy it. */ + if (list_empty(&event->event_map_entry->events_list)) + { + rb_remove(&uia_event_map.event_map, &event->event_map_entry->entry); + heap_free(event->event_map_entry); + InterlockedDecrement(&uia_event_map.event_count); + } + LeaveCriticalSection(&event_map_cs); + } + SafeArrayDestroy(event->runtime_id); for (i = 0; i < event->event_advisers_count; i++) IWineUiaEventAdviser_Release(event->event_advisers[i]); @@ -326,6 +418,10 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback if (FAILED(hr)) goto exit;
+ hr = uia_event_map_add_event(event); + if (FAILED(hr)) + goto exit; + *huiaevent = (HUIAEVENT)event;
exit: diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index bd5ca714b94..0d652dd7b13 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -106,6 +106,9 @@ struct uia_event int event_advisers_count; SIZE_T event_advisers_arr_size;
+ struct list event_list_entry; + struct uia_event_map_entry *event_map_entry; + UiaEventCallback *cback; };