gtkmain: be deterministic in source removal
authorChristian Hergert <chergert@redhat.com>
Fri, 10 Jan 2020 23:04:44 +0000 (15:04 -0800)
committerChristian Hergert <chergert@redhat.com>
Fri, 10 Jan 2020 23:04:44 +0000 (15:04 -0800)
Fixes gtk_main_sync() to only remove a source if it has not
already executed (and been removed). The previous code was
using gtk_main_quit() directly which would be non-determinstic
based on the previous value in the return register.

gtk/gtkmain.c

index 93fea8540ae4367f868fe4c8f5746661627c5d37..37ee557c480ef4b842aa892247e5911aadbe940e 100644 (file)
@@ -1044,6 +1044,7 @@ gtk_main (void)
 typedef struct {
   GMainLoop *store_loop;
   guint n_clipboards;
+  guint timeout_id;
 } ClipboardStore;
 
 static void
@@ -1071,13 +1072,20 @@ clipboard_store_finished (GObject      *source,
     g_main_loop_quit (store->store_loop);
 }
 
+static gboolean
+sync_timed_out_cb (ClipboardStore *store)
+{
+  store->timeout_id = 0;
+  g_main_loop_quit (store->store_loop);
+  return G_SOURCE_REMOVE;
+}
+
 void
 gtk_main_sync (void)
 {
   ClipboardStore store = { NULL, };
   GSList *displays, *l;
   GCancellable *cancel;
-  guint store_timeout;
   
   /* Try storing all clipboard data we have */
   displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
@@ -1101,17 +1109,16 @@ gtk_main_sync (void)
   g_slist_free (displays);
 
   store.store_loop = g_main_loop_new (NULL, TRUE);
-  store_timeout = g_timeout_add_seconds (10, (GSourceFunc) g_main_loop_quit, store.store_loop);
-  g_source_set_name_by_id (store_timeout, "[gtk] gtk_main_sync clipboard store timeout");
+  store.timeout_id = g_timeout_add_seconds (10, (GSourceFunc) sync_timed_out_cb, &store);
+  g_source_set_name_by_id (store.timeout_id, "[gtk] gtk_main_sync clipboard store timeout");
 
   if (g_main_loop_is_running (store.store_loop))
     g_main_loop_run (store.store_loop);
   
   g_cancellable_cancel (cancel);
   g_object_unref (cancel);
-  g_source_remove (store_timeout);
-  g_main_loop_unref (store.store_loop);
-  store.store_loop = NULL;
+  g_clear_handle_id (&store.timeout_id, g_source_remove);
+  g_clear_pointer (&store.store_loop, g_main_loop_unref);
   
   /* Synchronize the recent manager singleton */
   _gtk_recent_manager_sync ();