diff --git a/clutter/clutter-enums.h b/clutter/clutter-enums.h index 40bdb6aac..0588780bb 100644 --- a/clutter/clutter-enums.h +++ b/clutter/clutter-enums.h @@ -1094,6 +1094,25 @@ typedef enum { CLUTTER_ACTOR_ALIGN_END } ClutterActorAlign; +/** + * ClutterRepaintFlags: + * @CLUTTER_REPAINT_FLAGS_PRE_PAINT: Run the repaint function prior to + * painting the stages + * @CLUTTER_REPAINT_FLAGS_POST_PAINT: Run the repaint function after + * painting the stages + * @CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD: Ensure that a new frame + * is queued after adding the repaint function + * + * Flags to pass to clutter_threads_add_repaint_func_full(). + * + * Since: 1.10 + */ +typedef enum { + CLUTTER_REPAINT_FLAGS_PRE_PAINT = 1 << 0, + CLUTTER_REPAINT_FLAGS_POST_PAINT = 1 << 1, + CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD = 1 << 2 +} ClutterRepaintFlags; + G_END_DECLS #endif /* __CLUTTER_ENUMS_H__ */ diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 860fa6f6d..4ffbab109 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -19,9 +19,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . - * - * */ + /** * SECTION:clutter-main * @short_description: Various 'global' clutter functions. @@ -3310,6 +3309,7 @@ clutter_get_font_map (void) typedef struct _ClutterRepaintFunction { guint id; + ClutterRepaintFlags flags; GSourceFunc func; gpointer data; GDestroyNotify notify; @@ -3368,21 +3368,32 @@ clutter_threads_remove_repaint_func (guint handle_id) * @notify: function to be called when removing the repaint * function, or %NULL * - * Adds a function to be called whenever Clutter is repainting a Stage. + * Adds a function to be called whenever Clutter is processing a new + * frame. + * * 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. + * that called clutter_main(), and while the Clutter lock is being held; + * the function will be called within the main loop, so it is imperative + * that it does not block, otherwise the frame time budget may be lost. * * 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. + * a frame from a video into a #ClutterTexture. By default, a repaint + * function added using this function will be invoked prior to the frame + * being processed. + * + * Adding a repaint function does not automatically ensure that a new + * frame will be queued. * * 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. * + * See also: clutter_threads_add_repaint_func_full() + * * 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(). @@ -3393,6 +3404,55 @@ guint clutter_threads_add_repaint_func (GSourceFunc func, gpointer data, GDestroyNotify notify) +{ + return clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT, + func, + data, notify); +} + +/** + * clutter_threads_add_repaint_func_full: + * @flags: flags for the repaint function + * @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 processing a new + * frame. + * + * 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; + * the function will be called within the main loop, so it is imperative + * that it does not block, otherwise the frame time budget may be lost. + * + * 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. The @flags passed to this + * function will determine the section of the frame processing that will + * result in @func being called. + * + * Adding a repaint function does not automatically ensure that a new + * frame will be queued. + * + * 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.10 + */ +guint +clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags, + GSourceFunc func, + gpointer data, + GDestroyNotify notify) { ClutterMainContext *context; ClutterRepaintFunction *repaint_func; @@ -3406,6 +3466,9 @@ clutter_threads_add_repaint_func (GSourceFunc func, repaint_func = g_slice_new (ClutterRepaintFunction); repaint_func->id = context->last_repaint_id++; + + /* mask out QUEUE_REDRAW_ON_ADD, since we're going to consume it */ + repaint_func->flags = flags & ~CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD; repaint_func->func = func; repaint_func->data = data; repaint_func->notify = notify; @@ -3415,20 +3478,27 @@ clutter_threads_add_repaint_func (GSourceFunc func, _clutter_context_unlock (); + if ((flags & CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD) != 0) + { + ClutterMasterClock *master_clock = _clutter_master_clock_get_default (); + + _clutter_master_clock_ensure_next_iteration (master_clock); + } + return repaint_func->id; } /* * _clutter_run_repaint_functions: + * @flags: only run the repaint functions matching the passed flags * * Executes the repaint functions added using the * clutter_threads_add_repaint_func() function. * - * Must be called before calling _clutter_stage_do_paint() and - * with the Clutter thread lock held. + * Must be called with the Clutter thread lock held. */ void -_clutter_run_repaint_functions (void) +_clutter_run_repaint_functions (ClutterRepaintFlags flags) { ClutterMainContext *context = _clutter_context_get_default (); ClutterRepaintFunction *repaint_func; @@ -3455,7 +3525,10 @@ _clutter_run_repaint_functions (void) g_list_free (l); - res = repaint_func->func (repaint_func->data); + if ((repaint_func->flags & flags) != 0) + res = repaint_func->func (repaint_func->data); + else + res = TRUE; if (res) reinvoke_list = g_list_prepend (reinvoke_list, repaint_func); diff --git a/clutter/clutter-main.h b/clutter/clutter-main.h index b59b572d8..1b4a6bbe6 100644 --- a/clutter/clutter-main.h +++ b/clutter/clutter-main.h @@ -122,6 +122,10 @@ guint clutter_threads_add_timeout_full (gint guint clutter_threads_add_repaint_func (GSourceFunc func, gpointer data, GDestroyNotify notify); +guint clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags, + GSourceFunc func, + gpointer data, + GDestroyNotify notify); void clutter_threads_remove_repaint_func (guint handle_id); void clutter_grab_pointer (ClutterActor *actor); diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index a48a66ecb..78aefc7d9 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -359,10 +359,10 @@ clutter_clock_dispatch (GSource *source, stages = clutter_stage_manager_list_stages (stage_manager); g_slist_foreach (stages, (GFunc) g_object_ref, NULL); - CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process); - master_clock->idle = FALSE; + CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process); + /* Process queued events */ for (l = stages; l != NULL; l = l->next) { @@ -378,7 +378,7 @@ clutter_clock_dispatch (GSource *source, _clutter_master_clock_advance (master_clock); - _clutter_run_repaint_functions (); + _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT); /* Update any stage that needs redraw/relayout after the clock * is advanced. @@ -398,6 +398,8 @@ clutter_clock_dispatch (GSource *source, stages_updated |= _clutter_stage_do_update (l->data); } + _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT); + /* The master clock goes idle if no stages were updated and falls back * to polling for timeline progressions... */ if (!stages_updated) diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index df17d6a00..916ee732e 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -232,7 +232,7 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint, const GValue *handler_return, gpointer dummy); -void _clutter_run_repaint_functions (void); +void _clutter_run_repaint_functions (ClutterRepaintFlags flags); void _clutter_constraint_update_allocation (ClutterConstraint *constraint, ClutterActor *actor, diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols index df9fa69e3..9cd12fa8c 100644 --- a/clutter/clutter.symbols +++ b/clutter/clutter.symbols @@ -1247,6 +1247,7 @@ clutter_threads_add_frame_source_full clutter_threads_add_idle clutter_threads_add_idle_full clutter_threads_add_repaint_func +clutter_threads_add_repaint_func_full clutter_threads_add_timeout clutter_threads_add_timeout_full clutter_threads_enter diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 38fc7a831..1311b8726 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -1296,6 +1296,7 @@ clutter_threads_add_timeout_full clutter_threads_add_frame_source clutter_threads_add_frame_source_full clutter_threads_add_repaint_func +clutter_threads_add_repaint_func_full clutter_threads_remove_repaint_func