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