msxml3: Implement IXMLParser Get/Set Factory.
[wine/multimedia.git] / dlls / winemac.drv / cocoa_event.m
blob377faa825d5b05e92342612e42a7b23cd986f977
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>
26 #include "macdrv_cocoa.h"
27 #import "cocoa_event.h"
28 #import "cocoa_app.h"
29 #import "cocoa_window.h"
32 @interface MacDrvEvent : NSObject
34 @public
35     macdrv_event event;
38     - (id) initWithEvent:(const macdrv_event*)event;
40 @end
42 @implementation MacDrvEvent
44     - (id) initWithEvent:(const macdrv_event*)inEvent
45     {
46         self = [super init];
47         if (self)
48         {
49             event = *inEvent;
50         }
51         return self;
52     }
54 @end
57 @implementation WineEventQueue
59     - (id) init
60     {
61         self = [super init];
62         if (self != nil)
63         {
64             fds[0] = fds[1] = -1;
66             events = [[NSMutableArray alloc] init];
67             eventsLock = [[NSLock alloc] init];
69             if (!events || !eventsLock)
70             {
71                 [self release];
72                 return nil;
73             }
75             if (pipe(fds) ||
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)
80             {
81                 [self release];
82                 return nil;
83             }
84         }
85         return self;
86     }
88     - (void) dealloc
89     {
90         [events release];
91         [eventsLock release];
93         if (fds[0] != -1) close(fds[0]);
94         if (fds[1] != -1) close(fds[1]);
96         [super dealloc];
97     }
99     - (void) signalEventAvailable
100     {
101         char junk = 1;
102         int rc;
104         do
105         {
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));
111     }
113     - (void) postEventObject:(MacDrvEvent*)event
114     {
115         MacDrvEvent* lastEvent;
117         [eventsLock lock];
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)
125         {
126             if (event->event.type == MOUSE_MOVED)
127             {
128                 lastEvent->event.mouse_moved.x += event->event.mouse_moved.x;
129                 lastEvent->event.mouse_moved.y += event->event.mouse_moved.y;
130             }
131             else
132             {
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;
136             }
138             lastEvent->event.mouse_moved.time_ms = event->event.mouse_moved.time_ms;
140             macdrv_cleanup_event(&event->event);
141         }
142         else
143             [events addObject:event];
145         [eventsLock unlock];
147         [self signalEventAvailable];
148     }
150     - (void) postEvent:(const macdrv_event*)inEvent
151     {
152         MacDrvEvent* event = [[MacDrvEvent alloc] initWithEvent:inEvent];
153         [self postEventObject:event];
154         [event release];
155     }
157     - (MacDrvEvent*) getEventMatchingMask:(macdrv_event_mask)mask
158     {
159         char buf[512];
160         int rc;
161         NSUInteger index;
162         MacDrvEvent* event;
164         /* Clear the pipe which signals there are pending events. */
165         do
166         {
167             rc = read(fds[0], buf, sizeof(buf));
168         } while (rc > 0 || (rc < 0 && errno == EINTR));
169         if (rc == 0 || (rc < 0 && errno != EAGAIN))
170         {
171             if (rc == 0)
172                 ERR(@"%@: event queue signaling pipe unexpectedly closed\n", self);
173             else
174                 ERR(@"%@: got error reading from event queue signaling pipe: %s\n", self, strerror(errno));
175             return nil;
176         }
178         [eventsLock lock];
180         index = 0;
181         for (event in events)
182         {
183             if (event_mask_for_type(event->event.type) & mask)
184                 break;
186             index++;
187         }
189         if (event)
190         {
191             [event retain];
192             [events removeObjectAtIndex:index];
193         }
195         [eventsLock unlock];
196         return [event autorelease];
197     }
199     - (void) discardEventsMatchingMask:(macdrv_event_mask)mask forWindow:(NSWindow*)window
200     {
201         NSMutableIndexSet* indexes = [[[NSMutableIndexSet alloc] init] autorelease];
203         [eventsLock lock];
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))
209             {
210                 macdrv_cleanup_event(&event->event);
211                 [indexes addIndex:idx];
212             }
213         }];
215         [events removeObjectsAtIndexes:indexes];
217         [eventsLock unlock];
218     }
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.
226  */
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])
233     {
234         [queue release];
235         queue = nil;
236     }
238     [pool release];
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.
247  */
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];
254     [q release];
256     [pool release];
259 /***********************************************************************
260  *              macdrv_get_event_queue_fd
262  * Get the file descriptor whose readability signals that there are
263  * events on the event queue.
264  */
265 int macdrv_get_event_queue_fd(macdrv_event_queue queue)
267     WineEventQueue* q = (WineEventQueue*)queue;
268     return q->fds[0];
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.
280  */
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];
288     if (macDrvEvent)
289         *event = macDrvEvent->event;
291     [pool release];
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
300  * resources.
301  */
302 void macdrv_cleanup_event(macdrv_event *event)
304     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
306     switch (event->type)
307     {
308         case KEYBOARD_CHANGED:
309             CFRelease(event->keyboard_changed.uchr);
310             break;
311         case WINDOW_GOT_FOCUS:
312             [(NSMutableSet*)event->window_got_focus.tried_windows release];
313             break;
314     }
316     [(WineWindow*)event->window release];
318     [pool release];
321 @end