]> Pileus Git - ~andy/gtk/blobdiff - gdk/quartz/gdkeventloop-quartz.c
Fix broken quartz build from df3e19b
[~andy/gtk] / gdk / quartz / gdkeventloop-quartz.c
index 32ea8a47c6e9e39a700b17a72872f8ac4161bac6..0339bea1744532111adb5f9173775a87adcfe465 100644 (file)
@@ -7,6 +7,7 @@
 #include <unistd.h>
 
 #include "gdkprivate-quartz.h"
+#include <gdk/gdkdisplayprivate.h>
 
 /* 
  * This file implementations integration between the GLib main loop and
@@ -124,7 +125,7 @@ static NSAutoreleasePool *autorelease_pool;
  * a run loop iteration, so we need to detect that and avoid triggering
  * our "run the GLib main looop while the run loop is active machinery.
  */
-static gboolean getting_events;
+static gint getting_events = 0;
 
 /************************************************************
  *********              Select Thread               *********
@@ -207,9 +208,12 @@ signal_main_thread (void)
    */
   if (!run_loop_polling_async)
     CFRunLoopSourceSignal (select_main_thread_source);
-  
-  if (CFRunLoopIsWaiting (main_thread_run_loop))
-    CFRunLoopWakeUp (main_thread_run_loop);
+
+  /* Don't check for CFRunLoopIsWaiting() here because it causes a
+   * race condition (the loop could go into waiting state right after
+   * we checked).
+   */
+  CFRunLoopWakeUp (main_thread_run_loop);
 }
 
 static void *
@@ -613,14 +617,17 @@ gdk_event_prepare (GSource *source,
 {
   gboolean retval;
 
-  GDK_THREADS_ENTER ();
+  gdk_threads_enter ();
   
   *timeout = -1;
 
-  retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
-           _gdk_quartz_event_loop_check_pending ());
+  if (_gdk_display->event_pause_count > 0)
+    retval = FALSE;
+  else
+    retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
+              _gdk_quartz_event_loop_check_pending ());
 
-  GDK_THREADS_LEAVE ();
+  gdk_threads_leave ();
 
   return retval;
 }
@@ -630,26 +637,15 @@ gdk_event_check (GSource *source)
 {
   gboolean retval;
 
-  GDK_THREADS_ENTER ();
-
-/* Refresh the autorelease pool if we're at the base CFRunLoop level
- * (indicated by current_loop_level) and the base g_main_loop level
- * (indicated by g_main_depth()). Messing with the autorelease pool at
- * any level of nesting can cause access to deallocated memory because
- * autorelease_pool is static and releasing a pool will cause all
- * pools allocated inside of it to be released as well.
- */
-  if (current_loop_level == 0 && g_main_depth() == 0)
-    {
-      if (autorelease_pool)
-       [autorelease_pool release];
-      autorelease_pool = [[NSAutoreleasePool alloc] init];
-    }
+  gdk_threads_enter ();
 
-  retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
-           _gdk_quartz_event_loop_check_pending ());
+  if (_gdk_display->event_pause_count > 0)
+    retval = FALSE;
+  else
+    retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
+              _gdk_quartz_event_loop_check_pending ());
 
-  GDK_THREADS_LEAVE ();
+  gdk_threads_leave ();
 
   return retval;
 }
@@ -661,7 +657,22 @@ gdk_event_dispatch (GSource     *source,
 {
   GdkEvent *event;
 
-  GDK_THREADS_ENTER ();
+  gdk_threads_enter ();
+
+  /* Refresh the autorelease pool if we're at the base CFRunLoop level
+   * (indicated by current_loop_level) and the base g_main_loop level
+   * (indicated by g_main_depth()). Messing with the autorelease pool at
+   * any level of nesting can cause access to deallocated memory because
+   * autorelease_pool is static and releasing a pool will cause all pools
+   * allocated inside of it to be released as well.
+   */
+  if (current_loop_level == 0 && g_main_depth() == 0)
+    {
+      if (autorelease_pool)
+        [autorelease_pool drain];
+
+      autorelease_pool = [[NSAutoreleasePool alloc] init];
+    }
 
   _gdk_quartz_display_queue_events (_gdk_display);
 
@@ -674,7 +685,7 @@ gdk_event_dispatch (GSource     *source,
       gdk_event_free (event);
     }
 
-  GDK_THREADS_LEAVE ();
+  gdk_threads_leave ();
 
   return TRUE;
 }
@@ -699,6 +710,10 @@ poll_func (GPollFD *ufds,
   NSDate *limit_date;
   gint n_ready;
 
+  static GPollFD *last_ufds;
+
+  last_ufds = ufds;
+
   n_ready = select_thread_start_poll (ufds, nfds, timeout_);
   if (n_ready > 0)
     timeout_ = 0;
@@ -710,14 +725,23 @@ poll_func (GPollFD *ufds,
   else
     limit_date = [NSDate dateWithTimeIntervalSinceNow:timeout_/1000.0];
 
-  getting_events = TRUE;
+  getting_events++;
   event = [NSApp nextEventMatchingMask: NSAnyEventMask
                             untilDate: limit_date
                                inMode: NSDefaultRunLoopMode
                                dequeue: YES];
-  getting_events = FALSE;
-
-  if (n_ready < 0)
+  getting_events--;
+
+  /* We check if last_ufds did not change since the time this function was
+   * called. It is possible that a recursive main loop (and thus recursive
+   * invocation of this poll function) is triggered while in
+   * nextEventMatchingMask:. If during that time new fds are added,
+   * the cached fds array might be replaced in g_main_context_iterate().
+   * So, we should avoid accessing the old fd array (still pointed at by
+   * ufds) here in that case, since it might have been freed. We avoid this
+   * by not calling the collect stage.
+   */
+  if (last_ufds == ufds && n_ready < 0)
     n_ready = select_thread_collect_poll (ufds, nfds);
       
   if (event &&
@@ -776,8 +800,6 @@ query_main_context (GMainContext *context,
 static void
 run_loop_entry (void)
 {
-  current_loop_level++;
-
   if (acquired_loop_level == -1)
     {
       if (g_main_context_acquire (NULL))
@@ -926,16 +948,13 @@ run_loop_after_waiting (void)
 static void
 run_loop_exit (void)
 {
-  g_return_if_fail (current_loop_level > 0);
-
-  if (current_loop_level == acquired_loop_level)
+  /* + 1 because we decrement current_loop_level separately in observer_callback() */
+  if ((current_loop_level + 1) == acquired_loop_level)
     {
       g_main_context_release (NULL);
       acquired_loop_level = -1;
       GDK_NOTE (EVENTLOOP, g_print ("EventLoop: Ended tracking run loop activity\n"));
     }
-  
-  current_loop_level--;
 }
 
 static void
@@ -943,9 +962,22 @@ run_loop_observer_callback (CFRunLoopObserverRef observer,
                            CFRunLoopActivity    activity,
                            void                *info)
 {
-  if (getting_events) /* Activity we triggered */
+  switch (activity)
+    {
+    case kCFRunLoopEntry:
+      current_loop_level++;
+      break;
+    case kCFRunLoopExit:
+      g_return_if_fail (current_loop_level > 0);
+      current_loop_level--;
+      break;
+    default:
+      break;
+    }
+
+  if (getting_events > 0) /* Activity we triggered */
     return;
-  
+
   switch (activity)
     {
     case kCFRunLoopEntry: