winemac: Add WineEventQueue class for conveying events from Cocoa to Wine threads.
This commit is contained in:
parent
b6d902ee46
commit
3c995bb682
|
@ -12,6 +12,7 @@ C_SRCS = \
|
||||||
OBJC_SRCS = \
|
OBJC_SRCS = \
|
||||||
cocoa_app.m \
|
cocoa_app.m \
|
||||||
cocoa_display.m \
|
cocoa_display.m \
|
||||||
|
cocoa_event.m \
|
||||||
cocoa_main.m \
|
cocoa_main.m \
|
||||||
cocoa_window.m
|
cocoa_window.m
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,20 @@
|
||||||
#define ERR(...) do { if (macdrv_err_on) LogError(__func__, __VA_ARGS__); } while (false)
|
#define ERR(...) do { if (macdrv_err_on) LogError(__func__, __VA_ARGS__); } while (false)
|
||||||
|
|
||||||
|
|
||||||
|
@class WineEventQueue;
|
||||||
|
|
||||||
|
|
||||||
@interface WineApplication : NSApplication <NSApplicationDelegate>
|
@interface WineApplication : NSApplication <NSApplicationDelegate>
|
||||||
|
{
|
||||||
|
NSMutableArray* eventQueues;
|
||||||
|
NSLock* eventQueuesLock;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) transformProcessToForeground;
|
- (void) transformProcessToForeground;
|
||||||
|
|
||||||
|
- (BOOL) registerEventQueue:(WineEventQueue*)queue;
|
||||||
|
- (void) unregisterEventQueue:(WineEventQueue*)queue;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
void OnMainThread(dispatch_block_t block);
|
void OnMainThread(dispatch_block_t block);
|
||||||
|
|
|
@ -26,6 +26,30 @@
|
||||||
|
|
||||||
@implementation WineApplication
|
@implementation WineApplication
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil)
|
||||||
|
{
|
||||||
|
eventQueues = [[NSMutableArray alloc] init];
|
||||||
|
eventQueuesLock = [[NSLock alloc] init];
|
||||||
|
|
||||||
|
if (!eventQueues || !eventQueuesLock)
|
||||||
|
{
|
||||||
|
[self release];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
[eventQueues release];
|
||||||
|
[eventQueuesLock release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) transformProcessToForeground
|
- (void) transformProcessToForeground
|
||||||
{
|
{
|
||||||
if ([self activationPolicy] != NSApplicationActivationPolicyRegular)
|
if ([self activationPolicy] != NSApplicationActivationPolicyRegular)
|
||||||
|
@ -69,6 +93,21 @@ - (void) transformProcessToForeground
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL) registerEventQueue:(WineEventQueue*)queue
|
||||||
|
{
|
||||||
|
[eventQueuesLock lock];
|
||||||
|
[eventQueues addObject:queue];
|
||||||
|
[eventQueuesLock unlock];
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) unregisterEventQueue:(WineEventQueue*)queue
|
||||||
|
{
|
||||||
|
[eventQueuesLock lock];
|
||||||
|
[eventQueues removeObjectIdenticalTo:queue];
|
||||||
|
[eventQueuesLock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* MACDRV Cocoa event queue declarations
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#include "macdrv_cocoa.h"
|
||||||
|
|
||||||
|
|
||||||
|
@interface WineEventQueue : NSObject
|
||||||
|
{
|
||||||
|
NSMutableArray* events;
|
||||||
|
NSLock* eventsLock;
|
||||||
|
|
||||||
|
int fds[2]; /* Pipe signaling when there are events queued. */
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) postEvent:(const macdrv_event*)inEvent;
|
||||||
|
- (void) discardEventsMatchingMask:(macdrv_event_mask)mask forWindow:(NSWindow*)window;
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,283 @@
|
||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#include "macdrv_cocoa.h"
|
||||||
|
#import "cocoa_event.h"
|
||||||
|
#import "cocoa_app.h"
|
||||||
|
#import "cocoa_window.h"
|
||||||
|
|
||||||
|
|
||||||
|
@interface MacDrvEvent : NSObject
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
macdrv_event event;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithEvent:(const macdrv_event*)event;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MacDrvEvent
|
||||||
|
|
||||||
|
- (id) initWithEvent:(const macdrv_event*)inEvent
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
event = *inEvent;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation WineEventQueue
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil)
|
||||||
|
{
|
||||||
|
fds[0] = fds[1] = -1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
[events release];
|
||||||
|
[eventsLock release];
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
[eventsLock lock];
|
||||||
|
[events addObject:event];
|
||||||
|
[eventsLock unlock];
|
||||||
|
|
||||||
|
[self signalEventAvailable];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) postEvent:(const 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* event;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
for (event in events)
|
||||||
|
{
|
||||||
|
if (event_mask_for_type(event->event.type) & mask)
|
||||||
|
break;
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event)
|
||||||
|
{
|
||||||
|
[event retain];
|
||||||
|
[events removeObjectAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
[eventsLock unlock];
|
||||||
|
return [event autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) discardEventsMatchingMask:(macdrv_event_mask)mask forWindow:(NSWindow*)window
|
||||||
|
{
|
||||||
|
NSMutableIndexSet* indexes = [[[NSMutableIndexSet alloc] init] autorelease];
|
||||||
|
|
||||||
|
[eventsLock lock];
|
||||||
|
|
||||||
|
[events enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
|
||||||
|
MacDrvEvent* event = obj;
|
||||||
|
if ((event_mask_for_type(event->event.type) & mask) &&
|
||||||
|
(!window || event->event.window == (macdrv_window)window))
|
||||||
|
{
|
||||||
|
macdrv_cleanup_event(&event->event);
|
||||||
|
[indexes addIndex:idx];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[events removeObjectsAtIndexes:indexes];
|
||||||
|
|
||||||
|
[eventsLock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* 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(void)
|
||||||
|
{
|
||||||
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
WineEventQueue* queue = [[WineEventQueue alloc] init];
|
||||||
|
if (queue && ![NSApp registerEventQueue:queue])
|
||||||
|
{
|
||||||
|
[queue release];
|
||||||
|
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;
|
||||||
|
|
||||||
|
[NSApp unregisterEventQueue:q];
|
||||||
|
[q release];
|
||||||
|
|
||||||
|
[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_get_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_cleanup_event on any
|
||||||
|
* event returned by this function.
|
||||||
|
*/
|
||||||
|
int macdrv_get_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 = macDrvEvent->event;
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
return (macDrvEvent != nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_cleanup_event
|
||||||
|
*
|
||||||
|
* Performs cleanup of an event. For event types which carry resources
|
||||||
|
* such as allocated memory or retained objects, frees/releases those
|
||||||
|
* resources.
|
||||||
|
*/
|
||||||
|
void macdrv_cleanup_event(macdrv_event *event)
|
||||||
|
{
|
||||||
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
[(WineWindow*)event->window release];
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -100,6 +100,7 @@
|
||||||
|
|
||||||
|
|
||||||
typedef struct macdrv_opaque_window* macdrv_window;
|
typedef struct macdrv_opaque_window* macdrv_window;
|
||||||
|
typedef struct macdrv_opaque_event_queue* macdrv_event_queue;
|
||||||
|
|
||||||
struct macdrv_display {
|
struct macdrv_display {
|
||||||
CGDirectDisplayID displayID;
|
CGDirectDisplayID displayID;
|
||||||
|
@ -119,6 +120,28 @@
|
||||||
extern void macdrv_free_displays(struct macdrv_display* displays) DECLSPEC_HIDDEN;
|
extern void macdrv_free_displays(struct macdrv_display* displays) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
|
||||||
|
/* event */
|
||||||
|
typedef uint32_t macdrv_event_mask;
|
||||||
|
|
||||||
|
typedef struct macdrv_event {
|
||||||
|
int type;
|
||||||
|
macdrv_window window;
|
||||||
|
} macdrv_event;
|
||||||
|
|
||||||
|
static inline macdrv_event_mask event_mask_for_type(int type)
|
||||||
|
{
|
||||||
|
return ((macdrv_event_mask)1 << type);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern macdrv_event_queue macdrv_create_event_queue(void) DECLSPEC_HIDDEN;
|
||||||
|
extern void macdrv_destroy_event_queue(macdrv_event_queue queue) DECLSPEC_HIDDEN;
|
||||||
|
extern int macdrv_get_event_queue_fd(macdrv_event_queue queue) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
extern int macdrv_get_event_from_queue(macdrv_event_queue queue,
|
||||||
|
macdrv_event_mask mask, macdrv_event *event) DECLSPEC_HIDDEN;
|
||||||
|
extern void macdrv_cleanup_event(macdrv_event *event) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
|
||||||
/* window */
|
/* window */
|
||||||
struct macdrv_window_features {
|
struct macdrv_window_features {
|
||||||
unsigned int title_bar:1;
|
unsigned int title_bar:1;
|
||||||
|
|
Loading…
Reference in New Issue