wined3d: Use wined3d_texture_prepare_location() in wined3d_texture_update_desc().
[wine.git] / dlls / winemac.drv / cocoa_event.m
blob08a706fd8ba0db761482652e84d76ac146669083
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 @interface MacDrvEvent : NSObject
45 @public
46     macdrv_event* event;
49     - (id) initWithEvent:(macdrv_event*)event;
51 @end
53 @implementation MacDrvEvent
55     - (id) initWithEvent:(macdrv_event*)inEvent
56     {
57         self = [super init];
58         if (self)
59         {
60             event = macdrv_retain_event(inEvent);
61         }
62         return self;
63     }
65     - (void) dealloc
66     {
67         if (event) macdrv_release_event(event);
68         [super dealloc];
69     }
71 @end
74 @implementation WineEventQueue
76     - (id) init
77     {
78         [self doesNotRecognizeSelector:_cmd];
79         [self release];
80         return nil;
81     }
83     - (id) initWithEventHandler:(macdrv_event_handler)handler
84     {
85         NSParameterAssert(handler != nil);
87         self = [super init];
88         if (self != nil)
89         {
90             struct kevent kev;
91             int rc;
93             fds[0] = fds[1] = kq = -1;
95             event_handler = handler;
96             events = [[NSMutableArray alloc] init];
97             eventsLock = [[NSLock alloc] init];
99             if (!events || !eventsLock)
100             {
101                 [self release];
102                 return nil;
103             }
105             if (pipe(fds) ||
106                 fcntl(fds[0], F_SETFD, 1) == -1 ||
107                 fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
108                 fcntl(fds[1], F_SETFD, 1) == -1 ||
109                 fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1)
110             {
111                 [self release];
112                 return nil;
113             }
115             kq = kqueue();
116             if (kq < 0)
117             {
118                 [self release];
119                 return nil;
120             }
122             EV_SET(&kev, fds[0], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
123             do
124             {
125                 rc = kevent(kq, &kev, 1, NULL, 0, NULL);
126             } while (rc == -1 && errno == EINTR);
127             if (rc == -1)
128             {
129                 [self release];
130                 return nil;
131             }
132         }
133         return self;
134     }
136     - (void) dealloc
137     {
138         NSNumber* hotKeyMacID;
140         for (hotKeyMacID in hotKeysByMacID)
141         {
142             NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:hotKeyMacID];
143             EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue];
144             UnregisterEventHotKey(hotKeyRef);
145         }
146         [hotKeysByMacID release];
147         [hotKeysByWinID release];
148         [events release];
149         [eventsLock release];
151         if (kq != -1) close(kq);
152         if (fds[0] != -1) close(fds[0]);
153         if (fds[1] != -1) close(fds[1]);
155         [super dealloc];
156     }
158     - (void) signalEventAvailable
159     {
160         char junk = 1;
161         int rc;
163         do
164         {
165             rc = write(fds[1], &junk, 1);
166         } while (rc < 0 && errno == EINTR);
168         if (rc < 0 && errno != EAGAIN)
169             ERR(@"%@: got error writing to event queue signaling pipe: %s\n", self, strerror(errno));
170     }
172     - (void) postEventObject:(MacDrvEvent*)event
173     {
174         NSIndexSet* indexes;
175         MacDrvEvent* lastEvent;
177         [eventsLock lock];
179         indexes = [events indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
180             return ((MacDrvEvent*)obj)->event->deliver <= 0;
181         }];
182         [events removeObjectsAtIndexes:indexes];
184         if ((event->event->type == MOUSE_MOVED ||
185              event->event->type == MOUSE_MOVED_ABSOLUTE) &&
186             event->event->deliver == INT_MAX &&
187             (lastEvent = [events lastObject]) &&
188             (lastEvent->event->type == MOUSE_MOVED ||
189              lastEvent->event->type == MOUSE_MOVED_ABSOLUTE) &&
190             lastEvent->event->deliver == INT_MAX &&
191             lastEvent->event->window == event->event->window &&
192             lastEvent->event->mouse_moved.drag == event->event->mouse_moved.drag)
193         {
194             if (event->event->type == MOUSE_MOVED)
195             {
196                 lastEvent->event->mouse_moved.x += event->event->mouse_moved.x;
197                 lastEvent->event->mouse_moved.y += event->event->mouse_moved.y;
198             }
199             else
200             {
201                 lastEvent->event->type = MOUSE_MOVED_ABSOLUTE;
202                 lastEvent->event->mouse_moved.x = event->event->mouse_moved.x;
203                 lastEvent->event->mouse_moved.y = event->event->mouse_moved.y;
204             }
206             lastEvent->event->mouse_moved.time_ms = event->event->mouse_moved.time_ms;
207         }
208         else
209             [events addObject:event];
211         [eventsLock unlock];
213         [self signalEventAvailable];
214     }
216     - (void) postEvent:(macdrv_event*)inEvent
217     {
218         MacDrvEvent* event = [[MacDrvEvent alloc] initWithEvent:inEvent];
219         [self postEventObject:event];
220         [event release];
221     }
223     - (MacDrvEvent*) getEventMatchingMask:(macdrv_event_mask)mask
224     {
225         char buf[512];
226         int rc;
227         NSUInteger index;
228         MacDrvEvent* ret = nil;
230         /* Clear the pipe which signals there are pending events. */
231         do
232         {
233             rc = read(fds[0], buf, sizeof(buf));
234         } while (rc > 0 || (rc < 0 && errno == EINTR));
235         if (rc == 0 || (rc < 0 && errno != EAGAIN))
236         {
237             if (rc == 0)
238                 ERR(@"%@: event queue signaling pipe unexpectedly closed\n", self);
239             else
240                 ERR(@"%@: got error reading from event queue signaling pipe: %s\n", self, strerror(errno));
241             return nil;
242         }
244         [eventsLock lock];
246         index = 0;
247         while (index < [events count])
248         {
249             MacDrvEvent* event = [events objectAtIndex:index];
250             if (event_mask_for_type(event->event->type) & mask)
251             {
252                 [[event retain] autorelease];
253                 [events removeObjectAtIndex:index];
255                 if (event->event->deliver == INT_MAX ||
256                     OSAtomicDecrement32Barrier(&event->event->deliver) >= 0)
257                 {
258                     ret = event;
259                     break;
260                 }
261             }
262             else
263                 index++;
264         }
266         [eventsLock unlock];
267         return ret;
268     }
270     - (void) discardEventsPassingTest:(BOOL (^)(macdrv_event* event))block
271     {
272         NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
273         NSIndexSet* indexes;
275         [eventsLock lock];
277         indexes = [events indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
278             MacDrvEvent* event = obj;
279             return block(event->event);
280         }];
282         [events removeObjectsAtIndexes:indexes];
284         [eventsLock unlock];
286         [pool release];
287     }
289     - (void) discardEventsMatchingMask:(macdrv_event_mask)mask forWindow:(NSWindow*)window
290     {
291         [self discardEventsPassingTest:^BOOL (macdrv_event* event){
292             return ((event_mask_for_type(event->type) & mask) &&
293                     (!window || event->window == (macdrv_window)window));
294         }];
295     }
297     - (BOOL) query:(macdrv_query*)query timeout:(NSTimeInterval)timeout flags:(NSUInteger)flags
298     {
299         int type;
300         macdrv_event* event;
301         NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];
302         BOOL timedout;
304         type = (flags & WineQueryNoPreemptWait) ? QUERY_EVENT_NO_PREEMPT_WAIT : QUERY_EVENT;
305         event = macdrv_create_event(type, (WineWindow*)query->window);
306         event->query_event.query = macdrv_retain_query(query);
307         query->done = FALSE;
309         [self postEvent:event];
310         macdrv_release_event(event);
311         timedout = ![[WineApplicationController sharedController] waitUntilQueryDone:&query->done
312                                                                              timeout:timeoutDate
313                                                                        processEvents:(flags & WineQueryProcessEvents) != 0];
314         return !timedout && query->status;
315     }
317     - (BOOL) query:(macdrv_query*)query timeout:(NSTimeInterval)timeout
318     {
319         return [self query:query timeout:timeout flags:0];
320     }
322     - (void) resetMouseEventPositions:(CGPoint)pos
323     {
324         MacDrvEvent* event;
326         pos = cgpoint_win_from_mac(pos);
328         [eventsLock lock];
330         for (event in events)
331         {
332             if (event->event->type == MOUSE_BUTTON)
333             {
334                 event->event->mouse_button.x = pos.x;
335                 event->event->mouse_button.y = pos.y;
336             }
337             else if (event->event->type == MOUSE_SCROLL)
338             {
339                 event->event->mouse_scroll.x = pos.x;
340                 event->event->mouse_scroll.y = pos.y;
341             }
342         }
344         [eventsLock unlock];
345     }
347     - (BOOL) postHotKeyEvent:(UInt32)hotKeyNumber time:(double)time
348     {
349         NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:[NSNumber numberWithUnsignedInt:hotKeyNumber]];
350         if (hotKeyDict)
351         {
352             macdrv_event* event;
354             event = macdrv_create_event(HOTKEY_PRESS, nil);
355             event->hotkey_press.vkey        = [[hotKeyDict objectForKey:WineHotKeyVkeyKey] unsignedIntValue];
356             event->hotkey_press.mod_flags   = [[hotKeyDict objectForKey:WineHotKeyModFlagsKey] unsignedIntValue];
357             event->hotkey_press.keycode     = [[hotKeyDict objectForKey:WineHotKeyKeyCodeKey] unsignedIntValue];
358             event->hotkey_press.time_ms     = [[WineApplicationController sharedController] ticksForEventTime:time];
360             [self postEvent:event];
362             macdrv_release_event(event);
363         }
365         return hotKeyDict != nil;
366     }
368     static OSStatus HotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
369     {
370         WineEventQueue* self = userData;
371         OSStatus status;
372         EventHotKeyID hotKeyID;
374         status = GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL,
375                                    sizeof(hotKeyID), NULL, &hotKeyID);
376         if (status == noErr)
377         {
378             if (hotKeyID.signature != WineHotKeySignature ||
379                 ![self postHotKeyEvent:hotKeyID.id time:GetEventTime(theEvent)])
380                 status = eventNotHandledErr;
381         }
383         return status;
384     }
386     - (void) unregisterHotKey:(unsigned int)vkey modFlags:(unsigned int)modFlags
387     {
388         NSNumber* vkeyNumber = [NSNumber numberWithUnsignedInt:vkey];
389         NSNumber* modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags];
390         NSArray* winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil];
391         NSDictionary* hotKeyDict = [hotKeysByWinID objectForKey:winIDPair];
392         if (hotKeyDict)
393         {
394             EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue];
395             NSNumber* macID = [hotKeyDict objectForKey:WineHotKeyMacIDKey];
397             UnregisterEventHotKey(hotKeyRef);
398             [hotKeysByMacID removeObjectForKey:macID];
399             [hotKeysByWinID removeObjectForKey:winIDPair];
400         }
401     }
403     - (int) registerHotKey:(UInt32)keyCode modifiers:(UInt32)modifiers vkey:(unsigned int)vkey modFlags:(unsigned int)modFlags
404     {
405         static EventHandlerRef handler;
406         static UInt32 hotKeyNumber;
407         OSStatus status;
408         NSNumber* vkeyNumber;
409         NSNumber* modFlagsNumber;
410         NSArray* winIDPair;
411         EventHotKeyID hotKeyID;
412         EventHotKeyRef hotKeyRef;
413         NSNumber* macIDNumber;
414         NSDictionary* hotKeyDict;
416         if (!handler)
417         {
418             EventTypeSpec eventType = { kEventClassKeyboard, kEventHotKeyPressed };
419             status = InstallApplicationEventHandler(HotKeyHandler, 1, &eventType, self, &handler);
420             if (status != noErr)
421             {
422                 ERR(@"InstallApplicationEventHandler() failed: %d\n", status);
423                 handler = NULL;
424                 return MACDRV_HOTKEY_FAILURE;
425             }
426         }
428         if (!hotKeysByMacID && !(hotKeysByMacID = [[NSMutableDictionary alloc] init]))
429             return MACDRV_HOTKEY_FAILURE;
430         if (!hotKeysByWinID && !(hotKeysByWinID = [[NSMutableDictionary alloc] init]))
431             return MACDRV_HOTKEY_FAILURE;
433         vkeyNumber = [NSNumber numberWithUnsignedInt:vkey];
434         modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags];
435         winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil];
436         if ([hotKeysByWinID objectForKey:winIDPair])
437             return MACDRV_HOTKEY_ALREADY_REGISTERED;
439         hotKeyID.signature  = WineHotKeySignature;
440         hotKeyID.id         = hotKeyNumber++;
442         status = RegisterEventHotKey(keyCode, modifiers, hotKeyID, GetApplicationEventTarget(),
443                                      kEventHotKeyExclusive, &hotKeyRef);
444         if (status == eventHotKeyExistsErr)
445             return MACDRV_HOTKEY_ALREADY_REGISTERED;
446         if (status != noErr)
447         {
448             ERR(@"RegisterEventHotKey() failed: %d\n", status);
449             return MACDRV_HOTKEY_FAILURE;
450         }
452         macIDNumber = [NSNumber numberWithUnsignedInt:hotKeyID.id];
453         hotKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
454                       macIDNumber, WineHotKeyMacIDKey,
455                       vkeyNumber, WineHotKeyVkeyKey,
456                       modFlagsNumber, WineHotKeyModFlagsKey,
457                       [NSNumber numberWithUnsignedInt:keyCode], WineHotKeyKeyCodeKey,
458                       [NSValue valueWithPointer:hotKeyRef], WineHotKeyCarbonRefKey,
459                       nil];
460         [hotKeysByMacID setObject:hotKeyDict forKey:macIDNumber];
461         [hotKeysByWinID setObject:hotKeyDict forKey:winIDPair];
463         return MACDRV_HOTKEY_SUCCESS;
464     }
467 /***********************************************************************
468  *              OnMainThread
470  * Run a block on the main thread synchronously.
471  */
472 void OnMainThread(dispatch_block_t block)
474     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
475     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
476     WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey];
477     dispatch_semaphore_t semaphore = NULL;
478     __block BOOL finished;
480     if (!queue)
481     {
482         semaphore = dispatch_semaphore_create(0);
483         dispatch_retain(semaphore);
484     }
486     finished = FALSE;
487     OnMainThreadAsync(^{
488         block();
489         finished = TRUE;
490         if (queue)
491             [queue signalEventAvailable];
492         else
493         {
494             dispatch_semaphore_signal(semaphore);
495             dispatch_release(semaphore);
496         }
497     });
499     if (queue)
500     {
501         while (!finished)
502         {
503             MacDrvEvent* macDrvEvent;
504             struct kevent kev;
506             while (!finished &&
507                    (macDrvEvent = [queue getEventMatchingMask:event_mask_for_type(QUERY_EVENT)]))
508             {
509                 queue->event_handler(macDrvEvent->event);
510             }
512             if (!finished)
513             {
514                 [pool release];
515                 pool = [[NSAutoreleasePool alloc] init];
517                 kevent(queue->kq, NULL, 0, &kev, 1, NULL);
518             }
519         }
520     }
521     else
522     {
523         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
524         dispatch_release(semaphore);
525     }
527     [pool release];
531 /***********************************************************************
532  *              macdrv_create_event_queue
534  * Register this thread with the application on the main thread, and set
535  * up an event queue on which it can deliver events to this thread.
536  */
537 macdrv_event_queue macdrv_create_event_queue(macdrv_event_handler handler)
539     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
540     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
542     WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey];
543     if (!queue)
544     {
545         queue = [[[WineEventQueue alloc] initWithEventHandler:handler] autorelease];
546         if (queue)
547         {
548             if ([[WineApplicationController sharedController] registerEventQueue:queue])
549                 [threadDict setObject:queue forKey:WineEventQueueThreadDictionaryKey];
550             else
551                 queue = nil;
552         }
553     }
555     [pool release];
556     return (macdrv_event_queue)queue;
559 /***********************************************************************
560  *              macdrv_destroy_event_queue
562  * Tell the application that this thread is exiting and destroy the
563  * associated event queue.
564  */
565 void macdrv_destroy_event_queue(macdrv_event_queue queue)
567     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
568     WineEventQueue* q = (WineEventQueue*)queue;
569     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
571     [[WineApplicationController sharedController] unregisterEventQueue:q];
572     [threadDict removeObjectForKey:WineEventQueueThreadDictionaryKey];
574     [pool release];
577 /***********************************************************************
578  *              macdrv_get_event_queue_fd
580  * Get the file descriptor whose readability signals that there are
581  * events on the event queue.
582  */
583 int macdrv_get_event_queue_fd(macdrv_event_queue queue)
585     WineEventQueue* q = (WineEventQueue*)queue;
586     return q->fds[0];
589 /***********************************************************************
590  *              macdrv_copy_event_from_queue
592  * Pull an event matching the event mask from the event queue and store
593  * it in the event record pointed to by the event parameter.  If a
594  * matching event was found, return non-zero; otherwise, return 0.
596  * The caller is responsible for calling macdrv_release_event on any
597  * event returned by this function.
598  */
599 int macdrv_copy_event_from_queue(macdrv_event_queue queue,
600         macdrv_event_mask mask, macdrv_event **event)
602     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
603     WineEventQueue* q = (WineEventQueue*)queue;
605     MacDrvEvent* macDrvEvent = [q getEventMatchingMask:mask];
606     if (macDrvEvent)
607         *event = macdrv_retain_event(macDrvEvent->event);
609     [pool release];
610     return (macDrvEvent != nil);
613 /***********************************************************************
614  *              macdrv_create_event
615  */
616 macdrv_event* macdrv_create_event(int type, WineWindow* window)
618     macdrv_event *event;
620     event = calloc(1, sizeof(*event));
621     event->refs = 1;
622     event->deliver = INT_MAX;
623     event->type = type;
624     event->window = (macdrv_window)[window retain];
625     return event;
628 /***********************************************************************
629  *              macdrv_retain_event
630  */
631 macdrv_event* macdrv_retain_event(macdrv_event *event)
633     OSAtomicIncrement32Barrier(&event->refs);
634     return event;
637 /***********************************************************************
638  *              macdrv_release_event
640  * Decrements the reference count of an event.  If the count falls to
641  * zero, cleans up any resources, such as allocated memory or retained
642  * objects, held by the event and deallocates it
643  */
644 void macdrv_release_event(macdrv_event *event)
646     if (OSAtomicDecrement32Barrier(&event->refs) <= 0)
647     {
648         NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
650         switch (event->type)
651         {
652             case IM_SET_TEXT:
653                 if (event->im_set_text.text)
654                     CFRelease(event->im_set_text.text);
655                 break;
656             case KEYBOARD_CHANGED:
657                 CFRelease(event->keyboard_changed.uchr);
658                 CFRelease(event->keyboard_changed.input_source);
659                 break;
660             case QUERY_EVENT:
661             case QUERY_EVENT_NO_PREEMPT_WAIT:
662                 macdrv_release_query(event->query_event.query);
663                 break;
664             case WINDOW_GOT_FOCUS:
665                 [(NSMutableSet*)event->window_got_focus.tried_windows release];
666                 break;
667         }
669         [(WineWindow*)event->window release];
670         free(event);
672         [pool release];
673     }
676 /***********************************************************************
677  *              macdrv_create_query
678  */
679 macdrv_query* macdrv_create_query(void)
681     macdrv_query *query;
683     query = calloc(1, sizeof(*query));
684     query->refs = 1;
685     return query;
688 /***********************************************************************
689  *              macdrv_retain_query
690  */
691 macdrv_query* macdrv_retain_query(macdrv_query *query)
693     OSAtomicIncrement32Barrier(&query->refs);
694     return query;
697 /***********************************************************************
698  *              macdrv_release_query
699  */
700 void macdrv_release_query(macdrv_query *query)
702     if (OSAtomicDecrement32Barrier(&query->refs) <= 0)
703     {
704         switch (query->type)
705         {
706             case QUERY_DRAG_OPERATION:
707                 if (query->drag_operation.pasteboard)
708                     CFRelease(query->drag_operation.pasteboard);
709                 break;
710             case QUERY_DRAG_DROP:
711                 if (query->drag_drop.pasteboard)
712                     CFRelease(query->drag_drop.pasteboard);
713                 break;
714             case QUERY_PASTEBOARD_DATA:
715                 if (query->pasteboard_data.type)
716                     CFRelease(query->pasteboard_data.type);
717                 break;
718         }
719         [(WineWindow*)query->window release];
720         free(query);
721     }
724 /***********************************************************************
725  *              macdrv_set_query_done
726  */
727 void macdrv_set_query_done(macdrv_query *query)
729     macdrv_retain_query(query);
731     OnMainThreadAsync(^{
732         NSEvent* event;
734         query->done = TRUE;
735         macdrv_release_query(query);
737         event = [NSEvent otherEventWithType:NSApplicationDefined
738                                    location:NSZeroPoint
739                               modifierFlags:0
740                                   timestamp:[[NSProcessInfo processInfo] systemUptime]
741                                windowNumber:0
742                                     context:nil
743                                     subtype:WineApplicationEventWakeQuery
744                                       data1:0
745                                       data2:0];
746         [NSApp postEvent:event atStart:TRUE];
747     });
750 @end
753 /***********************************************************************
754  *              macdrv_register_hot_key
755  */
756 int macdrv_register_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags,
757                             unsigned int keycode, unsigned int modifiers)
759     WineEventQueue* queue = (WineEventQueue*)q;
760     __block int ret;
762     OnMainThread(^{
763         ret = [queue registerHotKey:keycode modifiers:modifiers vkey:vkey modFlags:mod_flags];
764     });
766     return ret;
770 /***********************************************************************
771  *              macdrv_unregister_hot_key
772  */
773 void macdrv_unregister_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags)
775     WineEventQueue* queue = (WineEventQueue*)q;
777     OnMainThreadAsync(^{
778         [queue unregisterHotKey:vkey modFlags:mod_flags];
779     });