mirror of
https://github.com/brl/mutter.git
synced 2024-11-29 19:40:43 -05:00
Add repaint functions
Sometimes it is necessary for third party code to have a function called during the redraw process, so that you can update the scenegraph before it is painted.
This commit is contained in:
parent
5cde6a598f
commit
87465355d3
@ -2816,3 +2816,162 @@ clutter_get_font_map (void)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct _ClutterRepaintFunction
|
||||
{
|
||||
guint id;
|
||||
GSourceFunc func;
|
||||
gpointer data;
|
||||
GDestroyNotify notify;
|
||||
} ClutterRepaintFunction;
|
||||
|
||||
/**
|
||||
* clutter_threads_remove_repaint_func:
|
||||
* @handle_id: an unsigned integer greater than zero
|
||||
*
|
||||
* Removes the repaint function with @handle_id as its id
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void
|
||||
clutter_threads_remove_repaint_func (guint handle_id)
|
||||
{
|
||||
ClutterRepaintFunction *repaint_func;
|
||||
ClutterMainContext *context;
|
||||
GList *l;
|
||||
|
||||
g_return_if_fail (handle_id > 0);
|
||||
|
||||
context = CLUTTER_CONTEXT ();
|
||||
l = context->repaint_funcs;
|
||||
while (l != NULL)
|
||||
{
|
||||
repaint_func = l->data;
|
||||
|
||||
if (repaint_func->id == handle_id)
|
||||
{
|
||||
context->repaint_funcs =
|
||||
g_list_remove_link (context->repaint_funcs, l);
|
||||
|
||||
g_list_free (l);
|
||||
|
||||
if (repaint_func->notify)
|
||||
repaint_func->notify (repaint_func->data);
|
||||
|
||||
g_slice_free (ClutterRepaintFunction, repaint_func);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
l = l->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_threads_add_repaint_func:
|
||||
* @func: the function to be called within the paint cycle
|
||||
* @data: data to be passed to the function, or %NULL
|
||||
* @notify: function to be called when removing the repaint
|
||||
* function, or %NULL
|
||||
*
|
||||
* Adds a function to be called whenever Clutter is repainting a Stage.
|
||||
* If the function returns %FALSE it is automatically removed from the
|
||||
* list of repaint functions and will not be called again.
|
||||
*
|
||||
* This function is guaranteed to be called from within the same thread
|
||||
* that called clutter_main(), and while the Clutter lock is being held.
|
||||
*
|
||||
* A repaint function is useful to ensure that an update of the scenegraph
|
||||
* is performed before the scenegraph is repainted; for instance, uploading
|
||||
* a frame from a video into a #ClutterTexture.
|
||||
*
|
||||
* When the repaint function is removed (either because it returned %FALSE
|
||||
* or because clutter_threads_remove_repaint_func() has been called) the
|
||||
* @notify function will be called, if any is set.
|
||||
*
|
||||
* Return value: the ID (greater than 0) of the repaint function. You
|
||||
* can use the returned integer to remove the repaint function by
|
||||
* calling clutter_threads_remove_repaint_func().
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
guint
|
||||
clutter_threads_add_repaint_func (GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
static guint repaint_id = 1;
|
||||
ClutterMainContext *context;
|
||||
ClutterRepaintFunction *repaint_func;
|
||||
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
context = CLUTTER_CONTEXT ();
|
||||
|
||||
/* XXX lock the context */
|
||||
|
||||
repaint_func = g_slice_new (ClutterRepaintFunction);
|
||||
|
||||
repaint_func->id = repaint_id++;
|
||||
repaint_func->func = func;
|
||||
repaint_func->data = data;
|
||||
repaint_func->notify = notify;
|
||||
|
||||
context->repaint_funcs = g_list_prepend (context->repaint_funcs,
|
||||
repaint_func);
|
||||
|
||||
/* XXX unlock the context */
|
||||
|
||||
return repaint_func->id;
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_run_repaint_functions:
|
||||
*
|
||||
* Executes the repaint functions added using the
|
||||
* clutter_threads_add_repaint_func() function.
|
||||
*
|
||||
* Must be called before calling clutter_redraw() and
|
||||
* with the Clutter thread lock held.
|
||||
*/
|
||||
void
|
||||
_clutter_run_repaint_functions (void)
|
||||
{
|
||||
ClutterMainContext *context = CLUTTER_CONTEXT ();
|
||||
ClutterRepaintFunction *repaint_func;
|
||||
GList *reinvoke_list, *l;
|
||||
|
||||
if (context->repaint_funcs == NULL)
|
||||
return;
|
||||
|
||||
reinvoke_list = NULL;
|
||||
|
||||
/* consume the whole list while we execute the functions */
|
||||
while (context->repaint_funcs)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
|
||||
repaint_func = context->repaint_funcs->data;
|
||||
|
||||
l = context->repaint_funcs;
|
||||
context->repaint_funcs =
|
||||
g_list_remove_link (context->repaint_funcs, context->repaint_funcs);
|
||||
|
||||
g_list_free (l);
|
||||
|
||||
res = repaint_func->func (repaint_func->data);
|
||||
|
||||
if (res)
|
||||
reinvoke_list = g_list_prepend (reinvoke_list, repaint_func);
|
||||
else
|
||||
{
|
||||
if (repaint_func->notify)
|
||||
repaint_func->notify (repaint_func->data);
|
||||
|
||||
g_slice_free (ClutterRepaintFunction, repaint_func);
|
||||
}
|
||||
}
|
||||
|
||||
if (reinvoke_list)
|
||||
context->repaint_funcs = reinvoke_list;
|
||||
}
|
||||
|
@ -109,34 +109,38 @@ gboolean clutter_get_show_fps (void);
|
||||
gulong clutter_get_timestamp (void);
|
||||
|
||||
/* Threading functions */
|
||||
void clutter_threads_init (void);
|
||||
void clutter_threads_enter (void);
|
||||
void clutter_threads_leave (void);
|
||||
void clutter_threads_set_lock_functions (GCallback enter_fn,
|
||||
GCallback leave_fn);
|
||||
guint clutter_threads_add_idle (GSourceFunc func,
|
||||
gpointer data);
|
||||
guint clutter_threads_add_idle_full (gint priority,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
guint clutter_threads_add_timeout (guint interval,
|
||||
GSourceFunc func,
|
||||
gpointer data);
|
||||
guint clutter_threads_add_timeout_full (gint priority,
|
||||
guint interval,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
guint clutter_threads_add_frame_source (guint fps,
|
||||
GSourceFunc func,
|
||||
gpointer data);
|
||||
guint clutter_threads_add_frame_source_full
|
||||
(gint priority,
|
||||
guint fps,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
void clutter_threads_init (void);
|
||||
void clutter_threads_enter (void);
|
||||
void clutter_threads_leave (void);
|
||||
void clutter_threads_set_lock_functions (GCallback enter_fn,
|
||||
GCallback leave_fn);
|
||||
guint clutter_threads_add_idle (GSourceFunc func,
|
||||
gpointer data);
|
||||
guint clutter_threads_add_idle_full (gint priority,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
guint clutter_threads_add_timeout (guint interval,
|
||||
GSourceFunc func,
|
||||
gpointer data);
|
||||
guint clutter_threads_add_timeout_full (gint priority,
|
||||
guint interval,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
guint clutter_threads_add_frame_source (guint fps,
|
||||
GSourceFunc func,
|
||||
gpointer data);
|
||||
guint clutter_threads_add_frame_source_full (gint priority,
|
||||
guint fps,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
guint clutter_threads_add_repaint_func (GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
void clutter_threads_remove_repaint_func (guint handler_id);
|
||||
|
||||
void clutter_set_motion_events_enabled (gboolean enable);
|
||||
gboolean clutter_get_motion_events_enabled (void);
|
||||
@ -158,7 +162,7 @@ void clutter_clear_glyph_cache (void);
|
||||
void clutter_set_font_flags (ClutterFontFlags flags);
|
||||
ClutterFontFlags clutter_get_font_flags (void);
|
||||
|
||||
ClutterInputDevice* clutter_get_input_device_for_id (gint id);
|
||||
ClutterInputDevice *clutter_get_input_device_for_id (gint id);
|
||||
|
||||
void clutter_grab_pointer_for_device (ClutterActor *actor,
|
||||
gint id);
|
||||
|
@ -132,6 +132,8 @@ struct _ClutterMainContext
|
||||
|
||||
ClutterMasterClock *master_clock;
|
||||
gulong redraw_count;
|
||||
|
||||
GList *repaint_funcs;
|
||||
};
|
||||
|
||||
#define CLUTTER_CONTEXT() (clutter_context_get_default ())
|
||||
@ -238,6 +240,8 @@ void _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
|
||||
void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
|
||||
gboolean enable);
|
||||
|
||||
void _clutter_run_repaint_functions (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _HAVE_CLUTTER_PRIVATE_H */
|
||||
|
@ -403,6 +403,12 @@ redraw_update_idle (gpointer user_data)
|
||||
master_clock = _clutter_master_clock_get_default ();
|
||||
_clutter_master_clock_advance (master_clock);
|
||||
|
||||
/* run the (eventual) repaint functions; since those might end up queuing
|
||||
* a relayout or a redraw we need to execute them before maybe_relayout()
|
||||
*/
|
||||
CLUTTER_NOTE (PAINT, "Repaint functions");
|
||||
_clutter_run_repaint_functions ();
|
||||
|
||||
/* clutter_redraw() will also call maybe_relayout(), but since a relayout
|
||||
* can queue a redraw, we want to do the relayout before we clear the
|
||||
* update_idle to avoid painting the stage twice. Calling maybe_relayout()
|
||||
@ -457,8 +463,7 @@ static void
|
||||
set_offscreen_while_unrealized (ClutterActor *actor,
|
||||
void *data)
|
||||
{
|
||||
CLUTTER_STAGE (actor)->priv->is_offscreen =
|
||||
GPOINTER_TO_INT (data);
|
||||
CLUTTER_STAGE (actor)->priv->is_offscreen = GPOINTER_TO_INT (data);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user