comctl32: Fix a typo in comment.
[wine.git] / dlls / winemac.drv / cocoa_event.m
blob40066ffda5ebf4850fb2b86cf34231291446787f
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 & (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask)) == NSCommandKeyMask);
48     }
50     + (BOOL) wine_commandKeyDown
51     {
52         return wine_commandKeyDown([self modifierFlags]);
53     }
55     - (BOOL) wine_commandKeyDown
56     {
57         return wine_commandKeyDown([self modifierFlags]);
58     }
60 @end
63 @interface MacDrvEvent : NSObject
65 @public
66     macdrv_event* event;
69     - (id) initWithEvent:(macdrv_event*)event;
71 @end
73 @implementation MacDrvEvent
75     - (id) initWithEvent:(macdrv_event*)inEvent
76     {
77         self = [super init];
78         if (self)
79         {
80             event = macdrv_retain_event(inEvent);
81         }
82         return self;
83     }
85     - (void) dealloc
86     {
87         if (event) macdrv_release_event(event);
88         [super dealloc];
89     }
91 @end
94 @implementation WineEventQueue
96     - (id) init
97     {
98         [self doesNotRecognizeSelector:_cmd];
99         [self release];
100         return nil;
101     }
103     - (id) initWithEventHandler:(macdrv_event_handler)handler
104     {
105         NSParameterAssert(handler != nil);
107         self = [super init];
108         if (self != nil)
109         {
110             struct kevent kev;
111             int rc;
113             fds[0] = fds[1] = kq = -1;
115             event_handler = handler;
116             events = [[NSMutableArray alloc] init];
117             eventsLock = [[NSLock alloc] init];
119             if (!events || !eventsLock)
120             {
121                 [self release];
122                 return nil;
123             }
125             if (pipe(fds) ||
126                 fcntl(fds[0], F_SETFD, 1) == -1 ||
127                 fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
128                 fcntl(fds[1], F_SETFD, 1) == -1 ||
129                 fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1)
130             {
131                 [self release];
132                 return nil;
133             }
135             kq = kqueue();
136             if (kq < 0)
137             {
138                 [self release];
139                 return nil;
140             }
142             EV_SET(&kev, fds[0], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
143             do
144             {
145                 rc = kevent(kq, &kev, 1, NULL, 0, NULL);
146             } while (rc == -1 && errno == EINTR);
147             if (rc == -1)
148             {
149                 [self release];
150                 return nil;
151             }
152         }
153         return self;
154     }
156     - (void) dealloc
157     {
158         NSNumber* hotKeyMacID;
160         for (hotKeyMacID in hotKeysByMacID)
161         {
162             NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:hotKeyMacID];
163             EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue];
164             UnregisterEventHotKey(hotKeyRef);
165         }
166         [hotKeysByMacID release];
167         [hotKeysByWinID release];
168         [events release];
169         [eventsLock release];
171         if (kq != -1) close(kq);
172         if (fds[0] != -1) close(fds[0]);
173         if (fds[1] != -1) close(fds[1]);
175         [super dealloc];
176     }
178     - (void) signalEventAvailable
179     {
180         char junk = 1;
181         int rc;
183         do
184         {
185             rc = write(fds[1], &junk, 1);
186         } while (rc < 0 && errno == EINTR);
188         if (rc < 0 && errno != EAGAIN)
189             ERR(@"%@: got error writing to event queue signaling pipe: %s\n", self, strerror(errno));
190     }
192     - (void) postEventObject:(MacDrvEvent*)event
193     {
194         NSIndexSet* indexes;
195         MacDrvEvent* lastEvent;
197         [eventsLock lock];
199         indexes = [events indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
200             return ((MacDrvEvent*)obj)->event->deliver <= 0;
201         }];
202         [events removeObjectsAtIndexes:indexes];
204         if ((event->event->type == MOUSE_MOVED ||
205              event->event->type == MOUSE_MOVED_ABSOLUTE) &&
206             event->event->deliver == INT_MAX &&
207             (lastEvent = [events lastObject]) &&
208             (lastEvent->event->type == MOUSE_MOVED ||
209              lastEvent->event->type == MOUSE_MOVED_ABSOLUTE) &&
210             lastEvent->event->deliver == INT_MAX &&
211             lastEvent->event->window == event->event->window &&
212             lastEvent->event->mouse_moved.drag == event->event->mouse_moved.drag)
213         {
214             if (event->event->type == MOUSE_MOVED)
215             {
216                 lastEvent->event->mouse_moved.x += event->event->mouse_moved.x;
217                 lastEvent->event->mouse_moved.y += event->event->mouse_moved.y;
218             }
219             else
220             {
221                 lastEvent->event->type = MOUSE_MOVED_ABSOLUTE;
222                 lastEvent->event->mouse_moved.x = event->event->mouse_moved.x;
223                 lastEvent->event->mouse_moved.y = event->event->mouse_moved.y;
224             }
226             lastEvent->event->mouse_moved.time_ms = event->event->mouse_moved.time_ms;
227         }
228         else
229             [events addObject:event];
231         [eventsLock unlock];
233         [self signalEventAvailable];
234     }
236     - (void) postEvent:(macdrv_event*)inEvent
237     {
238         MacDrvEvent* event = [[MacDrvEvent alloc] initWithEvent:inEvent];
239         [self postEventObject:event];
240         [event release];
241     }
243     - (MacDrvEvent*) getEventMatchingMask:(macdrv_event_mask)mask
244     {
245         char buf[512];
246         int rc;
247         NSUInteger index;
248         MacDrvEvent* ret = nil;
250         /* Clear the pipe which signals there are pending events. */
251         do
252         {
253             rc = read(fds[0], buf, sizeof(buf));
254         } while (rc > 0 || (rc < 0 && errno == EINTR));
255         if (rc == 0 || (rc < 0 && errno != EAGAIN))
256         {
257             if (rc == 0)
258                 ERR(@"%@: event queue signaling pipe unexpectedly closed\n", self);
259             else
260                 ERR(@"%@: got error reading from event queue signaling pipe: %s\n", self, strerror(errno));
261             return nil;
262         }
264         [eventsLock lock];
266         index = 0;
267         while (index < [events count])
268         {
269             MacDrvEvent* event = [events objectAtIndex:index];
270             if (event_mask_for_type(event->event->type) & mask)
271             {
272                 [[event retain] autorelease];
273                 [events removeObjectAtIndex:index];
275                 if (event->event->deliver == INT_MAX ||
276                     OSAtomicDecrement32Barrier(&event->event->deliver) >= 0)
277                 {
278                     ret = event;
279                     break;
280                 }
281             }
282             else
283                 index++;
284         }
286         [eventsLock unlock];
287         return ret;
288     }
290     - (void) discardEventsPassingTest:(BOOL (^)(macdrv_event* event))block
291     {
292         NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
293         NSIndexSet* indexes;
295         [eventsLock lock];
297         indexes = [events indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
298             MacDrvEvent* event = obj;
299             return block(event->event);
300         }];
302         [events removeObjectsAtIndexes:indexes];
304         [eventsLock unlock];
306         [pool release];
307     }
309     - (void) discardEventsMatchingMask:(macdrv_event_mask)mask forWindow:(NSWindow*)window
310     {
311         [self discardEventsPassingTest:^BOOL (macdrv_event* event){
312             return ((event_mask_for_type(event->type) & mask) &&
313                     (!window || event->window == (macdrv_window)window));
314         }];
315     }
317     - (BOOL) query:(macdrv_query*)query timeout:(NSTimeInterval)timeout flags:(NSUInteger)flags
318     {
319         int type;
320         macdrv_event* event;
321         NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];
322         BOOL timedout;
324         type = (flags & WineQueryNoPreemptWait) ? QUERY_EVENT_NO_PREEMPT_WAIT : QUERY_EVENT;
325         event = macdrv_create_event(type, (WineWindow*)query->window);
326         event->query_event.query = macdrv_retain_query(query);
327         query->done = FALSE;
329         [self postEvent:event];
330         macdrv_release_event(event);
331         timedout = ![[WineApplicationController sharedController] waitUntilQueryDone:&query->done
332                                                                              timeout:timeoutDate
333                                                                        processEvents:(flags & WineQueryProcessEvents) != 0];
334         return !timedout && query->status;
335     }
337     - (BOOL) query:(macdrv_query*)query timeout:(NSTimeInterval)timeout
338     {
339         return [self query:query timeout:timeout flags:0];
340     }
342     - (void) resetMouseEventPositions:(CGPoint)pos
343     {
344         MacDrvEvent* event;
346         pos = cgpoint_win_from_mac(pos);
348         [eventsLock lock];
350         for (event in events)
351         {
352             if (event->event->type == MOUSE_BUTTON)
353             {
354                 event->event->mouse_button.x = pos.x;
355                 event->event->mouse_button.y = pos.y;
356             }
357             else if (event->event->type == MOUSE_SCROLL)
358             {
359                 event->event->mouse_scroll.x = pos.x;
360                 event->event->mouse_scroll.y = pos.y;
361             }
362         }
364         [eventsLock unlock];
365     }
367     - (BOOL) postHotKeyEvent:(UInt32)hotKeyNumber time:(double)time
368     {
369         NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:[NSNumber numberWithUnsignedInt:hotKeyNumber]];
370         if (hotKeyDict)
371         {
372             macdrv_event* event;
374             event = macdrv_create_event(HOTKEY_PRESS, nil);
375             event->hotkey_press.vkey        = [[hotKeyDict objectForKey:WineHotKeyVkeyKey] unsignedIntValue];
376             event->hotkey_press.mod_flags   = [[hotKeyDict objectForKey:WineHotKeyModFlagsKey] unsignedIntValue];
377             event->hotkey_press.keycode     = [[hotKeyDict objectForKey:WineHotKeyKeyCodeKey] unsignedIntValue];
378             event->hotkey_press.time_ms     = [[WineApplicationController sharedController] ticksForEventTime:time];
380             [self postEvent:event];
382             macdrv_release_event(event);
383         }
385         return hotKeyDict != nil;
386     }
388     static OSStatus HotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
389     {
390         WineEventQueue* self = userData;
391         OSStatus status;
392         EventHotKeyID hotKeyID;
394         status = GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL,
395                                    sizeof(hotKeyID), NULL, &hotKeyID);
396         if (status == noErr)
397         {
398             if (hotKeyID.signature != WineHotKeySignature ||
399                 ![self postHotKeyEvent:hotKeyID.id time:GetEventTime(theEvent)])
400                 status = eventNotHandledErr;
401         }
403         return status;
404     }
406     - (void) unregisterHotKey:(unsigned int)vkey modFlags:(unsigned int)modFlags
407     {
408         NSNumber* vkeyNumber = [NSNumber numberWithUnsignedInt:vkey];
409         NSNumber* modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags];
410         NSArray* winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil];
411         NSDictionary* hotKeyDict = [hotKeysByWinID objectForKey:winIDPair];
412         if (hotKeyDict)
413         {
414             EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue];
415             NSNumber* macID = [hotKeyDict objectForKey:WineHotKeyMacIDKey];
417             UnregisterEventHotKey(hotKeyRef);
418             [hotKeysByMacID removeObjectForKey:macID];
419             [hotKeysByWinID removeObjectForKey:winIDPair];
420         }
421     }
423     - (int) registerHotKey:(UInt32)keyCode modifiers:(UInt32)modifiers vkey:(unsigned int)vkey modFlags:(unsigned int)modFlags
424     {
425         static EventHandlerRef handler;
426         static UInt32 hotKeyNumber;
427         OSStatus status;
428         NSNumber* vkeyNumber;
429         NSNumber* modFlagsNumber;
430         NSArray* winIDPair;
431         EventHotKeyID hotKeyID;
432         EventHotKeyRef hotKeyRef;
433         NSNumber* macIDNumber;
434         NSDictionary* hotKeyDict;
436         if (!handler)
437         {
438             EventTypeSpec eventType = { kEventClassKeyboard, kEventHotKeyPressed };
439             status = InstallApplicationEventHandler(HotKeyHandler, 1, &eventType, self, &handler);
440             if (status != noErr)
441             {
442                 ERR(@"InstallApplicationEventHandler() failed: %d\n", status);
443                 handler = NULL;
444                 return MACDRV_HOTKEY_FAILURE;
445             }
446         }
448         if (!hotKeysByMacID && !(hotKeysByMacID = [[NSMutableDictionary alloc] init]))
449             return MACDRV_HOTKEY_FAILURE;
450         if (!hotKeysByWinID && !(hotKeysByWinID = [[NSMutableDictionary alloc] init]))
451             return MACDRV_HOTKEY_FAILURE;
453         vkeyNumber = [NSNumber numberWithUnsignedInt:vkey];
454         modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags];
455         winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil];
456         if ([hotKeysByWinID objectForKey:winIDPair])
457             return MACDRV_HOTKEY_ALREADY_REGISTERED;
459         hotKeyID.signature  = WineHotKeySignature;
460         hotKeyID.id         = hotKeyNumber++;
462         status = RegisterEventHotKey(keyCode, modifiers, hotKeyID, GetApplicationEventTarget(),
463                                      kEventHotKeyExclusive, &hotKeyRef);
464         if (status == eventHotKeyExistsErr)
465             return MACDRV_HOTKEY_ALREADY_REGISTERED;
466         if (status != noErr)
467         {
468             ERR(@"RegisterEventHotKey() failed: %d\n", status);
469             return MACDRV_HOTKEY_FAILURE;
470         }
472         macIDNumber = [NSNumber numberWithUnsignedInt:hotKeyID.id];
473         hotKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
474                       macIDNumber, WineHotKeyMacIDKey,
475                       vkeyNumber, WineHotKeyVkeyKey,
476                       modFlagsNumber, WineHotKeyModFlagsKey,
477                       [NSNumber numberWithUnsignedInt:keyCode], WineHotKeyKeyCodeKey,
478                       [NSValue valueWithPointer:hotKeyRef], WineHotKeyCarbonRefKey,
479                       nil];
480         [hotKeysByMacID setObject:hotKeyDict forKey:macIDNumber];
481         [hotKeysByWinID setObject:hotKeyDict forKey:winIDPair];
483         return MACDRV_HOTKEY_SUCCESS;
484     }
487 /***********************************************************************
488  *              OnMainThread
490  * Run a block on the main thread synchronously.
491  */
492 void OnMainThread(dispatch_block_t block)
494     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
495     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
496     WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey];
497     dispatch_semaphore_t semaphore = NULL;
498     __block BOOL finished;
500     if (!queue)
501     {
502         semaphore = dispatch_semaphore_create(0);
503         dispatch_retain(semaphore);
504     }
506     finished = FALSE;
507     OnMainThreadAsync(^{
508         block();
509         finished = TRUE;
510         if (queue)
511             [queue signalEventAvailable];
512         else
513         {
514             dispatch_semaphore_signal(semaphore);
515             dispatch_release(semaphore);
516         }
517     });
519     if (queue)
520     {
521         while (!finished)
522         {
523             MacDrvEvent* macDrvEvent;
524             struct kevent kev;
526             while (!finished &&
527                    (macDrvEvent = [queue getEventMatchingMask:event_mask_for_type(QUERY_EVENT)]))
528             {
529                 queue->event_handler(macDrvEvent->event);
530             }
532             if (!finished)
533             {
534                 [pool release];
535                 pool = [[NSAutoreleasePool alloc] init];
537                 kevent(queue->kq, NULL, 0, &kev, 1, NULL);
538             }
539         }
540     }
541     else
542     {
543         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
544         dispatch_release(semaphore);
545     }
547     [pool release];
551 /***********************************************************************
552  *              macdrv_create_event_queue
554  * Register this thread with the application on the main thread, and set
555  * up an event queue on which it can deliver events to this thread.
556  */
557 macdrv_event_queue macdrv_create_event_queue(macdrv_event_handler handler)
559     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
560     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
562     WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey];
563     if (!queue)
564     {
565         queue = [[[WineEventQueue alloc] initWithEventHandler:handler] autorelease];
566         if (queue)
567         {
568             if ([[WineApplicationController sharedController] registerEventQueue:queue])
569                 [threadDict setObject:queue forKey:WineEventQueueThreadDictionaryKey];
570             else
571                 queue = nil;
572         }
573     }
575     [pool release];
576     return (macdrv_event_queue)queue;
579 /***********************************************************************
580  *              macdrv_destroy_event_queue
582  * Tell the application that this thread is exiting and destroy the
583  * associated event queue.
584  */
585 void macdrv_destroy_event_queue(macdrv_event_queue queue)
587     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
588     WineEventQueue* q = (WineEventQueue*)queue;
589     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
591     [[WineApplicationController sharedController] unregisterEventQueue:q];
592     [threadDict removeObjectForKey:WineEventQueueThreadDictionaryKey];
594     [pool release];
597 /***********************************************************************
598  *              macdrv_get_event_queue_fd
600  * Get the file descriptor whose readability signals that there are
601  * events on the event queue.
602  */
603 int macdrv_get_event_queue_fd(macdrv_event_queue queue)
605     WineEventQueue* q = (WineEventQueue*)queue;
606     return q->fds[0];
609 /***********************************************************************
610  *              macdrv_copy_event_from_queue
612  * Pull an event matching the event mask from the event queue and store
613  * it in the event record pointed to by the event parameter.  If a
614  * matching event was found, return non-zero; otherwise, return 0.
616  * The caller is responsible for calling macdrv_release_event on any
617  * event returned by this function.
618  */
619 int macdrv_copy_event_from_queue(macdrv_event_queue queue,
620         macdrv_event_mask mask, macdrv_event **event)
622     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
623     WineEventQueue* q = (WineEventQueue*)queue;
625     MacDrvEvent* macDrvEvent = [q getEventMatchingMask:mask];
626     if (macDrvEvent)
627         *event = macdrv_retain_event(macDrvEvent->event);
629     [pool release];
630     return (macDrvEvent != nil);
633 /***********************************************************************
634  *              macdrv_create_event
635  */
636 macdrv_event* macdrv_create_event(int type, WineWindow* window)
638     macdrv_event *event;
640     event = calloc(1, sizeof(*event));
641     event->refs = 1;
642     event->deliver = INT_MAX;
643     event->type = type;
644     event->window = (macdrv_window)[window retain];
645     return event;
648 /***********************************************************************
649  *              macdrv_retain_event
650  */
651 macdrv_event* macdrv_retain_event(macdrv_event *event)
653     OSAtomicIncrement32Barrier(&event->refs);
654     return event;
657 /***********************************************************************
658  *              macdrv_release_event
660  * Decrements the reference count of an event.  If the count falls to
661  * zero, cleans up any resources, such as allocated memory or retained
662  * objects, held by the event and deallocates it
663  */
664 void macdrv_release_event(macdrv_event *event)
666     if (OSAtomicDecrement32Barrier(&event->refs) <= 0)
667     {
668         NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
670         switch (event->type)
671         {
672             case IM_SET_TEXT:
673                 if (event->im_set_text.text)
674                     CFRelease(event->im_set_text.text);
675                 break;
676             case KEYBOARD_CHANGED:
677                 CFRelease(event->keyboard_changed.uchr);
678                 CFRelease(event->keyboard_changed.input_source);
679                 break;
680             case QUERY_EVENT:
681             case QUERY_EVENT_NO_PREEMPT_WAIT:
682                 macdrv_release_query(event->query_event.query);
683                 break;
684             case WINDOW_GOT_FOCUS:
685                 [(NSMutableSet*)event->window_got_focus.tried_windows release];
686                 break;
687         }
689         [(WineWindow*)event->window release];
690         free(event);
692         [pool release];
693     }
696 /***********************************************************************
697  *              macdrv_create_query
698  */
699 macdrv_query* macdrv_create_query(void)
701     macdrv_query *query;
703     query = calloc(1, sizeof(*query));
704     query->refs = 1;
705     return query;
708 /***********************************************************************
709  *              macdrv_retain_query
710  */
711 macdrv_query* macdrv_retain_query(macdrv_query *query)
713     OSAtomicIncrement32Barrier(&query->refs);
714     return query;
717 /***********************************************************************
718  *              macdrv_release_query
719  */
720 void macdrv_release_query(macdrv_query *query)
722     if (OSAtomicDecrement32Barrier(&query->refs) <= 0)
723     {
724         switch (query->type)
725         {
726             case QUERY_DRAG_OPERATION:
727                 if (query->drag_operation.pasteboard)
728                     CFRelease(query->drag_operation.pasteboard);
729                 break;
730             case QUERY_DRAG_DROP:
731                 if (query->drag_drop.pasteboard)
732                     CFRelease(query->drag_drop.pasteboard);
733                 break;
734             case QUERY_PASTEBOARD_DATA:
735                 if (query->pasteboard_data.type)
736                     CFRelease(query->pasteboard_data.type);
737                 break;
738         }
739         [(WineWindow*)query->window release];
740         free(query);
741     }
744 /***********************************************************************
745  *              macdrv_set_query_done
746  */
747 void macdrv_set_query_done(macdrv_query *query)
749     macdrv_retain_query(query);
751     OnMainThreadAsync(^{
752         NSEvent* event;
754         query->done = TRUE;
755         macdrv_release_query(query);
757         event = [NSEvent otherEventWithType:NSApplicationDefined
758                                    location:NSZeroPoint
759                               modifierFlags:0
760                                   timestamp:[[NSProcessInfo processInfo] systemUptime]
761                                windowNumber:0
762                                     context:nil
763                                     subtype:WineApplicationEventWakeQuery
764                                       data1:0
765                                       data2:0];
766         [NSApp postEvent:event atStart:TRUE];
767     });
770 @end
773 /***********************************************************************
774  *              macdrv_register_hot_key
775  */
776 int macdrv_register_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags,
777                             unsigned int keycode, unsigned int modifiers)
779     WineEventQueue* queue = (WineEventQueue*)q;
780     __block int ret;
782     OnMainThread(^{
783         ret = [queue registerHotKey:keycode modifiers:modifiers vkey:vkey modFlags:mod_flags];
784     });
786     return ret;
790 /***********************************************************************
791  *              macdrv_unregister_hot_key
792  */
793 void macdrv_unregister_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags)
795     WineEventQueue* queue = (WineEventQueue*)q;
797     OnMainThreadAsync(^{
798         [queue unregisterHotKey:vkey modFlags:mod_flags];
799     });