5e67e35ec5
As with the backend commit, this means all objects can reach the MetaContext by walking up the chain, thus can e.g. get the backend from the context, instead of the global singleton. This also is a squashed commit containing: compositor: Get backend via the context The MetaCompositor instance is owned by MetaDisplay, which is owned by MetaContext. Get the backend via that chain of ownership. dnd: Don't get backend from singleton window-actor: Don't get backend from singleton dnd: Don't get Wayland compositor via singleton background: Don't get the monitor manager from the singleton plugins: Don't get backend from singleton This applies to MetaPlugin, it's manager class, and the default plugin. feedback-actor: Pass a compositor pointer when constructing This allows getting to the display. later: Keep a pointer to the manager object This allows using the non-singleton API in idle callbacks. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2718>
381 lines
9.8 KiB
C
381 lines
9.8 KiB
C
/*
|
|
* 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 "compositor/meta-later-private.h"
|
|
|
|
#include "cogl/cogl.h"
|
|
#include "compositor/compositor-private.h"
|
|
#include "core/display-private.h"
|
|
#include "meta/meta-later.h"
|
|
|
|
typedef struct _MetaLater
|
|
{
|
|
MetaLaters *laters;
|
|
|
|
unsigned int id;
|
|
unsigned int ref_count;
|
|
MetaLaterType when;
|
|
|
|
GSourceFunc func;
|
|
gpointer user_data;
|
|
GDestroyNotify destroy_notify;
|
|
|
|
guint source_id;
|
|
gboolean run_once;
|
|
} MetaLater;
|
|
|
|
#define META_LATER_N_TYPES (META_LATER_IDLE + 1)
|
|
|
|
struct _MetaLaters
|
|
{
|
|
MetaCompositor *compositor;
|
|
|
|
unsigned int last_later_id;
|
|
|
|
GSList *laters[META_LATER_N_TYPES];
|
|
|
|
gulong before_update_handler_id;
|
|
};
|
|
|
|
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_free (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 void
|
|
on_before_update (ClutterStage *stage,
|
|
ClutterStageView *stage_view,
|
|
MetaLaters *laters)
|
|
{
|
|
unsigned int i;
|
|
GSList *l;
|
|
gboolean needs_schedule_update = 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)
|
|
needs_schedule_update = TRUE;
|
|
}
|
|
}
|
|
|
|
if (needs_schedule_update)
|
|
clutter_stage_schedule_update (stage);
|
|
}
|
|
|
|
static gboolean
|
|
invoke_later_idle (gpointer data)
|
|
{
|
|
MetaLater *later = data;
|
|
|
|
if (!later->func (later->user_data))
|
|
{
|
|
meta_laters_remove (later->laters, later->id);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
later->run_once = TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* meta_laters_add:
|
|
* @laters: a #MetaLaters
|
|
* @when: enumeration value determining the phase at which to run the callback
|
|
* @func: callback to run later
|
|
* @user_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_laters_add (MetaLaters *laters,
|
|
MetaLaterType when,
|
|
GSourceFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify notify)
|
|
{
|
|
ClutterStage *stage = meta_compositor_get_stage (laters->compositor);
|
|
MetaLater *later = g_new0 (MetaLater, 1);
|
|
|
|
later->id = ++laters->last_later_id;
|
|
later->laters = laters;
|
|
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");
|
|
clutter_stage_schedule_update (stage);
|
|
break;
|
|
case META_LATER_CALC_SHOWING:
|
|
case META_LATER_CHECK_FULLSCREEN:
|
|
case META_LATER_SYNC_STACK:
|
|
case META_LATER_BEFORE_REDRAW:
|
|
clutter_stage_schedule_update (stage);
|
|
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)
|
|
{
|
|
MetaDisplay *display = meta_get_display ();
|
|
MetaCompositor *compositor;
|
|
|
|
g_return_val_if_fail (display, 0);
|
|
g_return_val_if_fail (display->compositor, 0);
|
|
|
|
compositor = display->compositor;
|
|
return meta_laters_add (meta_compositor_get_laters (compositor),
|
|
when, func, data, notify);
|
|
}
|
|
|
|
/**
|
|
* meta_laters_remove:
|
|
* @laters: a #MetaLaters
|
|
* @later_id: the integer ID returned from meta_later_add()
|
|
*
|
|
* Removes a callback added with meta_later_add()
|
|
*/
|
|
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)
|
|
{
|
|
MetaDisplay *display = meta_get_display ();
|
|
MetaCompositor *compositor;
|
|
|
|
g_return_if_fail (display);
|
|
|
|
compositor = display->compositor;
|
|
if (!compositor)
|
|
return;
|
|
|
|
meta_laters_remove (meta_compositor_get_laters (compositor), later_id);
|
|
}
|
|
|
|
MetaLaters *
|
|
meta_laters_new (MetaCompositor *compositor)
|
|
{
|
|
ClutterStage *stage = meta_compositor_get_stage (compositor);
|
|
MetaLaters *laters;
|
|
|
|
laters = g_new0 (MetaLaters, 1);
|
|
laters->compositor = compositor;
|
|
|
|
laters->before_update_handler_id =
|
|
g_signal_connect (stage, "before-update",
|
|
G_CALLBACK (on_before_update),
|
|
laters);
|
|
|
|
return laters;
|
|
}
|
|
|
|
void
|
|
meta_laters_free (MetaLaters *laters)
|
|
{
|
|
ClutterStage *stage = meta_compositor_get_stage (laters->compositor);
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
|
|
g_slist_free_full (laters->laters[i], (GDestroyNotify) meta_later_unref);
|
|
|
|
g_clear_signal_handler (&laters->before_update_handler_id, stage);
|
|
g_free (laters);
|
|
}
|