vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / winemac.drv / cocoa_event.m
blob24f69b17a0a3d1501a96aa4a8ce3efa80dd1d9b0
1 /*
2  * MACDRV Cocoa event queue code
3  *
4  * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
21 #include <sys/types.h>
22 #include <sys/event.h>
23 #include <sys/time.h>
24 #include <libkern/OSAtomic.h>
25 #import <Carbon/Carbon.h>
27 #include "macdrv_cocoa.h"
28 #import "cocoa_event.h"
29 #import "cocoa_app.h"
30 #import "cocoa_window.h"
33 static NSString* const WineEventQueueThreadDictionaryKey = @"WineEventQueueThreadDictionaryKey";
35 static NSString* const WineHotKeyMacIDKey       = @"macID";
36 static NSString* const WineHotKeyVkeyKey        = @"vkey";
37 static NSString* const WineHotKeyModFlagsKey    = @"modFlags";
38 static NSString* const WineHotKeyKeyCodeKey     = @"keyCode";
39 static NSString* const WineHotKeyCarbonRefKey   = @"hotKeyRef";
40 static const OSType WineHotKeySignature = 'Wine';
43 @implementation NSEvent (WineExtensions)
45     static BOOL wine_commandKeyDown(NSUInteger flags)
46     {
47         return ((flags & (NSEventModifierFlagShift |
48                           NSEventModifierFlagControl |
49                           NSEventModifierFlagOption |
50                           NSEventModifierFlagCommand)) == NSEventModifierFlagCommand);
51     }
53     + (BOOL) wine_commandKeyDown
54     {
55         return wine_commandKeyDown([self modifierFlags]);
56     }
58     - (BOOL) wine_commandKeyDown
59     {
60         return wine_commandKeyDown([self modifierFlags]);
61     }
63 @end
66 @interface MacDrvEvent : NSObject
68 @public
69     macdrv_event* event;
72     - (id) initWithEvent:(macdrv_event*)event;
74 @end
76 @implementation MacDrvEvent
78     - (id) initWithEvent:(macdrv_event*)inEvent
79     {
80         self = [super init];
81         if (self)
82         {
83             event = macdrv_retain_event(inEvent);
84         }
85         return self;
86     }
88     - (void) dealloc
89     {
90         if (event) macdrv_release_event(event);
91         [super dealloc];
92     }
94 @end
97 @implementation WineEventQueue
99     - (id) init
100     {
101         [self doesNotRecognizeSelector:_cmd];
102         [self release];
103         return nil;
104     }
106     - (id) initWithEventHandler:(macdrv_event_handler)handler
107     {
108         NSParameterAssert(handler != nil);
110         self = [super init];
111         if (self != nil)
112         {
113             struct kevent kev;
114             int rc;
116             fds[0] = fds[1] = kq = -1;
118             event_handler = handler;
119             events = [[NSMutableArray alloc] init];
120             eventsLock = [[NSLock alloc] init];
122             if (!events || !eventsLock)
123             {
124                 [self release];
125                 return nil;
126             }
128             if (pipe(fds) ||
129                 fcntl(fds[0], F_SETFD, 1) == -1 ||
130                 fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
131                 fcntl(fds[1], F_SETFD, 1) == -1 ||
132                 fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1)
133             {
134                 [self release];
135                 return nil;
136             }
138             kq = kqueue();
139             if (kq < 0)
140             {
141                 [self release];
142                 return nil;
143             }
145             EV_SET(&kev, fds[0], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
146             do
147             {
148                 rc = kevent(kq, &kev, 1, NULL, 0, NULL);
149             } while (rc == -1 && errno == EINTR);
150             if (rc == -1)
151             {
152                 [self release];
153                 return nil;
154             }
155         }
156         return self;
157     }
159     - (void) dealloc
160     {
161         NSNumber* hotKeyMacID;
163         for (hotKeyMacID in hotKeysByMacID)
164         {
165             NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:hotKeyMacID];
166             EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue];
167             UnregisterEventHotKey(hotKeyRef);
168         }
169         [hotKeysByMacID release];
170         [hotKeysByWinID release];
171         [events release];
172         [eventsLock release];
174         if (kq != -1) close(kq);
175         if (fds[0] != -1) close(fds[0]);
176         if (fds[1] != -1) close(fds[1]);
178         [super dealloc];
179     }
181     - (void) signalEventAvailable
182     {
183         char junk = 1;
184         int rc;
186         do
187         {
188             rc = write(fds[1], &junk, 1);
189         } while (rc < 0 && errno == EINTR);
191         if (rc < 0 && errno != EAGAIN)
192             ERR(@"%@: got error writing to event queue signaling pipe: %s\n", self, strerror(errno));
193     }
195     - (void) postEventObject:(MacDrvEvent*)event
196     {
197         NSIndexSet* indexes;
198         MacDrvEvent* lastEvent;
200         [eventsLock lock];
202         indexes = [events indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
203             return ((MacDrvEvent*)obj)->event->deliver <= 0;
204         }];
205         [events removeObjectsAtIndexes:indexes];
207         if ((event->event->type == MOUSE_MOVED_RELATIVE ||
208              event->event->type == MOUSE_MOVED_ABSOLUTE) &&
209             event->event->deliver == INT_MAX &&
210             (lastEvent = [events lastObject]) &&
211             (lastEvent->event->type == MOUSE_MOVED_RELATIVE ||
212              lastEvent->event->type == MOUSE_MOVED_ABSOLUTE) &&
213             lastEvent->event->deliver == INT_MAX &&
214             lastEvent->event->window == event->event->window &&
215             lastEvent->event->mouse_moved.drag == event->event->mouse_moved.drag)
216         {
217             if (event->event->type == MOUSE_MOVED_RELATIVE)
218             {
219                 lastEvent->event->mouse_moved.x += event->event->mouse_moved.x;
220                 lastEvent->event->mouse_moved.y += event->event->mouse_moved.y;
221             }
222             else
223             {
224                 lastEvent->event->type = MOUSE_MOVED_ABSOLUTE;
225                 lastEvent->event->mouse_moved.x = event->event->mouse_moved.x;
226                 lastEvent->event->mouse_moved.y = event->event->mouse_moved.y;
227             }
229             lastEvent->event->mouse_moved.time_ms = event->event->mouse_moved.time_ms;
230         }
231         else
232             [events addObject:event];
234         [eventsLock unlock];
236         [self signalEventAvailable];
237     }
239     - (void) postEvent:(macdrv_event*)inEvent
240     {
241         MacDrvEvent* event = [[MacDrvEvent alloc] initWithEvent:inEvent];
242         [self postEventObject:event];
243         [event release];
244     }
246     - (MacDrvEvent*) getEventMatchingMask:(macdrv_event_mask)mask
247     {
248         char buf[512];
249         int rc;
250         NSUInteger index;
251         MacDrvEvent* ret = nil;
253         /* Clear the pipe which signals there are pending events. */
254         do
255         {
256             rc = read(fds[0], buf, sizeof(buf));
257         } while (rc > 0 || (rc < 0 && errno == EINTR));
258         if (rc == 0 || (rc < 0 && errno != EAGAIN))
259         {
260             if (rc == 0)
261                 ERR(@"%@: event queue signaling pipe unexpectedly closed\n", self);
262             else
263                 ERR(@"%@: got error reading from event queue signaling pipe: %s\n", self, strerror(errno));
264             return nil;
265         }
267         [eventsLock lock];
269         index = 0;
270         while (index < [events count])
271         {
272             MacDrvEvent* event = [events objectAtIndex:index];
273             if (event_mask_for_type(event->event->type) & mask)
274             {
275                 [[event retain] autorelease];
276                 [events removeObjectAtIndex:index];
278                 if (event->event->deliver == INT_MAX ||
279                     OSAtomicDecrement32Barrier(&event->event->deliver) >= 0)
280                 {
281                     ret = event;
282                     break;
283                 }
284             }
285             else
286                 index++;
287         }
289         [eventsLock unlock];
290         return ret;
291     }
293     - (void) discardEventsPassingTest:(BOOL (^)(macdrv_event* event))block
294     {
295         NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
296         NSIndexSet* indexes;
298         [eventsLock lock];
300         indexes = [events indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
301             MacDrvEvent* event = obj;
302             return block(event->event);
303         }];
305         [events removeObjectsAtIndexes:indexes];
307         [eventsLock unlock];
309         [pool release];
310     }
312     - (void) discardEventsMatchingMask:(macdrv_event_mask)mask forWindow:(NSWindow*)window
313     {
314         [self discardEventsPassingTest:^BOOL (macdrv_event* event){
315             return ((event_mask_for_type(event->type) & mask) &&
316                     (!window || event->window == (macdrv_window)window));
317         }];
318     }
320     - (BOOL) query:(macdrv_query*)query timeout:(NSTimeInterval)timeout flags:(NSUInteger)flags
321     {
322         int type;
323         macdrv_event* event;
324         NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];
325         BOOL timedout;
327         type = (flags & WineQueryNoPreemptWait) ? QUERY_EVENT_NO_PREEMPT_WAIT : QUERY_EVENT;
328         event = macdrv_create_event(type, (WineWindow*)query->window);
329         event->query_event.query = macdrv_retain_query(query);
330         query->done = FALSE;
332         [self postEvent:event];
333         macdrv_release_event(event);
334         timedout = ![[WineApplicationController sharedController] waitUntilQueryDone:&query->done
335                                                                              timeout:timeoutDate
336                                                                        processEvents:(flags & WineQueryProcessEvents) != 0];
337         return !timedout && query->status;
338     }
340     - (BOOL) query:(macdrv_query*)query timeout:(NSTimeInterval)timeout
341     {
342         return [self query:query timeout:timeout flags:0];
343     }
345     - (void) resetMouseEventPositions:(CGPoint)pos
346     {
347         MacDrvEvent* event;
349         pos = cgpoint_win_from_mac(pos);
351         [eventsLock lock];
353         for (event in events)
354         {
355             if (event->event->type == MOUSE_BUTTON)
356             {
357                 event->event->mouse_button.x = pos.x;
358                 event->event->mouse_button.y = pos.y;
359             }
360             else if (event->event->type == MOUSE_SCROLL)
361             {
362                 event->event->mouse_scroll.x = pos.x;
363                 event->event->mouse_scroll.y = pos.y;
364             }
365         }
367         [eventsLock unlock];
368     }
370     - (BOOL) postHotKeyEvent:(UInt32)hotKeyNumber time:(double)time
371     {
372         NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:[NSNumber numberWithUnsignedInt:hotKeyNumber]];
373         if (hotKeyDict)
374         {
375             macdrv_event* event;
377             event = macdrv_create_event(HOTKEY_PRESS, nil);
378             event->hotkey_press.vkey        = [[hotKeyDict objectForKey:WineHotKeyVkeyKey] unsignedIntValue];
379             event->hotkey_press.mod_flags   = [[hotKeyDict objectForKey:WineHotKeyModFlagsKey] unsignedIntValue];
380             event->hotkey_press.keycode     = [[hotKeyDict objectForKey:WineHotKeyKeyCodeKey] unsignedIntValue];
381             event->hotkey_press.time_ms     = [[WineApplicationController sharedController] ticksForEventTime:time];
383             [self postEvent:event];
385             macdrv_release_event(event);
386         }
388         return hotKeyDict != nil;
389     }
391     static OSStatus HotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
392     {
393         WineEventQueue* self = userData;
394         OSStatus status;
395         EventHotKeyID hotKeyID;
397         status = GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL,
398                                    sizeof(hotKeyID), NULL, &hotKeyID);
399         if (status == noErr)
400         {
401             if (hotKeyID.signature != WineHotKeySignature ||
402                 ![self postHotKeyEvent:hotKeyID.id time:GetEventTime(theEvent)])
403                 status = eventNotHandledErr;
404         }
406         return status;
407     }
409     - (void) unregisterHotKey:(unsigned int)vkey modFlags:(unsigned int)modFlags
410     {
411         NSNumber* vkeyNumber = [NSNumber numberWithUnsignedInt:vkey];
412         NSNumber* modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags];
413         NSArray* winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil];
414         NSDictionary* hotKeyDict = [hotKeysByWinID objectForKey:winIDPair];
415         if (hotKeyDict)
416         {
417             EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue];
418             NSNumber* macID = [hotKeyDict objectForKey:WineHotKeyMacIDKey];
420             UnregisterEventHotKey(hotKeyRef);
421             [hotKeysByMacID removeObjectForKey:macID];
422             [hotKeysByWinID removeObjectForKey:winIDPair];
423         }
424     }
426     - (int) registerHotKey:(UInt32)keyCode modifiers:(UInt32)modifiers vkey:(unsigned int)vkey modFlags:(unsigned int)modFlags
427     {
428         static EventHandlerRef handler;
429         static UInt32 hotKeyNumber;
430         OSStatus status;
431         NSNumber* vkeyNumber;
432         NSNumber* modFlagsNumber;
433         NSArray* winIDPair;
434         EventHotKeyID hotKeyID;
435         EventHotKeyRef hotKeyRef;
436         NSNumber* macIDNumber;
437         NSDictionary* hotKeyDict;
439         if (!handler)
440         {
441             EventTypeSpec eventType = { kEventClassKeyboard, kEventHotKeyPressed };
442             status = InstallApplicationEventHandler(HotKeyHandler, 1, &eventType, self, &handler);
443             if (status != noErr)
444             {
445                 ERR(@"InstallApplicationEventHandler() failed: %d\n", status);
446                 handler = NULL;
447                 return MACDRV_HOTKEY_FAILURE;
448             }
449         }
451         if (!hotKeysByMacID && !(hotKeysByMacID = [[NSMutableDictionary alloc] init]))
452             return MACDRV_HOTKEY_FAILURE;
453         if (!hotKeysByWinID && !(hotKeysByWinID = [[NSMutableDictionary alloc] init]))
454             return MACDRV_HOTKEY_FAILURE;
456         vkeyNumber = [NSNumber numberWithUnsignedInt:vkey];
457         modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags];
458         winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil];
459         if ([hotKeysByWinID objectForKey:winIDPair])
460             return MACDRV_HOTKEY_ALREADY_REGISTERED;
462         hotKeyID.signature  = WineHotKeySignature;
463         hotKeyID.id         = hotKeyNumber++;
465         status = RegisterEventHotKey(keyCode, modifiers, hotKeyID, GetApplicationEventTarget(),
466                                      kEventHotKeyExclusive, &hotKeyRef);
467         if (status == eventHotKeyExistsErr)
468             return MACDRV_HOTKEY_ALREADY_REGISTERED;
469         if (status != noErr)
470         {
471             ERR(@"RegisterEventHotKey() failed: %d\n", status);
472             return MACDRV_HOTKEY_FAILURE;
473         }
475         macIDNumber = [NSNumber numberWithUnsignedInt:hotKeyID.id];
476         hotKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
477                       macIDNumber, WineHotKeyMacIDKey,
478                       vkeyNumber, WineHotKeyVkeyKey,
479                       modFlagsNumber, WineHotKeyModFlagsKey,
480                       [NSNumber numberWithUnsignedInt:keyCode], WineHotKeyKeyCodeKey,
481                       [NSValue valueWithPointer:hotKeyRef], WineHotKeyCarbonRefKey,
482                       nil];
483         [hotKeysByMacID setObject:hotKeyDict forKey:macIDNumber];
484         [hotKeysByWinID setObject:hotKeyDict forKey:winIDPair];
486         return MACDRV_HOTKEY_SUCCESS;
487     }
490 /***********************************************************************
491  *              OnMainThread
493  * Run a block on the main thread synchronously.
494  */
495 void OnMainThread(dispatch_block_t block)
497     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
498     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
499     WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey];
500     dispatch_semaphore_t semaphore = NULL;
501     __block BOOL finished;
503     if (!queue)
504     {
505         semaphore = dispatch_semaphore_create(0);
506         dispatch_retain(semaphore);
507     }
509     finished = FALSE;
510     OnMainThreadAsync(^{
511         block();
512         finished = TRUE;
513         if (queue)
514             [queue signalEventAvailable];
515         else
516         {
517             dispatch_semaphore_signal(semaphore);
518             dispatch_release(semaphore);
519         }
520     });
522     if (queue)
523     {
524         while (!finished)
525         {
526             MacDrvEvent* macDrvEvent;
527             struct kevent kev;
529             while (!finished &&
530                    (macDrvEvent = [queue getEventMatchingMask:event_mask_for_type(QUERY_EVENT)]))
531             {
532                 queue->event_handler(macDrvEvent->event);
533             }
535             if (!finished)
536             {
537                 [pool release];
538                 pool = [[NSAutoreleasePool alloc] init];
540                 kevent(queue->kq, NULL, 0, &kev, 1, NULL);
541             }
542         }
543     }
544     else
545     {
546         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
547         dispatch_release(semaphore);
548     }
550     [pool release];
554 /***********************************************************************
555  *              macdrv_create_event_queue
557  * Register this thread with the application on the main thread, and set
558  * up an event queue on which it can deliver events to this thread.
559  */
560 macdrv_event_queue macdrv_create_event_queue(macdrv_event_handler handler)
562     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
563     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
565     WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey];
566     if (!queue)
567     {
568         queue = [[[WineEventQueue alloc] initWithEventHandler:handler] autorelease];
569         if (queue)
570         {
571             if ([[WineApplicationController sharedController] registerEventQueue:queue])
572                 [threadDict setObject:queue forKey:WineEventQueueThreadDictionaryKey];
573             else
574                 queue = nil;
575         }
576     }
578     [pool release];
579     return (macdrv_event_queue)queue;
582 /***********************************************************************
583  *              macdrv_destroy_event_queue
585  * Tell the application that this thread is exiting and destroy the
586  * associated event queue.
587  */
588 void macdrv_destroy_event_queue(macdrv_event_queue queue)
590     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
591     WineEventQueue* q = (WineEventQueue*)queue;
592     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
594     [[WineApplicationController sharedController] unregisterEventQueue:q];
595     [threadDict removeObjectForKey:WineEventQueueThreadDictionaryKey];
597     [pool release];
600 /***********************************************************************
601  *              macdrv_get_event_queue_fd
603  * Get the file descriptor whose readability signals that there are
604  * events on the event queue.
605  */
606 int macdrv_get_event_queue_fd(macdrv_event_queue queue)
608     WineEventQueue* q = (WineEventQueue*)queue;
609     return q->fds[0];
612 /***********************************************************************
613  *              macdrv_copy_event_from_queue
615  * Pull an event matching the event mask from the event queue and store
616  * it in the event record pointed to by the event parameter.  If a
617  * matching event was found, return non-zero; otherwise, return 0.
619  * The caller is responsible for calling macdrv_release_event on any
620  * event returned by this function.
621  */
622 int macdrv_copy_event_from_queue(macdrv_event_queue queue,
623         macdrv_event_mask mask, macdrv_event **event)
625     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
626     WineEventQueue* q = (WineEventQueue*)queue;
628     MacDrvEvent* macDrvEvent = [q getEventMatchingMask:mask];
629     if (macDrvEvent)
630         *event = macdrv_retain_event(macDrvEvent->event);
632     [pool release];
633     return (macDrvEvent != nil);
636 /***********************************************************************
637  *              macdrv_create_event
638  */
639 macdrv_event* macdrv_create_event(int type, WineWindow* window)
641     macdrv_event *event;
643     event = calloc(1, sizeof(*event));
644     event->refs = 1;
645     event->deliver = INT_MAX;
646     event->type = type;
647     event->window = (macdrv_window)[window retain];
648     return event;
651 /***********************************************************************
652  *              macdrv_retain_event
653  */
654 macdrv_event* macdrv_retain_event(macdrv_event *event)
656     OSAtomicIncrement32Barrier(&event->refs);
657     return event;
660 /***********************************************************************
661  *              macdrv_release_event
663  * Decrements the reference count of an event.  If the count falls to
664  * zero, cleans up any resources, such as allocated memory or retained
665  * objects, held by the event and deallocates it
666  */
667 void macdrv_release_event(macdrv_event *event)
669     if (OSAtomicDecrement32Barrier(&event->refs) <= 0)
670     {
671         NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
673         switch (event->type)
674         {
675             case IM_SET_TEXT:
676                 if (event->im_set_text.text)
677                     CFRelease(event->im_set_text.text);
678                 break;
679             case KEYBOARD_CHANGED:
680                 CFRelease(event->keyboard_changed.uchr);
681                 CFRelease(event->keyboard_changed.input_source);
682                 break;
683             case QUERY_EVENT:
684             case QUERY_EVENT_NO_PREEMPT_WAIT:
685                 macdrv_release_query(event->query_event.query);
686                 break;
687             case WINDOW_GOT_FOCUS:
688                 [(NSMutableSet*)event->window_got_focus.tried_windows release];
689                 break;
690         }
692         [(WineWindow*)event->window release];
693         free(event);
695         [pool release];
696     }
699 /***********************************************************************
700  *              macdrv_create_query
701  */
702 macdrv_query* macdrv_create_query(void)
704     macdrv_query *query;
706     query = calloc(1, sizeof(*query));
707     query->refs = 1;
708     return query;
711 /***********************************************************************
712  *              macdrv_retain_query
713  */
714 macdrv_query* macdrv_retain_query(macdrv_query *query)
716     OSAtomicIncrement32Barrier(&query->refs);
717     return query;
720 /***********************************************************************
721  *              macdrv_release_query
722  */
723 void macdrv_release_query(macdrv_query *query)
725     if (OSAtomicDecrement32Barrier(&query->refs) <= 0)
726     {
727         switch (query->type)
728         {
729             case QUERY_DRAG_OPERATION:
730                 if (query->drag_operation.pasteboard)
731                     CFRelease(query->drag_operation.pasteboard);
732                 break;
733             case QUERY_DRAG_DROP:
734                 if (query->drag_drop.pasteboard)
735                     CFRelease(query->drag_drop.pasteboard);
736                 break;
737             case QUERY_PASTEBOARD_DATA:
738                 if (query->pasteboard_data.type)
739                     CFRelease(query->pasteboard_data.type);
740                 break;
741         }
742         [(WineWindow*)query->window release];
743         free(query);
744     }
747 /***********************************************************************
748  *              macdrv_set_query_done
749  */
750 void macdrv_set_query_done(macdrv_query *query)
752     macdrv_retain_query(query);
754     OnMainThreadAsync(^{
755         NSEvent* event;
757         query->done = TRUE;
758         macdrv_release_query(query);
760         event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
761                                    location:NSZeroPoint
762                               modifierFlags:0
763                                   timestamp:[[NSProcessInfo processInfo] systemUptime]
764                                windowNumber:0
765                                     context:nil
766                                     subtype:WineApplicationEventWakeQuery
767                                       data1:0
768                                       data2:0];
769         [NSApp postEvent:event atStart:TRUE];
770     });
773 @end
776 /***********************************************************************
777  *              macdrv_register_hot_key
778  */
779 int macdrv_register_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags,
780                             unsigned int keycode, unsigned int modifiers)
782     WineEventQueue* queue = (WineEventQueue*)q;
783     __block int ret;
785     OnMainThread(^{
786         ret = [queue registerHotKey:keycode modifiers:modifiers vkey:vkey modFlags:mod_flags];
787     });
789     return ret;
793 /***********************************************************************
794  *              macdrv_unregister_hot_key
795  */
796 void macdrv_unregister_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags)
798     WineEventQueue* queue = (WineEventQueue*)q;
800     OnMainThreadAsync(^{
801         [queue unregisterHotKey:vkey modFlags:mod_flags];
802     });