9 #include "gdkprivate-quartz.h"
11 static GPollFD event_poll_fd;
12 static NSEvent *current_event;
14 static GPollFunc old_poll_func;
16 static gboolean select_fd_waiting = FALSE;
17 static pthread_t select_thread = 0;
18 static int wakeup_pipe[2];
19 static pthread_mutex_t pollfd_mutex = PTHREAD_MUTEX_INITIALIZER;
20 static pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;
21 static GPollFD *pollfds;
22 static GPollFD *pipe_pollfd;
23 static guint n_pollfds;
24 static CFRunLoopSourceRef select_main_thread_source;
25 static CFRunLoopRef main_thread_run_loop;
28 gdk_event_prepare (GSource *source,
34 GDK_QUARTZ_ALLOC_POOL;
38 event = [NSApp nextEventMatchingMask: NSAnyEventMask
39 untilDate: [NSDate distantPast]
40 inMode: NSDefaultRunLoopMode
43 retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
46 GDK_QUARTZ_RELEASE_POOL;
52 gdk_event_check (GSource *source)
54 if (_gdk_event_queue_find_first (_gdk_display) != NULL ||
58 /* FIXME: We should maybe try to fetch an event again here */
64 gdk_event_dispatch (GSource *source,
70 GDK_QUARTZ_ALLOC_POOL;
72 _gdk_events_queue (_gdk_display);
74 event = _gdk_event_unqueue (_gdk_display);
79 (*_gdk_event_func) (event, _gdk_event_data);
81 gdk_event_free (event);
84 GDK_QUARTZ_RELEASE_POOL;
89 static GSourceFuncs event_funcs = {
97 got_fd_activity (void *info)
101 /* Post a message so we'll break out of the message loop */
102 event = [NSEvent otherEventWithType: NSApplicationDefined
103 location: NSZeroPoint
112 [NSApp postEvent:event atStart:YES];
116 select_thread_func (void *arg)
120 pthread_mutex_lock (&pollfd_mutex);
121 pthread_cond_signal (&ready_cond);
128 pthread_cond_wait (&ready_cond, &pollfd_mutex);
130 pthread_mutex_unlock (&pollfd_mutex);
131 select_fd_waiting = TRUE;
132 n_active_fds = old_poll_func (pollfds, n_pollfds, -1);
133 select_fd_waiting = FALSE;
134 pthread_mutex_lock (&pollfd_mutex);
135 n = read (pipe_pollfd->fd, &c, 1);
142 pthread_mutex_unlock (&pollfd_mutex);
146 /* We have active fds, signal the main thread */
147 CFRunLoopSourceSignal (select_main_thread_source);
148 if (CFRunLoopIsWaiting (main_thread_run_loop))
149 CFRunLoopWakeUp (main_thread_run_loop);
152 pthread_mutex_lock (&pollfd_mutex);
157 poll_func (GPollFD *ufds, guint nfds, gint timeout_)
164 GDK_QUARTZ_ALLOC_POOL;
168 if (!select_thread) {
169 /* Create source used for signalling the main thread */
170 main_thread_run_loop = CFRunLoopGetCurrent ();
171 CFRunLoopSourceContext source_context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, got_fd_activity };
172 select_main_thread_source = CFRunLoopSourceCreate (NULL, 0, &source_context);
173 CFRunLoopAddSource (main_thread_run_loop, select_main_thread_source, kCFRunLoopDefaultMode);
176 fcntl(wakeup_pipe[0], F_SETFL, O_NONBLOCK);
178 pthread_mutex_lock (&pollfd_mutex);
179 pthread_create (&select_thread, NULL, select_thread_func, NULL);
180 pthread_cond_wait (&ready_cond, &pollfd_mutex);
182 pthread_mutex_lock (&pollfd_mutex);
186 pollfds = g_memdup (ufds, sizeof (GPollFD) * nfds);
188 /* We cheat and use the fake fd for our pipe */
189 for (i = 0; i < nfds; i++)
191 if (pollfds[i].fd == -1)
193 pipe_pollfd = &pollfds[i];
194 pollfds[i].fd = wakeup_pipe[0];
195 pollfds[i].events = G_IO_IN;
199 /* Start our thread */
200 pthread_cond_signal (&ready_cond);
201 pthread_mutex_unlock (&pollfd_mutex);
205 limit_date = [NSDate distantFuture];
206 else if (timeout_ == 0)
207 limit_date = [NSDate distantPast];
209 limit_date = [NSDate dateWithTimeIntervalSinceNow:timeout_/1000.0];
211 event = [NSApp nextEventMatchingMask: NSAnyEventMask
212 untilDate: limit_date
213 inMode: NSDefaultRunLoopMode
218 if ([event type] == NSApplicationDefined)
220 pthread_mutex_lock (&pollfd_mutex);
222 for (i = 0; i < n_pollfds; i++)
224 if (ufds[i].fd == -1)
227 g_assert (ufds[i].fd == pollfds[i].fd);
228 g_assert (ufds[i].events == pollfds[i].events);
230 if (pollfds[i].revents)
232 ufds[i].revents = pollfds[i].revents;
237 pthread_mutex_unlock (&pollfd_mutex);
239 event = [NSApp nextEventMatchingMask: NSAnyEventMask
240 untilDate: [NSDate distantPast]
241 inMode: NSDefaultRunLoopMode
247 /* There were no active fds, break out of the other thread's poll() */
248 pthread_mutex_lock (&pollfd_mutex);
249 if (select_fd_waiting && wakeup_pipe[1])
253 write (wakeup_pipe[1], &c, 1);
255 pthread_mutex_unlock (&pollfd_mutex);
259 ufds[0].revents = G_IO_IN;
261 /* FIXME: We can't assert here, but we might need to have a
262 * queue for events instead.
264 /*g_assert (current_event == NULL);*/
266 current_event = [event retain];
271 GDK_QUARTZ_RELEASE_POOL;
277 _gdk_quartz_event_loop_init (void)
281 event_poll_fd.events = G_IO_IN;
282 event_poll_fd.fd = -1;
284 source = g_source_new (&event_funcs, sizeof (GSource));
285 g_source_add_poll (source, &event_poll_fd);
286 g_source_set_priority (source, GDK_PRIORITY_EVENTS);
287 g_source_set_can_recurse (source, TRUE);
288 g_source_attach (source, NULL);
290 old_poll_func = g_main_context_get_poll_func (NULL);
291 g_main_context_set_poll_func (NULL, poll_func);
296 _gdk_quartz_event_loop_get_current (void)
298 return current_event;
302 _gdk_quartz_event_loop_release_current (void)
304 [current_event release];
305 current_event = NULL;