Skip to content

Commit fcd14d3

Browse files
committed
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. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=d682cdb078f281b03084e3e0d7ab40d3ea382c1f
1 parent a537e38 commit fcd14d3

File tree

3 files changed

+322
-285
lines changed

3 files changed

+322
-285
lines changed

src/compositor/meta-later.c

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
/*
2+
* Copyright (C) 2001 Havoc Pennington
3+
* Copyright (C) 2005 Elijah Newren
4+
* Copyright (C) 2020 Red Hat Inc.
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License as
8+
* published by the Free Software Foundation; either version 2 of the
9+
* License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful, but
12+
* WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "config.h"
21+
22+
#include "cogl/cogl.h"
23+
#include "meta/util.h"
24+
25+
typedef struct _MetaLater
26+
{
27+
unsigned int id;
28+
unsigned int ref_count;
29+
MetaLaterType when;
30+
31+
GSourceFunc func;
32+
gpointer user_data;
33+
GDestroyNotify destroy_notify;
34+
35+
guint source_id;
36+
gboolean run_once;
37+
} MetaLater;
38+
39+
typedef struct _MetaLaters MetaLaters;
40+
41+
#define META_LATER_N_TYPES (META_LATER_IDLE + 1)
42+
43+
struct _MetaLaters
44+
{
45+
unsigned int last_later_id;
46+
47+
GSList *laters[META_LATER_N_TYPES];
48+
49+
ClutterTimeline *timeline;
50+
guint repaint_func;
51+
};
52+
53+
static MetaLaters _laters;
54+
55+
static MetaLater *
56+
meta_later_ref (MetaLater *later)
57+
{
58+
later->ref_count++;
59+
return later;
60+
}
61+
62+
static void
63+
meta_later_unref (MetaLater *later)
64+
{
65+
if (--later->ref_count == 0)
66+
{
67+
if (later->destroy_notify)
68+
{
69+
later->destroy_notify (later->user_data);
70+
later->destroy_notify = NULL;
71+
}
72+
73+
g_slice_free (MetaLater, later);
74+
}
75+
}
76+
77+
static void
78+
meta_later_destroy (MetaLater *later)
79+
{
80+
g_clear_handle_id (&later->source_id, g_source_remove);
81+
later->func = NULL;
82+
meta_later_unref (later);
83+
}
84+
85+
#ifdef COGL_HAS_TRACING
86+
static const char *
87+
later_type_to_string (MetaLaterType when)
88+
{
89+
switch (when)
90+
{
91+
case META_LATER_RESIZE:
92+
return "Later (resize)";
93+
case META_LATER_CALC_SHOWING:
94+
return "Later (calc-showing)";
95+
case META_LATER_CHECK_FULLSCREEN:
96+
return "Later (check-fullscreen)";
97+
case META_LATER_SYNC_STACK:
98+
return "Later (sync-stack)";
99+
case META_LATER_BEFORE_REDRAW:
100+
return "Later (before-redraw)";
101+
case META_LATER_IDLE:
102+
return "Later (idle)";
103+
}
104+
105+
return "unknown";
106+
}
107+
#endif
108+
109+
static gboolean
110+
meta_later_invoke (MetaLater *later)
111+
{
112+
COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when));
113+
return later->func (later->user_data);
114+
}
115+
116+
static gboolean
117+
remove_later_from_list (unsigned int later_id,
118+
GSList **laters_list)
119+
{
120+
GSList *l;
121+
122+
for (l = *laters_list; l; l = l->next)
123+
{
124+
MetaLater *later = l->data;
125+
126+
if (later->id == later_id)
127+
{
128+
*laters_list = g_slist_delete_link (*laters_list, l);
129+
meta_later_destroy (later);
130+
return TRUE;
131+
}
132+
}
133+
134+
return FALSE;
135+
}
136+
137+
static void
138+
run_repaint_laters (GSList **laters_list)
139+
{
140+
g_autoptr (GSList) laters_copy = NULL;
141+
GSList *l;
142+
143+
for (l = *laters_list; l; l = l->next)
144+
{
145+
MetaLater *later = l->data;
146+
147+
if (!later->source_id ||
148+
(later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
149+
laters_copy = g_slist_prepend (laters_copy, meta_later_ref (later));
150+
}
151+
laters_copy = g_slist_reverse (laters_copy);
152+
153+
for (l = laters_copy; l; l = l->next)
154+
{
155+
MetaLater *later = l->data;
156+
157+
if (!later->func)
158+
remove_later_from_list (later->id, laters_list);
159+
else if (!meta_later_invoke (later))
160+
remove_later_from_list (later->id, laters_list);
161+
162+
meta_later_unref (later);
163+
}
164+
}
165+
166+
static gboolean
167+
run_all_repaint_laters (gpointer data)
168+
{
169+
MetaLaters *laters = data;
170+
unsigned int i;
171+
GSList *l;
172+
gboolean keep_timeline_running = FALSE;
173+
174+
for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
175+
run_repaint_laters (&laters->laters[i]);
176+
177+
for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
178+
{
179+
for (l = laters->laters[i]; l; l = l->next)
180+
{
181+
MetaLater *later = l->data;
182+
183+
if (!later->source_id)
184+
keep_timeline_running = TRUE;
185+
}
186+
}
187+
188+
if (!keep_timeline_running)
189+
clutter_timeline_stop (laters->timeline);
190+
191+
return TRUE;
192+
}
193+
194+
static void
195+
ensure_later_repaint_func (MetaLaters *laters)
196+
{
197+
if (!laters->timeline)
198+
laters->timeline = clutter_timeline_new (G_MAXUINT);
199+
200+
if (laters->repaint_func == 0)
201+
{
202+
laters->repaint_func =
203+
clutter_threads_add_repaint_func (run_all_repaint_laters,
204+
laters, NULL);
205+
}
206+
207+
/* Make sure the repaint function gets run */
208+
clutter_timeline_start (laters->timeline);
209+
}
210+
211+
static gboolean
212+
invoke_later_idle (gpointer data)
213+
{
214+
MetaLater *later = data;
215+
216+
if (!later->func (later->user_data))
217+
{
218+
meta_later_remove (later->id);
219+
return FALSE;
220+
}
221+
else
222+
{
223+
later->run_once = TRUE;
224+
return TRUE;
225+
}
226+
}
227+
228+
static unsigned int
229+
meta_laters_add (MetaLaters *laters,
230+
MetaLaterType when,
231+
GSourceFunc func,
232+
gpointer user_data,
233+
GDestroyNotify notify)
234+
{
235+
MetaLater *later = g_slice_new0 (MetaLater);
236+
237+
later->id = ++laters->last_later_id;
238+
later->ref_count = 1;
239+
later->when = when;
240+
later->func = func;
241+
later->user_data = user_data;
242+
later->destroy_notify = notify;
243+
244+
laters->laters[when] = g_slist_prepend (laters->laters[when], later);
245+
246+
switch (when)
247+
{
248+
case META_LATER_RESIZE:
249+
later->source_id = g_idle_add_full (META_PRIORITY_RESIZE,
250+
invoke_later_idle,
251+
later, NULL);
252+
g_source_set_name_by_id (later->source_id, "[muffin] invoke_later_idle");
253+
ensure_later_repaint_func (laters);
254+
break;
255+
case META_LATER_CALC_SHOWING:
256+
case META_LATER_CHECK_FULLSCREEN:
257+
case META_LATER_SYNC_STACK:
258+
case META_LATER_BEFORE_REDRAW:
259+
ensure_later_repaint_func (laters);
260+
break;
261+
case META_LATER_IDLE:
262+
later->source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
263+
invoke_later_idle,
264+
later, NULL);
265+
g_source_set_name_by_id (later->source_id, "[muffin] invoke_later_idle");
266+
break;
267+
}
268+
269+
return later->id;
270+
}
271+
272+
/**
273+
* meta_later_add:
274+
* @when: enumeration value determining the phase at which to run the callback
275+
* @func: callback to run later
276+
* @data: data to pass to the callback
277+
* @notify: function to call to destroy @data when it is no longer in use, or %NULL
278+
*
279+
* Sets up a callback to be called at some later time. @when determines the
280+
* particular later occasion at which it is called. This is much like g_idle_add(),
281+
* except that the functions interact properly with clutter event handling.
282+
* If a "later" function is added from a clutter event handler, and is supposed
283+
* to be run before the stage is redrawn, it will be run before that redraw
284+
* of the stage, not the next one.
285+
*
286+
* Return value: an integer ID (guaranteed to be non-zero) that can be used
287+
* to cancel the callback and prevent it from being run.
288+
*/
289+
unsigned int
290+
meta_later_add (MetaLaterType when,
291+
GSourceFunc func,
292+
gpointer data,
293+
GDestroyNotify notify)
294+
{
295+
return meta_laters_add (&_laters, when, func, data, notify);
296+
}
297+
298+
static void
299+
meta_laters_remove (MetaLaters *laters,
300+
unsigned int later_id)
301+
{
302+
unsigned int i;
303+
304+
for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
305+
{
306+
if (remove_later_from_list (later_id, &laters->laters[i]))
307+
return;
308+
}
309+
}
310+
311+
/**
312+
* meta_later_remove:
313+
* @later_id: the integer ID returned from meta_later_add()
314+
*
315+
* Removes a callback added with meta_later_add()
316+
*/
317+
void
318+
meta_later_remove (unsigned int later_id)
319+
{
320+
meta_laters_remove (&_laters, later_id);
321+
}

0 commit comments

Comments
 (0)