2 * MACDRV Cocoa event queue code
4 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
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.
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.
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
21 #include <sys/types.h>
22 #include <sys/event.h>
24 #include <libkern/OSAtomic.h>
26 #include "macdrv_cocoa.h"
27 #import "cocoa_event.h"
29 #import "cocoa_window.h"
32 @interface MacDrvEvent : NSObject
38 - (id) initWithEvent:(const macdrv_event*)event;
42 @implementation MacDrvEvent
44 - (id) initWithEvent:(const macdrv_event*)inEvent
57 @implementation WineEventQueue
66 events = [[NSMutableArray alloc] init];
67 eventsLock = [[NSLock alloc] init];
69 if (!events || !eventsLock)
76 fcntl(fds[0], F_SETFD, 1) == -1 ||
77 fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
78 fcntl(fds[1], F_SETFD, 1) == -1 ||
79 fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1)
93 if (fds[0] != -1) close(fds[0]);
94 if (fds[1] != -1) close(fds[1]);
99 - (void) signalEventAvailable
106 rc = write(fds[1], &junk, 1);
107 } while (rc < 0 && errno == EINTR);
109 if (rc < 0 && errno != EAGAIN)
110 ERR(@"%@: got error writing to event queue signaling pipe: %s\n", self, strerror(errno));
113 - (void) postEventObject:(MacDrvEvent*)event
115 MacDrvEvent* lastEvent;
119 if ((event->event.type == MOUSE_MOVED ||
120 event->event.type == MOUSE_MOVED_ABSOLUTE) &&
121 (lastEvent = [events lastObject]) &&
122 (lastEvent->event.type == MOUSE_MOVED ||
123 lastEvent->event.type == MOUSE_MOVED_ABSOLUTE) &&
124 lastEvent->event.window == event->event.window)
126 if (event->event.type == MOUSE_MOVED)
128 lastEvent->event.mouse_moved.x += event->event.mouse_moved.x;
129 lastEvent->event.mouse_moved.y += event->event.mouse_moved.y;
133 lastEvent->event.type = MOUSE_MOVED_ABSOLUTE;
134 lastEvent->event.mouse_moved.x = event->event.mouse_moved.x;
135 lastEvent->event.mouse_moved.y = event->event.mouse_moved.y;
138 lastEvent->event.mouse_moved.time_ms = event->event.mouse_moved.time_ms;
140 macdrv_cleanup_event(&event->event);
143 [events addObject:event];
147 [self signalEventAvailable];
150 - (void) postEvent:(const macdrv_event*)inEvent
152 MacDrvEvent* event = [[MacDrvEvent alloc] initWithEvent:inEvent];
153 [self postEventObject:event];
157 - (MacDrvEvent*) getEventMatchingMask:(macdrv_event_mask)mask
164 /* Clear the pipe which signals there are pending events. */
167 rc = read(fds[0], buf, sizeof(buf));
168 } while (rc > 0 || (rc < 0 && errno == EINTR));
169 if (rc == 0 || (rc < 0 && errno != EAGAIN))
172 ERR(@"%@: event queue signaling pipe unexpectedly closed\n", self);
174 ERR(@"%@: got error reading from event queue signaling pipe: %s\n", self, strerror(errno));
181 for (event in events)
183 if (event_mask_for_type(event->event.type) & mask)
192 [events removeObjectAtIndex:index];
196 return [event autorelease];
199 - (void) discardEventsMatchingMask:(macdrv_event_mask)mask forWindow:(NSWindow*)window
201 NSMutableIndexSet* indexes = [[[NSMutableIndexSet alloc] init] autorelease];
205 [events enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
206 MacDrvEvent* event = obj;
207 if ((event_mask_for_type(event->event.type) & mask) &&
208 (!window || event->event.window == (macdrv_window)window))
210 macdrv_cleanup_event(&event->event);
211 [indexes addIndex:idx];
215 [events removeObjectsAtIndexes:indexes];
221 /***********************************************************************
222 * macdrv_create_event_queue
224 * Register this thread with the application on the main thread, and set
225 * up an event queue on which it can deliver events to this thread.
227 macdrv_event_queue macdrv_create_event_queue(void)
229 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
231 WineEventQueue* queue = [[WineEventQueue alloc] init];
232 if (queue && ![NSApp registerEventQueue:queue])
239 return (macdrv_event_queue)queue;
242 /***********************************************************************
243 * macdrv_destroy_event_queue
245 * Tell the application that this thread is exiting and destroy the
246 * associated event queue.
248 void macdrv_destroy_event_queue(macdrv_event_queue queue)
250 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
251 WineEventQueue* q = (WineEventQueue*)queue;
253 [NSApp unregisterEventQueue:q];
259 /***********************************************************************
260 * macdrv_get_event_queue_fd
262 * Get the file descriptor whose readability signals that there are
263 * events on the event queue.
265 int macdrv_get_event_queue_fd(macdrv_event_queue queue)
267 WineEventQueue* q = (WineEventQueue*)queue;
271 /***********************************************************************
272 * macdrv_get_event_from_queue
274 * Pull an event matching the event mask from the event queue and store
275 * it in the event record pointed to by the event parameter. If a
276 * matching event was found, return non-zero; otherwise, return 0.
278 * The caller is responsible for calling macdrv_cleanup_event on any
279 * event returned by this function.
281 int macdrv_get_event_from_queue(macdrv_event_queue queue,
282 macdrv_event_mask mask, macdrv_event *event)
284 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
285 WineEventQueue* q = (WineEventQueue*)queue;
287 MacDrvEvent* macDrvEvent = [q getEventMatchingMask:mask];
289 *event = macDrvEvent->event;
292 return (macDrvEvent != nil);
295 /***********************************************************************
296 * macdrv_cleanup_event
298 * Performs cleanup of an event. For event types which carry resources
299 * such as allocated memory or retained objects, frees/releases those
302 void macdrv_cleanup_event(macdrv_event *event)
304 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
308 case KEYBOARD_CHANGED:
309 CFRelease(event->keyboard_changed.uchr);
311 case WINDOW_GOT_FOCUS:
312 [(NSMutableSet*)event->window_got_focus.tried_windows release];
316 [(WineWindow*)event->window release];