From 179d5ba6a6c0806ca0ac36318c01b9a91c65462b Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Thu, 17 Oct 2019 17:01:25 +0200 Subject: [PATCH] clutter: Split pick and paint Add the corresponding clutter_actor_pick() and clutter_actor_continue_pick() as public APIs, and use them in pick overrides and ClutterEffect. https://gitlab.gnome.org/GNOME/mutter/merge_requests/865 --- clutter/clutter/clutter-actor.c | 145 +++++++++++++++++++++++++++- clutter/clutter/clutter-actor.h | 4 + clutter/clutter/clutter-effect.c | 2 +- clutter/clutter/clutter-private.h | 4 +- src/compositor/meta-surface-actor.c | 2 +- 5 files changed, 153 insertions(+), 4 deletions(-) diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 62a28e945..b6949aff1 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -2373,7 +2373,7 @@ clutter_actor_real_pick (ClutterActor *self) for (iter = self->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) - clutter_actor_paint (iter); + clutter_actor_pick (iter); } } @@ -4215,6 +4215,149 @@ clutter_actor_continue_paint (ClutterActor *self) } } +/** + * clutter_actor_pick: + * @actor: A #ClutterActor + * + * Asks @actor to perform a pick. + */ +void +clutter_actor_pick (ClutterActor *actor) +{ + ClutterActorPrivate *priv; + ClutterActorBox clip; + gboolean clip_set = FALSE; + + if (CLUTTER_ACTOR_IN_DESTRUCTION (actor)) + return; + + priv = actor->priv; + + /* if we aren't paintable (not in a toplevel with all + * parents paintable) then do nothing. + */ + if (!CLUTTER_ACTOR_IS_MAPPED (actor)) + return; + + clutter_actor_ensure_resource_scale (actor); + + /* mark that we are in the paint process */ + CLUTTER_SET_PRIVATE_FLAGS (actor, CLUTTER_IN_PICK); + + cogl_push_matrix (); + + if (priv->enable_model_view_transform) + { + CoglMatrix matrix; + + cogl_get_modelview_matrix (&matrix); + _clutter_actor_apply_modelview_transform (actor, &matrix); + cogl_set_modelview_matrix (&matrix); + } + + if (priv->has_clip) + { + clip.x1 = priv->clip.origin.x; + clip.y1 = priv->clip.origin.y; + clip.x2 = priv->clip.origin.x + priv->clip.size.width; + clip.y2 = priv->clip.origin.y + priv->clip.size.height; + clip_set = TRUE; + } + else if (priv->clip_to_allocation) + { + clip.x1 = 0.f; + clip.y1 = 0.f; + clip.x2 = priv->allocation.x2 - priv->allocation.x1; + clip.y2 = priv->allocation.y2 - priv->allocation.y1; + clip_set = TRUE; + } + + if (clip_set) + clip_set = _clutter_actor_push_pick_clip (actor, &clip); + + priv->next_effect_to_paint = NULL; + if (priv->effects) + { + priv->next_effect_to_paint = + _clutter_meta_group_peek_metas (priv->effects); + } + + clutter_actor_continue_pick (actor); + + if (clip_set) + _clutter_actor_pop_pick_clip (actor); + + cogl_pop_matrix (); + + /* paint sequence complete */ + CLUTTER_UNSET_PRIVATE_FLAGS (actor, CLUTTER_IN_PICK); +} + +/** + * clutter_actor_continue_pick: + * @actor: A #ClutterActor + * + * Run the next stage of the pick sequence. This function should only + * be called within the implementation of the ‘pick’ virtual of a + * #ClutterEffect. It will cause the run method of the next effect to + * be applied, or it will pick the actual actor if the current effect + * is the last effect in the chain. + */ +void +clutter_actor_continue_pick (ClutterActor *actor) +{ + ClutterActorPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); + + g_return_if_fail (CLUTTER_ACTOR_IN_PICK (actor)); + + priv = actor->priv; + + /* Skip any effects that are disabled */ + while (priv->next_effect_to_paint && + !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data)) + priv->next_effect_to_paint = priv->next_effect_to_paint->next; + + /* If this has come from the last effect then we'll just pick the + * actual actor. + */ + if (priv->next_effect_to_paint == NULL) + { + /* The actor will log a silhouette of itself to the stage pick log. + * + * XXX:2.0 - Call the pick() virtual directly + */ + if (g_signal_has_handler_pending (actor, actor_signals[PICK], + 0, TRUE)) + g_signal_emit (actor, actor_signals[PICK], 0); + else + CLUTTER_ACTOR_GET_CLASS (actor)->pick (actor); + } + else + { + ClutterEffect *old_current_effect; + ClutterEffectPaintFlags run_flags = 0; + + /* Cache the current effect so that we can put it back before + * returning. + */ + old_current_effect = priv->current_effect; + + priv->current_effect = priv->next_effect_to_paint->data; + priv->next_effect_to_paint = priv->next_effect_to_paint->next; + + /* We can't determine when an actor has been modified since + * its last pick so lets just assume it has always been + * modified. + */ + run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY; + _clutter_effect_pick (priv->current_effect, run_flags); + + priv->current_effect = old_current_effect; + } +} + static void _clutter_actor_stop_transitions (ClutterActor *self) { diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h index d7382c776..efe919ec8 100644 --- a/clutter/clutter/clutter-actor.h +++ b/clutter/clutter/clutter-actor.h @@ -353,6 +353,10 @@ void clutter_actor_paint CLUTTER_EXPORT void clutter_actor_continue_paint (ClutterActor *self); CLUTTER_EXPORT +void clutter_actor_pick (ClutterActor *actor); +CLUTTER_EXPORT +void clutter_actor_continue_pick (ClutterActor *actor); +CLUTTER_EXPORT void clutter_actor_queue_redraw (ClutterActor *self); CLUTTER_EXPORT void clutter_actor_queue_redraw_with_clip (ClutterActor *self, diff --git a/clutter/clutter/clutter-effect.c b/clutter/clutter/clutter-effect.c index 47c11a53a..5a4c7aa87 100644 --- a/clutter/clutter/clutter-effect.c +++ b/clutter/clutter/clutter-effect.c @@ -223,7 +223,7 @@ clutter_effect_real_pick (ClutterEffect *effect, ClutterActor *actor; actor = clutter_actor_meta_get_actor (actor_meta); - clutter_actor_continue_paint (actor); + clutter_actor_continue_pick (actor); } static void diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h index 28c56c0d0..94575f06b 100644 --- a/clutter/clutter/clutter-private.h +++ b/clutter/clutter/clutter-private.h @@ -67,6 +67,7 @@ typedef struct _ClutterVertex4 ClutterVertex4; #define CLUTTER_ACTOR_IN_DESTRUCTION(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_DESTRUCTION) != FALSE) #define CLUTTER_ACTOR_IN_REPARENT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_REPARENT) != FALSE) #define CLUTTER_ACTOR_IN_PAINT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PAINT) != FALSE) +#define CLUTTER_ACTOR_IN_PICK(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PICK) != FALSE) #define CLUTTER_ACTOR_IN_RELAYOUT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_RELAYOUT) != FALSE) #define CLUTTER_ACTOR_IN_PREF_WIDTH(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PREF_WIDTH) != FALSE) #define CLUTTER_ACTOR_IN_PREF_HEIGHT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PREF_HEIGHT) != FALSE) @@ -104,9 +105,10 @@ typedef enum /* Used to avoid recursion */ CLUTTER_IN_PAINT = 1 << 5, + CLUTTER_IN_PICK = 1 << 6, /* Used to avoid recursion */ - CLUTTER_IN_RELAYOUT = 1 << 6, + CLUTTER_IN_RELAYOUT = 1 << 7, } ClutterPrivateFlags; /* diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c index 19e775dc9..5046a70fa 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -168,7 +168,7 @@ meta_surface_actor_pick (ClutterActor *actor) clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) - clutter_actor_paint (child); + clutter_actor_pick (child); } static gboolean