makefiles: Generate dependencies for static libraries.
[wine.git] / dlls / winemac.drv / cocoa_event.m
blob9ce43fb0ba757cd1e1322837c467def7e35bfcab
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         [eventsLock lock];
328         for (event in events)
329         {
330             if (event->event->type == MOUSE_BUTTON)
331             {
332                 event->event->mouse_button.x = pos.x;
333                 event->event->mouse_button.y = pos.y;
334             }
335             else if (event->event->type == MOUSE_SCROLL)
336             {
337                 event->event->mouse_scroll.x = pos.x;
338                 event->event->mouse_scroll.y = pos.y;
339             }
340         }
342         [eventsLock unlock];
343     }
345     - (BOOL) postHotKeyEvent:(UInt32)hotKeyNumber time:(double)time
346     {
347         NSDictionary* hotKeyDict = [hotKeysByMacID objectForKey:[NSNumber numberWithUnsignedInt:hotKeyNumber]];
348         if (hotKeyDict)
349         {
350             macdrv_event* event;
352             event = macdrv_create_event(HOTKEY_PRESS, nil);
353             event->hotkey_press.vkey        = [[hotKeyDict objectForKey:WineHotKeyVkeyKey] unsignedIntValue];
354             event->hotkey_press.mod_flags   = [[hotKeyDict objectForKey:WineHotKeyModFlagsKey] unsignedIntValue];
355             event->hotkey_press.keycode     = [[hotKeyDict objectForKey:WineHotKeyKeyCodeKey] unsignedIntValue];
356             event->hotkey_press.time_ms     = [[WineApplicationController sharedController] ticksForEventTime:time];
358             [self postEvent:event];
360             macdrv_release_event(event);
361         }
363         return hotKeyDict != nil;
364     }
366     static OSStatus HotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
367     {
368         WineEventQueue* self = userData;
369         OSStatus status;
370         EventHotKeyID hotKeyID;
372         status = GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL,
373                                    sizeof(hotKeyID), NULL, &hotKeyID);
374         if (status == noErr)
375         {
376             if (hotKeyID.signature != WineHotKeySignature ||
377                 ![self postHotKeyEvent:hotKeyID.id time:GetEventTime(theEvent)])
378                 status = eventNotHandledErr;
379         }
381         return status;
382     }
384     - (void) unregisterHotKey:(unsigned int)vkey modFlags:(unsigned int)modFlags
385     {
386         NSNumber* vkeyNumber = [NSNumber numberWithUnsignedInt:vkey];
387         NSNumber* modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags];
388         NSArray* winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil];
389         NSDictionary* hotKeyDict = [hotKeysByWinID objectForKey:winIDPair];
390         if (hotKeyDict)
391         {
392             EventHotKeyRef hotKeyRef = [[hotKeyDict objectForKey:WineHotKeyCarbonRefKey] pointerValue];
393             NSNumber* macID = [hotKeyDict objectForKey:WineHotKeyMacIDKey];
395             UnregisterEventHotKey(hotKeyRef);
396             [hotKeysByMacID removeObjectForKey:macID];
397             [hotKeysByWinID removeObjectForKey:winIDPair];
398         }
399     }
401     - (int) registerHotKey:(UInt32)keyCode modifiers:(UInt32)modifiers vkey:(unsigned int)vkey modFlags:(unsigned int)modFlags
402     {
403         static EventHandlerRef handler;
404         static UInt32 hotKeyNumber;
405         OSStatus status;
406         NSNumber* vkeyNumber;
407         NSNumber* modFlagsNumber;
408         NSArray* winIDPair;
409         EventHotKeyID hotKeyID;
410         EventHotKeyRef hotKeyRef;
411         NSNumber* macIDNumber;
412         NSDictionary* hotKeyDict;
414         if (!handler)
415         {
416             EventTypeSpec eventType = { kEventClassKeyboard, kEventHotKeyPressed };
417             status = InstallApplicationEventHandler(HotKeyHandler, 1, &eventType, self, &handler);
418             if (status != noErr)
419             {
420                 ERR(@"InstallApplicationEventHandler() failed: %d\n", status);
421                 handler = NULL;
422                 return MACDRV_HOTKEY_FAILURE;
423             }
424         }
426         if (!hotKeysByMacID && !(hotKeysByMacID = [[NSMutableDictionary alloc] init]))
427             return MACDRV_HOTKEY_FAILURE;
428         if (!hotKeysByWinID && !(hotKeysByWinID = [[NSMutableDictionary alloc] init]))
429             return MACDRV_HOTKEY_FAILURE;
431         vkeyNumber = [NSNumber numberWithUnsignedInt:vkey];
432         modFlagsNumber = [NSNumber numberWithUnsignedInt:modFlags];
433         winIDPair = [NSArray arrayWithObjects:vkeyNumber, modFlagsNumber, nil];
434         if ([hotKeysByWinID objectForKey:winIDPair])
435             return MACDRV_HOTKEY_ALREADY_REGISTERED;
437         hotKeyID.signature  = WineHotKeySignature;
438         hotKeyID.id         = hotKeyNumber++;
440         status = RegisterEventHotKey(keyCode, modifiers, hotKeyID, GetApplicationEventTarget(),
441                                      kEventHotKeyExclusive, &hotKeyRef);
442         if (status == eventHotKeyExistsErr)
443             return MACDRV_HOTKEY_ALREADY_REGISTERED;
444         if (status != noErr)
445         {
446             ERR(@"RegisterEventHotKey() failed: %d\n", status);
447             return MACDRV_HOTKEY_FAILURE;
448         }
450         macIDNumber = [NSNumber numberWithUnsignedInt:hotKeyID.id];
451         hotKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
452                       macIDNumber, WineHotKeyMacIDKey,
453                       vkeyNumber, WineHotKeyVkeyKey,
454                       modFlagsNumber, WineHotKeyModFlagsKey,
455                       [NSNumber numberWithUnsignedInt:keyCode], WineHotKeyKeyCodeKey,
456                       [NSValue valueWithPointer:hotKeyRef], WineHotKeyCarbonRefKey,
457                       nil];
458         [hotKeysByMacID setObject:hotKeyDict forKey:macIDNumber];
459         [hotKeysByWinID setObject:hotKeyDict forKey:winIDPair];
461         return MACDRV_HOTKEY_SUCCESS;
462     }
465 /***********************************************************************
466  *              OnMainThread
468  * Run a block on the main thread synchronously.
469  */
470 void OnMainThread(dispatch_block_t block)
472     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
473     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
474     WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey];
475     dispatch_semaphore_t semaphore = NULL;
476     __block BOOL finished;
478     if (!queue)
479     {
480         semaphore = dispatch_semaphore_create(0);
481         dispatch_retain(semaphore);
482     }
484     finished = FALSE;
485     OnMainThreadAsync(^{
486         block();
487         finished = TRUE;
488         if (queue)
489             [queue signalEventAvailable];
490         else
491         {
492             dispatch_semaphore_signal(semaphore);
493             dispatch_release(semaphore);
494         }
495     });
497     if (queue)
498     {
499         while (!finished)
500         {
501             MacDrvEvent* macDrvEvent;
502             struct kevent kev;
504             while (!finished &&
505                    (macDrvEvent = [queue getEventMatchingMask:event_mask_for_type(QUERY_EVENT)]))
506             {
507                 queue->event_handler(macDrvEvent->event);
508             }
510             if (!finished)
511             {
512                 [pool release];
513                 pool = [[NSAutoreleasePool alloc] init];
515                 kevent(queue->kq, NULL, 0, &kev, 1, NULL);
516             }
517         }
518     }
519     else
520     {
521         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
522         dispatch_release(semaphore);
523     }
525     [pool release];
529 /***********************************************************************
530  *              macdrv_create_event_queue
532  * Register this thread with the application on the main thread, and set
533  * up an event queue on which it can deliver events to this thread.
534  */
535 macdrv_event_queue macdrv_create_event_queue(macdrv_event_handler handler)
537     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
538     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
540     WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey];
541     if (!queue)
542     {
543         queue = [[[WineEventQueue alloc] initWithEventHandler:handler] autorelease];
544         if (queue)
545         {
546             if ([[WineApplicationController sharedController] registerEventQueue:queue])
547                 [threadDict setObject:queue forKey:WineEventQueueThreadDictionaryKey];
548             else
549                 queue = nil;
550         }
551     }
553     [pool release];
554     return (macdrv_event_queue)queue;
557 /***********************************************************************
558  *              macdrv_destroy_event_queue
560  * Tell the application that this thread is exiting and destroy the
561  * associated event queue.
562  */
563 void macdrv_destroy_event_queue(macdrv_event_queue queue)
565     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
566     WineEventQueue* q = (WineEventQueue*)queue;
567     NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
569     [[WineApplicationController sharedController] unregisterEventQueue:q];
570     [threadDict removeObjectForKey:WineEventQueueThreadDictionaryKey];
572     [pool release];
575 /***********************************************************************
576  *              macdrv_get_event_queue_fd
578  * Get the file descriptor whose readability signals that there are
579  * events on the event queue.
580  */
581 int macdrv_get_event_queue_fd(macdrv_event_queue queue)
583     WineEventQueue* q = (WineEventQueue*)queue;
584     return q->fds[0];
587 /***********************************************************************
588  *              macdrv_copy_event_from_queue
590  * Pull an event matching the event mask from the event queue and store
591  * it in the event record pointed to by the event parameter.  If a
592  * matching event was found, return non-zero; otherwise, return 0.
594  * The caller is responsible for calling macdrv_release_event on any
595  * event returned by this function.
596  */
597 int macdrv_copy_event_from_queue(macdrv_event_queue queue,
598         macdrv_event_mask mask, macdrv_event **event)
600     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
601     WineEventQueue* q = (WineEventQueue*)queue;
603     MacDrvEvent* macDrvEvent = [q getEventMatchingMask:mask];
604     if (macDrvEvent)
605         *event = macdrv_retain_event(macDrvEvent->event);
607     [pool release];
608     return (macDrvEvent != nil);
611 /***********************************************************************
612  *              macdrv_create_event
613  */
614 macdrv_event* macdrv_create_event(int type, WineWindow* window)
616     macdrv_event *event;
618     event = calloc(1, sizeof(*event));
619     event->refs = 1;
620     event->deliver = INT_MAX;
621     event->type = type;
622     event->window = (macdrv_window)[window retain];
623     return event;
626 /***********************************************************************
627  *              macdrv_retain_event
628  */
629 macdrv_event* macdrv_retain_event(macdrv_event *event)
631     OSAtomicIncrement32Barrier(&event->refs);
632     return event;
635 /***********************************************************************
636  *              macdrv_release_event
638  * Decrements the reference count of an event.  If the count falls to
639  * zero, cleans up any resources, such as allocated memory or retained
640  * objects, held by the event and deallocates it
641  */
642 void macdrv_release_event(macdrv_event *event)
644     if (OSAtomicDecrement32Barrier(&event->refs) <= 0)
645     {
646         NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
648         switch (event->type)
649         {
650             case IM_SET_TEXT:
651                 if (event->im_set_text.text)
652                     CFRelease(event->im_set_text.text);
653                 break;
654             case KEYBOARD_CHANGED:
655                 CFRelease(event->keyboard_changed.uchr);
656                 CFRelease(event->keyboard_changed.input_source);
657                 break;
658             case QUERY_EVENT:
659             case QUERY_EVENT_NO_PREEMPT_WAIT:
660                 macdrv_release_query(event->query_event.query);
661                 break;
662             case WINDOW_GOT_FOCUS:
663                 [(NSMutableSet*)event->window_got_focus.tried_windows release];
664                 break;
665         }
667         [(WineWindow*)event->window release];
668         free(event);
670         [pool release];
671     }
674 /***********************************************************************
675  *              macdrv_create_query
676  */
677 macdrv_query* macdrv_create_query(void)
679     macdrv_query *query;
681     query = calloc(1, sizeof(*query));
682     query->refs = 1;
683     return query;
686 /***********************************************************************
687  *              macdrv_retain_query
688  */
689 macdrv_query* macdrv_retain_query(macdrv_query *query)
691     OSAtomicIncrement32Barrier(&query->refs);
692     return query;
695 /***********************************************************************
696  *              macdrv_release_query
697  */
698 void macdrv_release_query(macdrv_query *query)
700     if (OSAtomicDecrement32Barrier(&query->refs) <= 0)
701     {
702         switch (query->type)
703         {
704             case QUERY_DRAG_OPERATION:
705                 if (query->drag_operation.pasteboard)
706                     CFRelease(query->drag_operation.pasteboard);
707                 break;
708             case QUERY_DRAG_DROP:
709                 if (query->drag_drop.pasteboard)
710                     CFRelease(query->drag_drop.pasteboard);
711                 break;
712             case QUERY_PASTEBOARD_DATA:
713                 if (query->pasteboard_data.type)
714                     CFRelease(query->pasteboard_data.type);
715                 break;
716         }
717         [(WineWindow*)query->window release];
718         free(query);
719     }
722 /***********************************************************************
723  *              macdrv_set_query_done
724  */
725 void macdrv_set_query_done(macdrv_query *query)
727     macdrv_retain_query(query);
729     OnMainThreadAsync(^{
730         NSEvent* event;
732         query->done = TRUE;
733         macdrv_release_query(query);
735         event = [NSEvent otherEventWithType:NSApplicationDefined
736                                    location:NSZeroPoint
737                               modifierFlags:0
738                                   timestamp:[[NSProcessInfo processInfo] systemUptime]
739                                windowNumber:0
740                                     context:nil
741                                     subtype:WineApplicationEventWakeQuery
742                                       data1:0
743                                       data2:0];
744         [NSApp postEvent:event atStart:TRUE];
745     });
748 @end
751 /***********************************************************************
752  *              macdrv_register_hot_key
753  */
754 int macdrv_register_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags,
755                             unsigned int keycode, unsigned int modifiers)
757     WineEventQueue* queue = (WineEventQueue*)q;
758     __block int ret;
760     OnMainThread(^{
761         ret = [queue registerHotKey:keycode modifiers:modifiers vkey:vkey modFlags:mod_flags];
762     });
764     return ret;
768 /***********************************************************************
769  *              macdrv_unregister_hot_key
770  */
771 void macdrv_unregister_hot_key(macdrv_event_queue q, unsigned int vkey, unsigned int mod_flags)
773     WineEventQueue* queue = (WineEventQueue*)q;
775     OnMainThreadAsync(^{
776         [queue unregisterHotKey:vkey modFlags:mod_flags];
777     });