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
This commit is contained in:
parent
ff7a42b8bc
commit
d682cdb078
321
src/compositor/meta-later.c
Normal file
321
src/compositor/meta-later.c
Normal file
@ -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);
|
||||
}
|
285
src/core/util.c
285
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)
|
||||
{
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user