From d682cdb078f281b03084e3e0d7ab40d3ea382c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 3 Mar 2020 08:46:11 +0100 Subject: [PATCH] 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(-) create mode 100644 src/compositor/meta-later.c 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 . + */ + +#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',