[mutter] util: Move MetaLater to its own file



commit d682cdb078f281b03084e3e0d7ab40d3ea382c1f
Author: Jonas Ådahl <jadahl gmail com>
Date:   Tue Mar 3 08:46:11 2020 +0100

    util: Move MetaLater to its own file
    
    While at it, fix some style inconsistencies, for now use a single
    singleton struct instead of multiple static variables, and
    other non-functional cleanups. Semantically, there is no changes
    introduced.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/798

 src/compositor/meta-later.c | 321 ++++++++++++++++++++++++++++++++++++++++++++
 src/core/util.c             | 285 ---------------------------------------
 src/meson.build             |   1 +
 3 files changed, 322 insertions(+), 285 deletions(-)
---
diff --git a/src/compositor/meta-later.c b/src/compositor/meta-later.c
new file mode 100644
index 000000000..1b71f58bb
--- /dev/null
+++ b/src/compositor/meta-later.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2005 Elijah Newren
+ * Copyright (C) 2020 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "cogl/cogl.h"
+#include "meta/util.h"
+
+typedef struct _MetaLater
+{
+  unsigned int id;
+  unsigned int ref_count;
+  MetaLaterType when;
+
+  GSourceFunc func;
+  gpointer user_data;
+  GDestroyNotify destroy_notify;
+
+  guint source_id;
+  gboolean run_once;
+} MetaLater;
+
+typedef struct _MetaLaters MetaLaters;
+
+#define META_LATER_N_TYPES (META_LATER_IDLE + 1)
+
+struct _MetaLaters
+{
+  unsigned int last_later_id;
+
+  GSList *laters[META_LATER_N_TYPES];
+
+  ClutterTimeline *timeline;
+  guint repaint_func;
+};
+
+static MetaLaters _laters;
+
+static MetaLater *
+meta_later_ref (MetaLater *later)
+{
+  later->ref_count++;
+  return later;
+}
+
+static void
+meta_later_unref (MetaLater *later)
+{
+  if (--later->ref_count == 0)
+    {
+      if (later->destroy_notify)
+        {
+          later->destroy_notify (later->user_data);
+          later->destroy_notify = NULL;
+        }
+
+      g_slice_free (MetaLater, later);
+    }
+}
+
+static void
+meta_later_destroy (MetaLater *later)
+{
+  g_clear_handle_id (&later->source_id, g_source_remove);
+  later->func = NULL;
+  meta_later_unref (later);
+}
+
+#ifdef COGL_HAS_TRACING
+static const char *
+later_type_to_string (MetaLaterType when)
+{
+  switch (when)
+    {
+    case META_LATER_RESIZE:
+      return "Later (resize)";
+    case META_LATER_CALC_SHOWING:
+      return "Later (calc-showing)";
+    case META_LATER_CHECK_FULLSCREEN:
+      return "Later (check-fullscreen)";
+    case META_LATER_SYNC_STACK:
+      return "Later (sync-stack)";
+    case META_LATER_BEFORE_REDRAW:
+      return "Later (before-redraw)";
+    case META_LATER_IDLE:
+      return "Later (idle)";
+    }
+
+  return "unknown";
+}
+#endif
+
+static gboolean
+meta_later_invoke (MetaLater *later)
+{
+  COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when));
+  return later->func (later->user_data);
+}
+
+static gboolean
+remove_later_from_list (unsigned int   later_id,
+                        GSList       **laters_list)
+{
+  GSList *l;
+
+  for (l = *laters_list; l; l = l->next)
+    {
+      MetaLater *later = l->data;
+
+      if (later->id == later_id)
+        {
+          *laters_list = g_slist_delete_link (*laters_list, l);
+          meta_later_destroy (later);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+run_repaint_laters (GSList **laters_list)
+{
+  g_autoptr (GSList) laters_copy = NULL;
+  GSList *l;
+
+  for (l = *laters_list; l; l = l->next)
+    {
+      MetaLater *later = l->data;
+
+      if (!later->source_id ||
+          (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
+        laters_copy = g_slist_prepend (laters_copy, meta_later_ref (later));
+    }
+  laters_copy = g_slist_reverse (laters_copy);
+
+  for (l = laters_copy; l; l = l->next)
+    {
+      MetaLater *later = l->data;
+
+      if (!later->func)
+        remove_later_from_list (later->id, laters_list);
+      else if (!meta_later_invoke (later))
+        remove_later_from_list (later->id, laters_list);
+
+      meta_later_unref (later);
+    }
+}
+
+static gboolean
+run_all_repaint_laters (gpointer data)
+{
+  MetaLaters *laters = data;
+  unsigned int i;
+  GSList *l;
+  gboolean keep_timeline_running = FALSE;
+
+  for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
+    run_repaint_laters (&laters->laters[i]);
+
+  for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
+    {
+      for (l = laters->laters[i]; l; l = l->next)
+        {
+          MetaLater *later = l->data;
+
+          if (!later->source_id)
+            keep_timeline_running = TRUE;
+        }
+    }
+
+  if (!keep_timeline_running)
+    clutter_timeline_stop (laters->timeline);
+
+  return TRUE;
+}
+
+static void
+ensure_later_repaint_func (MetaLaters *laters)
+{
+  if (!laters->timeline)
+    laters->timeline = clutter_timeline_new (G_MAXUINT);
+
+  if (laters->repaint_func == 0)
+    {
+      laters->repaint_func =
+        clutter_threads_add_repaint_func (run_all_repaint_laters,
+                                          laters, NULL);
+    }
+
+  /* Make sure the repaint function gets run */
+  clutter_timeline_start (laters->timeline);
+}
+
+static gboolean
+invoke_later_idle (gpointer data)
+{
+  MetaLater *later = data;
+
+  if (!later->func (later->user_data))
+    {
+      meta_later_remove (later->id);
+      return FALSE;
+    }
+  else
+    {
+      later->run_once = TRUE;
+      return TRUE;
+    }
+}
+
+static unsigned int
+meta_laters_add (MetaLaters     *laters,
+                 MetaLaterType   when,
+                 GSourceFunc     func,
+                 gpointer        user_data,
+                 GDestroyNotify  notify)
+{
+  MetaLater *later = g_slice_new0 (MetaLater);
+
+  later->id = ++laters->last_later_id;
+  later->ref_count = 1;
+  later->when = when;
+  later->func = func;
+  later->user_data = user_data;
+  later->destroy_notify = notify;
+
+  laters->laters[when] = g_slist_prepend (laters->laters[when], later);
+
+  switch (when)
+    {
+    case META_LATER_RESIZE:
+      later->source_id = g_idle_add_full (META_PRIORITY_RESIZE,
+                                          invoke_later_idle,
+                                          later, NULL);
+      g_source_set_name_by_id (later->source_id, "[mutter] invoke_later_idle");
+      ensure_later_repaint_func (laters);
+      break;
+    case META_LATER_CALC_SHOWING:
+    case META_LATER_CHECK_FULLSCREEN:
+    case META_LATER_SYNC_STACK:
+    case META_LATER_BEFORE_REDRAW:
+      ensure_later_repaint_func (laters);
+      break;
+    case META_LATER_IDLE:
+      later->source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+                                          invoke_later_idle,
+                                          later, NULL);
+      g_source_set_name_by_id (later->source_id, "[mutter] invoke_later_idle");
+      break;
+    }
+
+  return later->id;
+}
+
+/**
+ * meta_later_add:
+ * @when: enumeration value determining the phase at which to run the callback
+ * @func: callback to run later
+ * @data: data to pass to the callback
+ * @notify: function to call to destroy @data when it is no longer in use, or %NULL
+ *
+ * Sets up a callback  to be called at some later time. @when determines the
+ * particular later occasion at which it is called. This is much like g_idle_add(),
+ * except that the functions interact properly with clutter event handling.
+ * If a "later" function is added from a clutter event handler, and is supposed
+ * to be run before the stage is redrawn, it will be run before that redraw
+ * of the stage, not the next one.
+ *
+ * Return value: an integer ID (guaranteed to be non-zero) that can be used
+ *  to cancel the callback and prevent it from being run.
+ */
+unsigned int
+meta_later_add (MetaLaterType  when,
+                GSourceFunc    func,
+                gpointer       data,
+                GDestroyNotify notify)
+{
+  return meta_laters_add (&_laters, when, func, data, notify);
+}
+
+static void
+meta_laters_remove (MetaLaters   *laters,
+                    unsigned int  later_id)
+{
+  unsigned int i;
+
+  for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
+    {
+      if (remove_later_from_list (later_id, &laters->laters[i]))
+        return;
+    }
+}
+
+/**
+ * meta_later_remove:
+ * @later_id: the integer ID returned from meta_later_add()
+ *
+ * Removes a callback added with meta_later_add()
+ */
+void
+meta_later_remove (unsigned int later_id)
+{
+  meta_laters_remove (&_laters, later_id);
+}
diff --git a/src/core/util.c b/src/core/util.c
index 3854b3737..f01ef39d7 100644
--- a/src/core/util.c
+++ b/src/core/util.c
@@ -50,9 +50,6 @@ meta_topic_real_valist (MetaDebugTopic topic,
                         va_list        args) G_GNUC_PRINTF(2, 0);
 #endif
 
-static gboolean
-meta_later_remove_from_list (guint later_id, GSList **laters_list);
-
 static gint verbose_topics = 0;
 static gboolean is_debugging = FALSE;
 static gboolean replace_current = FALSE;
@@ -715,288 +712,6 @@ meta_show_dialog (const char *type,
   return child_pid;
 }
 
-/***************************************************************************
- * Later functions: like idles but integrated with the Clutter repaint loop
- ***************************************************************************/
-
-static guint last_later_id = 0;
-
-typedef struct
-{
-  guint id;
-  guint ref_count;
-  MetaLaterType when;
-  GSourceFunc func;
-  gpointer data;
-  GDestroyNotify notify;
-  int source;
-  gboolean run_once;
-} MetaLater;
-
-static GSList *laters[] = {
-  NULL, /* META_LATER_RESIZE */
-  NULL, /* META_LATER_CALC_SHOWING */
-  NULL, /* META_LATER_CHECK_FULLSCREEN */
-  NULL, /* META_LATER_SYNC_STACK */
-  NULL, /* META_LATER_BEFORE_REDRAW */
-  NULL, /* META_LATER_IDLE */
-};
-/* This is a dummy timeline used to get the Clutter master clock running */
-static ClutterTimeline *later_timeline;
-static guint later_repaint_func = 0;
-
-static void ensure_later_repaint_func (void);
-
-static void
-unref_later (MetaLater *later)
-{
-  if (--later->ref_count == 0)
-    {
-      if (later->notify)
-        {
-          later->notify (later->data);
-          later->notify = NULL;
-        }
-      g_slice_free (MetaLater, later);
-    }
-}
-
-static void
-destroy_later (MetaLater *later)
-{
-  g_clear_handle_id (&later->source, g_source_remove);
-  later->func = NULL;
-  unref_later (later);
-}
-
-#ifdef COGL_HAS_TRACING
-static const char *
-later_type_to_string (MetaLaterType when)
-{
-  switch (when)
-    {
-    case META_LATER_RESIZE:
-      return "Later (resize)";
-    case META_LATER_CALC_SHOWING:
-      return "Later (calc-showing)";
-    case META_LATER_CHECK_FULLSCREEN:
-      return "Later (check-fullscreen)";
-    case META_LATER_SYNC_STACK:
-      return "Later (sync-stack)";
-    case META_LATER_BEFORE_REDRAW:
-      return "Later (before-redraw)";
-    case META_LATER_IDLE:
-      return "Later (idle)";
-    }
-
-  return "unknown";
-}
-#endif
-
-static gboolean
-call_later_func (MetaLater *later)
-{
-  COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when));
-  return later->func (later->data);
-}
-
-static void
-run_repaint_laters (GSList **laters_list)
-{
-  GSList *laters_copy;
-  GSList *l;
-
-  laters_copy = NULL;
-  for (l = *laters_list; l; l = l->next)
-    {
-      MetaLater *later = l->data;
-      if (later->source == 0 ||
-          (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
-        {
-          later->ref_count++;
-          laters_copy = g_slist_prepend (laters_copy, later);
-        }
-    }
-  laters_copy = g_slist_reverse (laters_copy);
-
-  for (l = laters_copy; l; l = l->next)
-    {
-      MetaLater *later = l->data;
-
-      if (!later->func || !call_later_func (later))
-        meta_later_remove_from_list (later->id, laters_list);
-      unref_later (later);
-    }
-
-  g_slist_free (laters_copy);
-}
-
-static gboolean
-run_all_repaint_laters (gpointer data)
-{
-  guint i;
-  GSList *l;
-  gboolean keep_timeline_running = FALSE;
-
-  for (i = 0; i < G_N_ELEMENTS (laters); i++)
-    {
-      run_repaint_laters (&laters[i]);
-    }
-
-  for (i = 0; i < G_N_ELEMENTS (laters); i++)
-    {
-      for (l = laters[i]; l; l = l->next)
-        {
-          MetaLater *later = l->data;
-
-          if (later->source == 0)
-            keep_timeline_running = TRUE;
-        }
-    }
-
-  if (!keep_timeline_running)
-    clutter_timeline_stop (later_timeline);
-
-  /* Just keep the repaint func around - it's cheap if the lists are empty */
-  return TRUE;
-}
-
-static void
-ensure_later_repaint_func (void)
-{
-  if (!later_timeline)
-    later_timeline = clutter_timeline_new (G_MAXUINT);
-
-  if (later_repaint_func == 0)
-    later_repaint_func = clutter_threads_add_repaint_func (run_all_repaint_laters,
-                                                           NULL, NULL);
-
-  /* Make sure the repaint function gets run */
-  clutter_timeline_start (later_timeline);
-}
-
-static gboolean
-call_idle_later (gpointer data)
-{
-  MetaLater *later = data;
-
-  if (!later->func (later->data))
-    {
-      meta_later_remove (later->id);
-      return FALSE;
-    }
-  else
-    {
-      later->run_once = TRUE;
-      return TRUE;
-    }
-}
-
-/**
- * meta_later_add:
- * @when:     enumeration value determining the phase at which to run the callback
- * @func:     callback to run later
- * @data:     data to pass to the callback
- * @notify:   function to call to destroy @data when it is no longer in use, or %NULL
- *
- * Sets up a callback  to be called at some later time. @when determines the
- * particular later occasion at which it is called. This is much like g_idle_add(),
- * except that the functions interact properly with clutter event handling.
- * If a "later" function is added from a clutter event handler, and is supposed
- * to be run before the stage is redrawn, it will be run before that redraw
- * of the stage, not the next one.
- *
- * Return value: an integer ID (guaranteed to be non-zero) that can be used
- *  to cancel the callback and prevent it from being run.
- */
-guint
-meta_later_add (MetaLaterType  when,
-                GSourceFunc    func,
-                gpointer       data,
-                GDestroyNotify notify)
-{
-  MetaLater *later = g_slice_new0 (MetaLater);
-
-  later->id = ++last_later_id;
-  later->ref_count = 1;
-  later->when = when;
-  later->func = func;
-  later->data = data;
-  later->notify = notify;
-
-  laters[when] = g_slist_prepend (laters[when], later);
-
-  switch (when)
-    {
-    case META_LATER_RESIZE:
-      /* We add this one two ways - as a high-priority idle and as a
-       * repaint func. If we are in a clutter event callback, the repaint
-       * handler will get hit first, and we'll take care of this function
-       * there so it gets called before the stage is redrawn, even if
-       * we haven't gotten back to the main loop. Otherwise, the idle
-       * handler will get hit first and we want to call this function
-       * there so it will happen before GTK+ repaints.
-       */
-      later->source = g_idle_add_full (META_PRIORITY_RESIZE, call_idle_later, later, NULL);
-      g_source_set_name_by_id (later->source, "[mutter] call_idle_later");
-      ensure_later_repaint_func ();
-      break;
-    case META_LATER_CALC_SHOWING:
-    case META_LATER_CHECK_FULLSCREEN:
-    case META_LATER_SYNC_STACK:
-    case META_LATER_BEFORE_REDRAW:
-      ensure_later_repaint_func ();
-      break;
-    case META_LATER_IDLE:
-      later->source = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, call_idle_later, later, NULL);
-      g_source_set_name_by_id (later->source, "[mutter] call_idle_later");
-      break;
-    }
-
-  return later->id;
-}
-
-static gboolean
-meta_later_remove_from_list (guint later_id, GSList **laters_list)
-{
-  GSList *l;
-
-  for (l = *laters_list; l; l = l->next)
-    {
-      MetaLater *later = l->data;
-
-      if (later->id == later_id)
-        {
-          *laters_list = g_slist_delete_link (*laters_list, l);
-          /* If this was a "repaint func" later, we just let the
-           * repaint func run and get removed
-           */
-          destroy_later (later);
-          return TRUE;
-        }
-    }
-
-  return FALSE;
-}
-
-/**
- * meta_later_remove:
- * @later_id: the integer ID returned from meta_later_add()
- *
- * Removes a callback added with meta_later_add()
- */
-void
-meta_later_remove (guint later_id)
-{
-  guint i;
-
-  for (i = 0; i < G_N_ELEMENTS (laters); i++)
-    {
-      if (meta_later_remove_from_list (later_id, &laters[i]))
-        return;
-    }
-}
-
 MetaLocaleDirection
 meta_get_locale_direction (void)
 {
diff --git a/src/meson.build b/src/meson.build
index bb1b48b44..c5ff7966d 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -300,6 +300,7 @@ mutter_sources = [
   'compositor/meta-dnd.c',
   'compositor/meta-feedback-actor.c',
   'compositor/meta-feedback-actor-private.h',
+  'compositor/meta-later.c',
   'compositor/meta-module.c',
   'compositor/meta-module.h',
   'compositor/meta-plugin.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]