Skip to content

Commit 44f5b0e

Browse files
committed
Add Clutter API to get the stage-views an actor is painted on
Add a clutter_actor_peek_stage_views() method and a stage-views-changed signal to ClutterActor. This doesn't invalidate the stage-views list on changes to the transformation of the actors yet, for that we need another new ClutterActor method to invalidate the custom transformations applied via the apply_transform() vfunc. Also things will get quite a bit more expensive when doing that (the transformation matrix will have to be put together more often), so we probably also want the caching of transformation matrices in place when we start doing that.
1 parent f1046bb commit 44f5b0e

10 files changed

Lines changed: 794 additions & 34 deletions

File tree

clutter/clutter/clutter-actor-private.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,14 +313,16 @@ void _clutter_actor_detach_clone
313313
void _clutter_actor_queue_redraw_on_clones (ClutterActor *actor);
314314
void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor);
315315
void _clutter_actor_queue_only_relayout (ClutterActor *actor);
316-
void _clutter_actor_queue_update_resource_scale_recursive (ClutterActor *actor);
316+
void clutter_actor_clear_stage_views_recursive (ClutterActor *actor);
317317

318318
gboolean _clutter_actor_get_real_resource_scale (ClutterActor *actor,
319319
float *resource_scale);
320320

321321
ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
322322
CoglTexture *texture);
323323

324+
void clutter_actor_update_stage_views (ClutterActor *self);
325+
324326
G_END_DECLS
325327

326328
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */

clutter/clutter/clutter-actor.c

Lines changed: 217 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,8 @@ struct _ClutterActorPrivate
812812
gulong resolution_changed_id;
813813
gulong font_changed_id;
814814

815+
GList *stage_views;
816+
815817
/* bitfields: KEEP AT THE END */
816818

817819
/* fixed position and sizes */
@@ -854,6 +856,7 @@ struct _ClutterActorPrivate
854856
guint had_effects_on_last_paint_volume_update : 1;
855857
guint needs_compute_resource_scale : 1;
856858
guint absolute_origin_changed : 1;
859+
guint needs_update_stage_views : 1;
857860
};
858861

859862
enum
@@ -1016,6 +1019,7 @@ enum
10161019
TRANSITIONS_COMPLETED,
10171020
TOUCH_EVENT,
10181021
TRANSITION_STOPPED,
1022+
STAGE_VIEWS_CHANGED,
10191023

10201024
LAST_SIGNAL
10211025
};
@@ -1636,6 +1640,22 @@ clutter_actor_update_map_state (ClutterActor *self,
16361640
#endif
16371641
}
16381642

1643+
static void
1644+
queue_update_stage_views (ClutterActor *actor)
1645+
{
1646+
while (actor && !actor->priv->needs_update_stage_views)
1647+
{
1648+
actor->priv->needs_update_stage_views = TRUE;
1649+
1650+
/* We don't really need to update the stage-views of the actors up the
1651+
* hierarchy, we set the flag anyway though so we can avoid traversing
1652+
* the whole scenegraph when looking for actors which need an update
1653+
* in clutter_actor_update_stage_views().
1654+
*/
1655+
actor = actor->priv->parent;
1656+
}
1657+
}
1658+
16391659
static void
16401660
clutter_actor_real_map (ClutterActor *self)
16411661
{
@@ -1650,6 +1670,18 @@ clutter_actor_real_map (ClutterActor *self)
16501670

16511671
self->priv->needs_paint_volume_update = TRUE;
16521672

1673+
/* We skip unmapped actors when updating the stage-views list, so if
1674+
* an actors list got invalidated while it was unmapped make sure to
1675+
* set priv->needs_update_stage_views to TRUE for all actors up the
1676+
* hierarchy now.
1677+
*/
1678+
if (self->priv->needs_update_stage_views)
1679+
{
1680+
/* Avoid the early return in queue_update_stage_views() */
1681+
self->priv->needs_update_stage_views = FALSE;
1682+
queue_update_stage_views (self);
1683+
}
1684+
16531685
clutter_actor_ensure_resource_scale (self);
16541686

16551687
/* notify on parent mapped before potentially mapping
@@ -2587,6 +2619,7 @@ static void
25872619
absolute_allocation_changed (ClutterActor *actor)
25882620
{
25892621
actor->priv->needs_compute_resource_scale = TRUE;
2622+
queue_update_stage_views (actor);
25902623
}
25912624

25922625
static ClutterActorTraverseVisitFlags
@@ -4403,6 +4436,7 @@ typedef enum
44034436
REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
44044437
REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
44054438
REMOVE_CHILD_STOP_TRANSITIONS = 1 << 6,
4439+
REMOVE_CHILD_CLEAR_STAGE_VIEWS = 1 << 7,
44064440

44074441
/* default flags for public API */
44084442
REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
@@ -4411,14 +4445,16 @@ typedef enum
44114445
REMOVE_CHILD_EMIT_ACTOR_REMOVED |
44124446
REMOVE_CHILD_CHECK_STATE |
44134447
REMOVE_CHILD_FLUSH_QUEUE |
4414-
REMOVE_CHILD_NOTIFY_FIRST_LAST,
4448+
REMOVE_CHILD_NOTIFY_FIRST_LAST |
4449+
REMOVE_CHILD_CLEAR_STAGE_VIEWS,
44154450

44164451
/* flags for legacy/deprecated API */
44174452
REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
44184453
REMOVE_CHILD_CHECK_STATE |
44194454
REMOVE_CHILD_FLUSH_QUEUE |
44204455
REMOVE_CHILD_EMIT_PARENT_SET |
4421-
REMOVE_CHILD_NOTIFY_FIRST_LAST
4456+
REMOVE_CHILD_NOTIFY_FIRST_LAST |
4457+
REMOVE_CHILD_CLEAR_STAGE_VIEWS
44224458
} ClutterActorRemoveChildFlags;
44234459

44244460
/*< private >
@@ -4440,6 +4476,7 @@ clutter_actor_remove_child_internal (ClutterActor *self,
44404476
gboolean notify_first_last;
44414477
gboolean was_mapped;
44424478
gboolean stop_transitions;
4479+
gboolean clear_stage_views;
44434480
GObject *obj;
44444481

44454482
if (self == child)
@@ -4456,6 +4493,7 @@ clutter_actor_remove_child_internal (ClutterActor *self,
44564493
flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
44574494
notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
44584495
stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
4496+
clear_stage_views = (flags & REMOVE_CHILD_CLEAR_STAGE_VIEWS) != 0;
44594497

44604498
obj = G_OBJECT (self);
44614499
g_object_freeze_notify (obj);
@@ -4529,6 +4567,13 @@ clutter_actor_remove_child_internal (ClutterActor *self,
45294567
clutter_actor_queue_compute_expand (self);
45304568
}
45314569

4570+
/* Only actors which are attached to a stage get notified about changes
4571+
* to the stage views, so make sure all the stage-views lists are
4572+
* cleared as the child and its children leave the actor tree.
4573+
*/
4574+
if (clear_stage_views && !CLUTTER_ACTOR_IN_DESTRUCTION (child))
4575+
clutter_actor_clear_stage_views_recursive (child);
4576+
45324577
if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child) &&
45334578
!CLUTTER_ACTOR_IN_DESTRUCTION (child))
45344579
{
@@ -6201,6 +6246,8 @@ clutter_actor_dispose (GObject *object)
62016246
priv->clones = NULL;
62026247
}
62036248

6249+
g_clear_pointer (&priv->stage_views, g_list_free);
6250+
62046251
G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
62056252
}
62066253

@@ -8748,6 +8795,26 @@ clutter_actor_class_init (ClutterActorClass *klass)
87488795
g_signal_set_va_marshaller (actor_signals[TOUCH_EVENT],
87498796
G_TYPE_FROM_CLASS (object_class),
87508797
_clutter_marshal_BOOLEAN__BOXEDv);
8798+
8799+
/**
8800+
* ClutterActor::stage-views-changed:
8801+
* @actor: a #ClutterActor
8802+
*
8803+
* The ::stage-views-changed signal is emitted when the position or
8804+
* size an actor is being painted at have changed so that it's visible
8805+
* on different stage views.
8806+
*
8807+
* This signal is also emitted when the actor gets detached from the stage
8808+
* or when the views of the stage have been invalidated and will be
8809+
* replaced; it's not emitted when the actor gets hidden.
8810+
*/
8811+
actor_signals[STAGE_VIEWS_CHANGED] =
8812+
g_signal_new (I_("stage-views-changed"),
8813+
G_TYPE_FROM_CLASS (object_class),
8814+
G_SIGNAL_RUN_LAST,
8815+
0,
8816+
NULL, NULL, NULL,
8817+
G_TYPE_NONE, 0);
87518818
}
87528819

87538820
static void
@@ -8766,6 +8833,7 @@ clutter_actor_init (ClutterActor *self)
87668833
priv->needs_allocation = TRUE;
87678834
priv->needs_paint_volume_update = TRUE;
87688835
priv->needs_compute_resource_scale = TRUE;
8836+
priv->needs_update_stage_views = TRUE;
87698837

87708838
priv->cached_width_age = 1;
87718839
priv->cached_height_age = 1;
@@ -17578,17 +17646,27 @@ _clutter_actor_get_resource_scale_for_rect (ClutterActor *self,
1757817646
float *resource_scale)
1757917647
{
1758017648
ClutterActor *stage;
17649+
g_autoptr (GList) views = NULL;
17650+
GList *l;
1758117651
float max_scale = 0;
1758217652

1758317653
stage = _clutter_actor_get_stage_internal (self);
1758417654
if (!stage)
1758517655
return FALSE;
1758617656

17587-
if (!_clutter_stage_get_max_view_scale_factor_for_rect (CLUTTER_STAGE (stage),
17588-
bounding_rect,
17589-
&max_scale))
17657+
views = clutter_stage_get_views_for_rect (CLUTTER_STAGE (stage),
17658+
bounding_rect);
17659+
17660+
if (!views)
1759017661
return FALSE;
1759117662

17663+
for (l = views; l; l = l->next)
17664+
{
17665+
ClutterStageView *view = l->data;
17666+
17667+
max_scale = MAX (clutter_stage_view_get_scale (view), max_scale);
17668+
}
17669+
1759217670
*resource_scale = max_scale;
1759317671

1759417672
return TRUE;
@@ -17664,20 +17742,30 @@ _clutter_actor_compute_resource_scale (ClutterActor *self,
1766417742
}
1766517743

1766617744
static ClutterActorTraverseVisitFlags
17667-
queue_update_resource_scale_cb (ClutterActor *actor,
17668-
int depth,
17669-
void *user_data)
17745+
clear_stage_views_cb (ClutterActor *actor,
17746+
int depth,
17747+
gpointer user_data)
1767017748
{
17749+
g_autoptr (GList) old_stage_views = NULL;
17750+
17751+
actor->priv->needs_update_stage_views = TRUE;
17752+
1767117753
actor->priv->needs_compute_resource_scale = TRUE;
17754+
17755+
old_stage_views = g_steal_pointer (&actor->priv->stage_views);
17756+
17757+
if (old_stage_views)
17758+
g_signal_emit (actor, actor_signals[STAGE_VIEWS_CHANGED], 0);
17759+
1767217760
return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1767317761
}
1767417762

1767517763
void
17676-
_clutter_actor_queue_update_resource_scale_recursive (ClutterActor *self)
17764+
clutter_actor_clear_stage_views_recursive (ClutterActor *self)
1767717765
{
1767817766
_clutter_actor_traverse (self,
1767917767
CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
17680-
queue_update_resource_scale_cb,
17768+
clear_stage_views_cb,
1768117769
NULL,
1768217770
NULL);
1768317771
}
@@ -17769,6 +17857,125 @@ clutter_actor_get_resource_scale (ClutterActor *self,
1776917857
return FALSE;
1777017858
}
1777117859

17860+
static gboolean
17861+
sorted_lists_equal (GList *list_a,
17862+
GList *list_b)
17863+
{
17864+
GList *a, *b;
17865+
17866+
if (!list_a && !list_b)
17867+
return TRUE;
17868+
17869+
for (a = list_a, b = list_b;
17870+
a && b;
17871+
a = a->next, b = b->next)
17872+
{
17873+
if (a->data != b->data)
17874+
break;
17875+
17876+
if (!a->next && !b->next)
17877+
return TRUE;
17878+
}
17879+
17880+
return FALSE;
17881+
}
17882+
17883+
static void
17884+
update_stage_views (ClutterActor *self)
17885+
{
17886+
ClutterActorPrivate *priv = self->priv;
17887+
g_autoptr (GList) old_stage_views = NULL;
17888+
ClutterStage *stage;
17889+
graphene_rect_t bounding_rect;
17890+
17891+
old_stage_views = g_steal_pointer (&priv->stage_views);
17892+
17893+
if (priv->needs_allocation)
17894+
{
17895+
g_warning ("Can't update stage views actor %s is on because it needs an "
17896+
"allocation.", _clutter_actor_get_debug_name (self));
17897+
goto out;
17898+
}
17899+
17900+
stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
17901+
g_return_if_fail (stage);
17902+
17903+
clutter_actor_get_transformed_position (self,
17904+
&bounding_rect.origin.x,
17905+
&bounding_rect.origin.y);
17906+
clutter_actor_get_transformed_size (self,
17907+
&bounding_rect.size.width,
17908+
&bounding_rect.size.height);
17909+
17910+
if (bounding_rect.size.width == 0.0 ||
17911+
bounding_rect.size.height == 0.0)
17912+
goto out;
17913+
17914+
priv->stage_views = clutter_stage_get_views_for_rect (stage,
17915+
&bounding_rect);
17916+
17917+
out:
17918+
if (g_signal_has_handler_pending (self, actor_signals[STAGE_VIEWS_CHANGED],
17919+
0, TRUE))
17920+
{
17921+
if (!sorted_lists_equal (old_stage_views, priv->stage_views))
17922+
g_signal_emit (self, actor_signals[STAGE_VIEWS_CHANGED], 0);
17923+
}
17924+
}
17925+
17926+
void
17927+
clutter_actor_update_stage_views (ClutterActor *self)
17928+
{
17929+
ClutterActorPrivate *priv = self->priv;
17930+
ClutterActor *child;
17931+
17932+
if (!CLUTTER_ACTOR_IS_MAPPED (self) ||
17933+
CLUTTER_ACTOR_IN_DESTRUCTION (self))
17934+
return;
17935+
17936+
if (!priv->needs_update_stage_views)
17937+
return;
17938+
17939+
update_stage_views (self);
17940+
17941+
priv->needs_update_stage_views = FALSE;
17942+
17943+
for (child = priv->first_child; child; child = child->priv->next_sibling)
17944+
clutter_actor_update_stage_views (child);
17945+
}
17946+
17947+
/**
17948+
* clutter_actor_peek_stage_views:
17949+
* @self: A #ClutterActor
17950+
*
17951+
* Retrieves the list of #ClutterStageView<!-- -->s the actor is being
17952+
* painted on.
17953+
*
17954+
* If this function is called during the paint cycle, the list is guaranteed
17955+
* to be up-to-date, if called outside the paint cycle, the list will
17956+
* contain the views the actor was painted on last.
17957+
*
17958+
* The list returned by this function is not updated when the actors
17959+
* visibility changes: If an actor gets hidden and is not being painted
17960+
* anymore, this function will return the list of views the actor was
17961+
* painted on last.
17962+
*
17963+
* If an actor is not attached to a stage (realized), this function will
17964+
* always return an empty list.
17965+
*
17966+
* Returns: (transfer none) (element-type Clutter.StageView): The list of
17967+
* #ClutterStageView<!-- -->s the actor is being painted on. The list and
17968+
* its contents are owned by the #ClutterActor and the list may not be
17969+
* freed or modified.
17970+
*/
17971+
GList *
17972+
clutter_actor_peek_stage_views (ClutterActor *self)
17973+
{
17974+
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
17975+
17976+
return self->priv->stage_views;
17977+
}
17978+
1777217979
/**
1777317980
* clutter_actor_has_overlaps:
1777417981
* @self: A #ClutterActor

clutter/clutter/clutter-actor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,9 @@ void clutter_actor_class_set_layout_manager_type (ClutterActorClass *actor_class
932932
CLUTTER_EXPORT
933933
GType clutter_actor_class_get_layout_manager_type (ClutterActorClass *actor_class);
934934

935+
CLUTTER_EXPORT
936+
GList * clutter_actor_peek_stage_views (ClutterActor *self);
937+
935938
G_END_DECLS
936939

937940
#endif /* __CLUTTER_ACTOR_H__ */

0 commit comments

Comments
 (0)