| /* |
| * MACDRV Cocoa event queue code |
| * |
| * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <sys/types.h> |
| #include <sys/event.h> |
| #include <sys/time.h> |
| #include <libkern/OSAtomic.h> |
| #import <Carbon/Carbon.h> |
| |
| #include "macdrv_cocoa.h" |
| #import "cocoa_event.h" |
| #import "cocoa_app.h" |
| #import "cocoa_window.h" |
| |
| |
| static NSString* const WineEventQueueThreadDictionaryKey = @"WineEventQueueThreadDictionaryKey"; |
| |
| static NSString* const WineHotKeyMacIDKey = @"macID"; |
| static NSString* const WineHotKeyVkeyKey = @"vkey"; |
| static NSString* const WineHotKeyModFlagsKey = @"modFlags"; |
| static NSString* const WineHotKeyKeyCodeKey = @"keyCode"; |
| static NSString* const WineHotKeyCarbonRefKey = @"hotKeyRef"; |
| static const OSType WineHotKeySignature = 'Wine'; |
| |
| |
| @interface MacDrvEvent : NSObject |
| { |
| @public |
| macdrv_event* event; |
| } |
| |
| - (id) initWithEvent:(macdrv_event*)event; |
| |
| @end |
| |
| @implementation MacDrvEvent |
| |
| - (id) initWithEvent:(macdrv_event*)inEvent |
| { |
| self = [super init]; |
| if (self) |
| { |
| event = macdrv_retain_event(inEvent); |
| } |
| return self; |
| } |
| |
| - (void) dealloc |
| { |
| if (event) macdrv_release_event(event); |
| [super dealloc]; |
| } |
| |
| @end |
| |
| |
| @implementation WineEventQueue |
| |
| - (id) init |
| { |
| [self doesNotRecognizeSelector:_cmd]; |
| [self release]; |
| return nil; |
| } |
| |
| - (id) initWithEventHandler:(macdrv_event_handler)handler |
| { |
| NSParameterAssert(handler != nil); |
| |
| self = [super init]; |
| if (self != nil) |
| { |
| struct kevent kev; |
| int rc; |
| |
| fds[0] = fds[1] = kq = -1; |
| |
| event_handler = handler; |
| events = [[NSMutableArray alloc] init]; |
| eventsLock = [[NSLock alloc] init]; |
| |
| if (!events || !eventsLock) |
| { |
| [self release]; |
| return nil; |
| } |
| |
| if (pipe(fds) || |
| fcntl(fds[0], F_SETFD, 1) == -1 || |
| fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 || |
| fcntl(fds[1], F_SETFD, 1) == -1 || |
| fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1) |
| { |
| [self release]; |
| return nil; |
| } |
| |
| kq = kqueue(); |
| if (kq < 0) |
| { |
| [self release]; |
| return nil; |
| } |
| |
| EV_SET(&kev, fds[0], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); |
| do |
| { |
| rc = kevent(kq, &kev, 1, NULL, 0, NULL); |
| } while (rc == -1 && errno == EINTR); |
| if (rc == -1) |
| { |
| [self release]; |
| return nil; |
| } |
| } |
| return self; |
| } |
| |
| - (void) dealloc |
| { |
| NSNumber* hotKeyMacID; |
| |
| for (hotKeyMacID in hotKeysByMacID) |
| { |
| NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:hotKeyMacID]; |
| EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue]; |
| UnregisterEventHotKey(hotKeyRef); |
| } |
| [hotKeysByMacID release]; |
| [hotKeysByWinID release]; |
| [events release]; |
| [eventsLock release]; |
| |
| if (kq != -1) close(kq); |
| if (fds[0] != -1) close(fds[0]); |
| if (fds[1] != -1) close(fds[1]); |
| |
| [super dealloc]; |
| } |
| |
| - (void) signalEventAvailable |
| { |
| char junk = 1; |
| int rc; |
| |
| do |
| { |
| rc = write(fds[1], &junk, 1); |
| } while (rc < 0 && errno == EINTR); |
| |
| if (rc < 0 && errno != EAGAIN) |
| ERR(@"%@: got error writing to event queue signaling pipe: %s\n", self, strerror(errno)); |
| } |
| |
| - (void) postEventObject:(MacDrvEvent*)event |
| { |
| NSIndexSet* indexes; |
| MacDrvEvent* lastEvent; |
| |
| [eventsLock lock]; |
| |
| indexes = [events indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){ |
| return ((MacDrvEvent*)obj)->event->deliver <= 0; |
| }]; |
| [events removeObjectsAtIndexes:indexes]; |
| |
| if ((event->event->type == MOUSE_MOVED || |
| event->event->type == MOUSE_MOVED_ABSOLUTE) && |
| event->event->deliver == INT_MAX && |
| (lastEvent = [events lastObject]) && |
| (lastEvent->event->type == MOUSE_MOVED || |
| lastEvent->event->type == MOUSE_MOVED_ABSOLUTE) && |
| lastEvent->event->deliver == INT_MAX && |
| lastEvent->event->window == event->event->window && |
| lastEvent->event->mouse_moved.drag == event->event->mouse_moved.drag) |
| { |
| if (event->event->type == MOUSE_MOVED) |
| { |
| lastEvent->event->mouse_moved.x += event->event->mouse_moved.x; |
| lastEvent->event->mouse_moved.y += event->event->mouse_moved.y; |
| } |
| else |
| { |
| lastEvent->event->type = MOUSE_MOVED_ABSOLUTE; |
| lastEvent->event->mouse_moved.x = event->event->mouse_moved.x; |
| lastEvent->event->mouse_moved.y = event->event->mouse_moved.y; |
| } |
| |
| lastEvent->event->mouse_moved.time_ms = event->event->mouse_moved.time_ms; |
| } |
| else |
| [events addObject:event]; |
| |
| [eventsLock unlock]; |
| |
| [self signalEventAvailable]; |
| } |
| |
| - (void) postEvent:(macdrv_event*)inEvent |
| { |
| MacDrvEvent* event = [[MacDrvEvent alloc] initWithEvent:inEvent]; |
| [self postEventObject:event]; |
| [event release]; |
| } |
| |
| - (MacDrvEvent*) getEventMatchingMask:(macdrv_event_mask)mask |
| { |
| char buf[512]; |
| int rc; |
| NSUInteger index; |
| MacDrvEvent* ret = nil; |
| |
| /* Clear the pipe which signals there are pending events. */ |
| do |
| { |
| rc = read(fds[0], buf, sizeof(buf)); |
| } while (rc > 0 || (rc < 0 && errno == EINTR)); |
| if (rc == 0 || (rc < 0 && errno != EAGAIN)) |
| { |
| if (rc == 0) |
| ERR(@"%@: event queue signaling pipe unexpectedly closed\n", self); |
| else |
| ERR(@"%@: got error reading from event queue signaling pipe: %s\n", self, strerror(errno)); |
| return nil; |
| } |
| |
| [eventsLock lock]; |
| |
| index = 0; |
| while (index < [events count]) |
| { |
| MacDrvEvent* event = [events objectAtIndex:index]; |
| if (event_mask_for_type(event->event->type) & mask) |
| { |
| [[event retain] autorelease]; |
| [events removeObjectAtIndex:index]; |
| |
| if (event->event->deliver == INT_MAX || |
| OSAtomicDecrement32Barrier(&event->event->deliver) >= 0) |
| { |
| ret = event; |
| break; |
| } |
| } |
| else |
| index++; |
| } |
| |
| [eventsLock unlock]; |
| return ret; |
| } |
| |
| - (void) discardEventsPassingTest:(BOOL (^)(macdrv_event* event))block |
| { |
| NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| NSIndexSet* indexes; |
| |
| [eventsLock lock]; |
| |
| indexes = [events indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){ |
| MacDrvEvent* event = obj; |
| return block(event->event); |
| }]; |
| |
| [events removeObjectsAtIndexes:indexes]; |
| |
| [eventsLock unlock]; |
| |
| [pool release]; |
| } |
| |
| - (void) discardEventsMatchingMask:(macdrv_event_mask)mask forWindow:(NSWindow*)window |
| { |
| [self discardEventsPassingTest:^BOOL (macdrv_event* event){ |
| return ((event_mask_for_type(event->type) & mask) && |
| (!window || event->window == (macdrv_window)window)); |
| }]; |
| } |
| |
| - (BOOL) query:(macdrv_query*)query timeout:(NSTimeInterval)timeout flags:(NSUInteger)flags |
| { |
| int type; |
| macdrv_event* event; |
| NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout]; |
| BOOL timedout; |
| |
| type = (flags & WineQueryNoPreemptWait) ? QUERY_EVENT_NO_PREEMPT_WAIT : QUERY_EVENT; |
| event = macdrv_create_event(type, (WineWindow*)query->window); |
| event->query_event.query = macdrv_retain_query(query); |
| query->done = FALSE; |
| |
| [self postEvent:event]; |
| macdrv_release_event(event); |
| timedout = ![[WineApplicationController sharedController] waitUntilQueryDone:&query->done |
| timeout:timeoutDate |
| processEvents:(flags & WineQueryProcessEvents) != 0]; |
| return !timedout && query->status; |
| } |
| |
| - (BOOL) query:(macdrv_query*)query timeout:(NSTimeInterval)timeout |
| { |
| return [self query:query timeout:timeout flags:0]; |
| } |
| |
| - (void) resetMouseEventPositions:(CGPoint)pos |
| { |
| MacDrvEvent* event; |
| |
| pos = cgpoint_win_from_mac(pos); |
| |
| [eventsLock lock]; |
| |
| for (event in events) |
| { |
| if (event->event->type == MOUSE_BUTTON) |
| { |
| event->event->mouse_button.x = pos.x; |
| event->event->mouse_button.y = pos.y; |
| } |
| else if (event->event->type == MOUSE_SCROLL) |
| { |
| event->event->mouse_scroll.x = pos.x; |
| event->event->mouse_scroll.y = pos.y; |
| } |
| } |
| |
| [eventsLock unlock]; |
| } |
| |
| - (BOOL) postHotKeyEvent:(UInt32)hotKeyNumber time:(double)time |
| { |
| NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:[NSNumber numberWithUnsignedInt:hotKeyNumber]]; |
| if (hotKeyDict) |
| { |
| macdrv_event* event; |
| |
| event = macdrv_create_event(HOTKEY_PRESS, nil); |
| event->hotkey_press.vkey = [[hotKeyDict objectForKey:WineHotKeyVkeyKey] unsignedIntValue]; |
| event->hotkey_press.mod_flags = [[hotKeyDict objectForKey:WineHotKeyModFlagsKey] unsignedIntValue]; |
| event->hotkey_press.keycode = [[hotKeyDict objectForKey:WineHotKeyKeyCodeKey] unsignedIntValue]; |
| event->hotkey_press.time_ms = [[WineApplicationController sharedController] ticksForEventTime:time]; |
| |
| [self postEvent:event]; |
| |
| macdrv_release_event(event); |
| } |
| |
| return hotKeyDict != nil; |
| } |
| |
| static OSStatus HotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) |
| { |
| WineEventQueue* self = userData; |
| OSStatus status; |
| EventHotKeyID hotKeyID; |
| |
| status = GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, |
| sizeof(hotKeyID), NULL, &hotKeyID); |
| if (status == noErr) |
| { |
| if (hotKeyID.signature != WineHotKeySignature || |
| ![self postHotKeyEvent:hotKeyID.id time:GetEventTime(theEvent)]) |
| status = eventNotHandledErr; |
| } |
| |
| return status; |
| } |
| |
| - (void) unregisterHotKey:(unsigned int)vkey modFlags:(unsigned int)modFlags |
| { |
| NSNumber* vkeyNumber = [NSNumber numberWithUnsignedInt:vkey]; |
| NSNumber* modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags]; |
| NSArray* winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil]; |
| NSDictionary* hotKeyDict = [hotKeysByWinID objectForKey:winIDPair]; |
| if (hotKeyDict) |
| { |
| EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue]; |
| NSNumber* macID = [hotKeyDict objectForKey:WineHotKeyMacIDKey]; |
| |
| UnregisterEventHotKey(hotKeyRef); |
| [hotKeysByMacID removeObjectForKey:macID]; |
| [hotKeysByWinID removeObjectForKey:winIDPair]; |
| } |
| } |
| |
| - (int) registerHotKey:(UInt32)keyCode modifiers:(UInt32)modifiers vkey:(unsigned int)vkey modFlags:(unsigned int)modFlags |
| { |
| static EventHandlerRef handler; |
| static UInt32 hotKeyNumber; |
| OSStatus status; |
| NSNumber* vkeyNumber; |
| NSNumber* modFlagsNumber; |
| NSArray* winIDPair; |
| EventHotKeyID hotKeyID; |
| EventHotKeyRef hotKeyRef; |
| NSNumber* macIDNumber; |
| NSDictionary* hotKeyDict; |
| |
| if (!handler) |
| { |
| EventTypeSpec eventType = { kEventClassKeyboard, kEventHotKeyPressed }; |
| status = InstallApplicationEventHandler(HotKeyHandler, 1, &eventType, self, &handler); |
| if (status != noErr) |
| { |
| ERR(@"InstallApplicationEventHandler() failed: %d\n", status); |
| handler = NULL; |
| return MACDRV_HOTKEY_FAILURE; |
| } |
| } |
| |
| if (!hotKeysByMacID && !(hotKeysByMacID = [[NSMutableDictionary alloc] init])) |
| return MACDRV_HOTKEY_FAILURE; |
| if (!hotKeysByWinID && !(hotKeysByWinID = [[NSMutableDictionary alloc] init])) |
| return MACDRV_HOTKEY_FAILURE; |
| |
| vkeyNumber = [NSNumber numberWithUnsignedInt:vkey]; |
| modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags]; |
| winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil]; |
| if ([hotKeysByWinID objectForKey:winIDPair]) |
| return MACDRV_HOTKEY_ALREADY_REGISTERED; |
| |
| hotKeyID.signature = WineHotKeySignature; |
| hotKeyID.id = hotKeyNumber++; |
| |
| status = RegisterEventHotKey(keyCode, modifiers, hotKeyID, GetApplicationEventTarget(), |
| kEventHotKeyExclusive, &hotKeyRef); |
| if (status == eventHotKeyExistsErr) |
| return MACDRV_HOTKEY_ALREADY_REGISTERED; |
| if (status != noErr) |
| { |
| ERR(@"RegisterEventHotKey() failed: %d\n", status); |
| return MACDRV_HOTKEY_FAILURE; |
| } |
| |
| macIDNumber = [NSNumber numberWithUnsignedInt:hotKeyID.id]; |
| hotKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: |
| macIDNumber, WineHotKeyMacIDKey, |
| vkeyNumber, WineHotKeyVkeyKey, |
| modFlagsNumber, WineHotKeyModFlagsKey, |
| [NSNumber numberWithUnsignedInt:keyCode], WineHotKeyKeyCodeKey, |
| [NSValue valueWithPointer:hotKeyRef], WineHotKeyCarbonRefKey, |
| nil]; |
| [hotKeysByMacID setObject:hotKeyDict forKey:macIDNumber]; |
| [hotKeysByWinID setObject:hotKeyDict forKey:winIDPair]; |
| |
| return MACDRV_HOTKEY_SUCCESS; |
| } |
| |
| |
| /*********************************************************************** |
| * OnMainThread |
| * |
| * Run a block on the main thread synchronously. |
| */ |
| void OnMainThread(dispatch_block_t block) |
| { |
| NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary]; |
| WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey]; |
| dispatch_semaphore_t semaphore = NULL; |
| __block BOOL finished; |
| |
| if (!queue) |
| { |
| semaphore = dispatch_semaphore_create(0); |
| dispatch_retain(semaphore); |
| } |
| |
| finished = FALSE; |
| OnMainThreadAsync(^{ |
| block(); |
| finished = TRUE; |
| if (queue) |
| [queue signalEventAvailable]; |
| else |
| { |
| dispatch_semaphore_signal(semaphore); |
| dispatch_release(semaphore); |
| } |
| }); |
| |
| if (queue) |
| { |
| while (!finished) |
| { |
| MacDrvEvent* macDrvEvent; |
| struct kevent kev; |
| |
| while (!finished && |
| (macDrvEvent = [queue getEventMatchingMask:event_mask_for_type(QUERY_EVENT)])) |
| { |
| queue->event_handler(macDrvEvent->event); |
| } |
| |
| if (!finished) |
| { |
| [pool release]; |
| pool = [[NSAutoreleasePool alloc] init]; |
| |
| kevent(queue->kq, NULL, 0, &kev, 1, NULL); |
| } |
| } |
| } |
| else |
| { |
| dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); |
| dispatch_release(semaphore); |
| } |
| |
| [pool release]; |
| } |
| |
| |
| /*********************************************************************** |
| * macdrv_create_event_queue |
| * |
| * Register this thread with the application on the main thread, and set |
| * up an event queue on which it can deliver events to this thread. |
| */ |
| macdrv_event_queue macdrv_create_event_queue(macdrv_event_handler handler) |
| { |
| NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary]; |
| |
| WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey]; |
| if (!queue) |
| { |
| queue = [[[WineEventQueue alloc] initWithEventHandler:handler] autorelease]; |
| if (queue) |
| { |
| if ([[WineApplicationController sharedController] registerEventQueue:queue]) |
| [threadDict setObject:queue forKey:WineEventQueueThreadDictionaryKey]; |
| else |
| queue = nil; |
| } |
| } |
| |
| [pool release]; |
| return (macdrv_event_queue)queue; |
| } |
| |
| /*********************************************************************** |
| * macdrv_destroy_event_queue |
| * |
| * Tell the application that this thread is exiting and destroy the |
| * associated event queue. |
| */ |
| void macdrv_destroy_event_queue(macdrv_event_queue queue) |
| { |
| NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| WineEventQueue* q = (WineEventQueue*)queue; |
| NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary]; |
| |
| [[WineApplicationController sharedController] unregisterEventQueue:q]; |
| [threadDict removeObjectForKey:WineEventQueueThreadDictionaryKey]; |
| |
| [pool release]; |
| } |
| |
| /*********************************************************************** |
| * macdrv_get_event_queue_fd |
| * |
| * Get the file descriptor whose readability signals that there are |
| * events on the event queue. |
| */ |
| int macdrv_get_event_queue_fd(macdrv_event_queue queue) |
| { |
| WineEventQueue* q = (WineEventQueue*)queue; |
| return q->fds[0]; |
| } |
| |
| /*********************************************************************** |
| * macdrv_copy_event_from_queue |
| * |
| * Pull an event matching the event mask from the event queue and store |
| * it in the event record pointed to by the event parameter. If a |
| * matching event was found, return non-zero; otherwise, return 0. |
| * |
| * The caller is responsible for calling macdrv_release_event on any |
| * event returned by this function. |
| */ |
| int macdrv_copy_event_from_queue(macdrv_event_queue queue, |
| macdrv_event_mask mask, macdrv_event **event) |
| { |
| NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| WineEventQueue* q = (WineEventQueue*)queue; |
| |
| MacDrvEvent* macDrvEvent = [q getEventMatchingMask:mask]; |
| if (macDrvEvent) |
| *event = macdrv_retain_event(macDrvEvent->event); |
| |
| [pool release]; |
| return (macDrvEvent != nil); |
| } |
| |
| /*********************************************************************** |
| * macdrv_create_event |
| */ |
| macdrv_event* macdrv_create_event(int type, WineWindow* window) |
| { |
| macdrv_event *event; |
| |
| event = calloc(1, sizeof(*event)); |
| event->refs = 1; |
| event->deliver = INT_MAX; |
| event->type = type; |
| event->window = (macdrv_window)[window retain]; |
| return event; |
| } |
| |
| /*********************************************************************** |
| * macdrv_retain_event |
| */ |
| macdrv_event* macdrv_retain_event(macdrv_event *event) |
| { |
| OSAtomicIncrement32Barrier(&event->refs); |
| return event; |
| } |
| |
| /*********************************************************************** |
| * macdrv_release_event |
| * |
| * Decrements the reference count of an event. If the count falls to |
| * zero, cleans up any resources, such as allocated memory or retained |
| * objects, held by the event and deallocates it |
| */ |
| void macdrv_release_event(macdrv_event *event) |
| { |
| if (OSAtomicDecrement32Barrier(&event->refs) <= 0) |
| { |
| NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| |
| switch (event->type) |
| { |
| case IM_SET_TEXT: |
| if (event->im_set_text.text) |
| CFRelease(event->im_set_text.text); |
| break; |
| case KEYBOARD_CHANGED: |
| CFRelease(event->keyboard_changed.uchr); |
| CFRelease(event->keyboard_changed.input_source); |
| break; |
| case QUERY_EVENT: |
| case QUERY_EVENT_NO_PREEMPT_WAIT: |
| macdrv_release_query(event->query_event.query); |
| break; |
| case WINDOW_GOT_FOCUS: |
| [(NSMutableSet*)event->window_got_focus.tried_windows release]; |
| break; |
| } |
| |
| [(WineWindow*)event->window release]; |
| free(event); |
| |
| [pool release]; |
| } |
| } |
| |
| /*********************************************************************** |
| * macdrv_create_query |
| */ |
| macdrv_query* macdrv_create_query(void) |
| { |
| macdrv_query *query; |
| |
| query = calloc(1, sizeof(*query)); |
| query->refs = 1; |
| return query; |
| } |
| |
| /*********************************************************************** |
| * macdrv_retain_query |
| */ |
| macdrv_query* macdrv_retain_query(macdrv_query *query) |
| { |
| OSAtomicIncrement32Barrier(&query->refs); |
| return query; |
| } |
| |
| /*********************************************************************** |
| * macdrv_release_query |
| */ |
| void macdrv_release_query(macdrv_query *query) |
| { |
| if (OSAtomicDecrement32Barrier(&query->refs) <= 0) |
| { |
| switch (query->type) |
| { |
| case QUERY_DRAG_OPERATION: |
| if (query->drag_operation.pasteboard) |
| CFRelease(query->drag_operation.pasteboard); |
| break; |
| case QUERY_DRAG_DROP: |
| if (query->drag_drop.pasteboard) |
| CFRelease(query->drag_drop.pasteboard); |
| break; |
| case QUERY_PASTEBOARD_DATA: |
| if (query->pasteboard_data.type) |
| CFRelease(query->pasteboard_data.type); |
| break; |
| } |
| [(WineWindow*)query->window release]; |
| free(query); |
| } |
| } |
| |
| /*********************************************************************** |
| * macdrv_set_query_done |
| */ |
| void macdrv_set_query_done(macdrv_query *query) |
| { |
| macdrv_retain_query(query); |
| |
| OnMainThreadAsync(^{ |
| NSEvent* event; |
| |
| query->done = TRUE; |
| macdrv_release_query(query); |
| |
| event = [NSEvent otherEventWithType:NSApplicationDefined |
| location:NSZeroPoint |
| modifierFlags:0 |
| timestamp:[[NSProcessInfo processInfo] systemUptime] |
| windowNumber:0 |
| context:nil |
| subtype:WineApplicationEventWakeQuery |
| data1:0 |
| data2:0]; |
| [NSApp postEvent:event atStart:TRUE]; |
| }); |
| } |
| |
| @end |
| |
| |
| /*********************************************************************** |
| * macdrv_register_hot_key |
| */ |
| int macdrv_register_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags, |
| unsigned int keycode, unsigned int modifiers) |
| { |
| WineEventQueue* queue = (WineEventQueue*)q; |
| __block int ret; |
| |
| OnMainThread(^{ |
| ret = [queue registerHotKey:keycode modifiers:modifiers vkey:vkey modFlags:mod_flags]; |
| }); |
| |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * macdrv_unregister_hot_key |
| */ |
| void macdrv_unregister_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags) |
| { |
| WineEventQueue* queue = (WineEventQueue*)q; |
| |
| OnMainThreadAsync(^{ |
| [queue unregisterHotKey:vkey modFlags:mod_flags]; |
| }); |
| } |