actor: Add internal child flag
ClutterActor checks, when destroying and reparenting, if the parent actor implements the Container interface, and automatically calls the remove() method to perform a clean removal. Actors implementing Container, though, might have internal children; that is, children that are not added through the Container API. It is already possible to iterate through them using the Container API to avoid breaking invariants - but calling clutter_actor_destroy() on these children (even from the Container implementation, and thus outside of Clutter's control) will either lead to leaks or to segmentation faults. Clutter needs a way to distinguish a clutter_actor_set_parent() done on an internal child from one done on a "public" child; for this reason, a push/pop pair of functions should be available to Actor implementations to mark the section where they wish to add internal children: ➔ clutter_actor_push_internal (); ... clutter_actor_set_parent (child1, parent); clutter_actor_set_parent (child2, parent); ... ➔ clutter_actor_pop_internal (); The set_parent() call will automatically set the newly added INTERNAL_CHILD private flag on each child, and both clutter_actor_destroy() and clutter_actor_unparent() will check for the flag before deciding whether to call the Container's remove method.
This commit is contained in:
parent
d2ea7cd6a8
commit
1520ba6190
@ -3001,8 +3001,14 @@ clutter_actor_dispose (GObject *object)
|
|||||||
{
|
{
|
||||||
ClutterActor *parent = priv->parent_actor;
|
ClutterActor *parent = priv->parent_actor;
|
||||||
|
|
||||||
if (CLUTTER_IS_CONTAINER (parent))
|
/* go through the Container implementation unless this
|
||||||
clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
|
* is an internal child and has been marked as such
|
||||||
|
*/
|
||||||
|
if (CLUTTER_IS_CONTAINER (parent) &&
|
||||||
|
!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_INTERNAL_CHILD))
|
||||||
|
{
|
||||||
|
clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
priv->parent_actor = NULL;
|
priv->parent_actor = NULL;
|
||||||
}
|
}
|
||||||
@ -6619,6 +6625,7 @@ clutter_actor_set_parent (ClutterActor *self,
|
|||||||
{
|
{
|
||||||
ClutterActorPrivate *priv;
|
ClutterActorPrivate *priv;
|
||||||
ClutterTextDirection text_dir;
|
ClutterTextDirection text_dir;
|
||||||
|
ClutterMainContext *ctx;
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
||||||
g_return_if_fail (CLUTTER_IS_ACTOR (parent));
|
g_return_if_fail (CLUTTER_IS_ACTOR (parent));
|
||||||
@ -6648,6 +6655,14 @@ clutter_actor_set_parent (ClutterActor *self,
|
|||||||
g_object_ref_sink (self);
|
g_object_ref_sink (self);
|
||||||
priv->parent_actor = parent;
|
priv->parent_actor = parent;
|
||||||
|
|
||||||
|
ctx = _clutter_context_get_default ();
|
||||||
|
|
||||||
|
/* if push_internal() has been called then we automatically set
|
||||||
|
* the flag on the actor
|
||||||
|
*/
|
||||||
|
if (ctx->internal_child)
|
||||||
|
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_INTERNAL_CHILD);
|
||||||
|
|
||||||
/* clutter_actor_reparent() will emit ::parent-set for us */
|
/* clutter_actor_reparent() will emit ::parent-set for us */
|
||||||
if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT))
|
if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT))
|
||||||
g_signal_emit (self, actor_signals[PARENT_SET], 0, NULL);
|
g_signal_emit (self, actor_signals[PARENT_SET], 0, NULL);
|
||||||
@ -6825,17 +6840,22 @@ clutter_actor_reparent (ClutterActor *self,
|
|||||||
|
|
||||||
g_object_ref (self);
|
g_object_ref (self);
|
||||||
|
|
||||||
if (CLUTTER_IS_CONTAINER (priv->parent_actor))
|
/* go through the Container implementation if this is a regular
|
||||||
|
* child and not an internal one
|
||||||
|
*/
|
||||||
|
if (CLUTTER_IS_CONTAINER (priv->parent_actor) &&
|
||||||
|
!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_INTERNAL_CHILD))
|
||||||
{
|
{
|
||||||
ClutterContainer *parent = CLUTTER_CONTAINER (priv->parent_actor);
|
ClutterContainer *parent = CLUTTER_CONTAINER (priv->parent_actor);
|
||||||
/* Note, will call unparent() */
|
|
||||||
|
/* this will have to call unparent() */
|
||||||
clutter_container_remove_actor (parent, self);
|
clutter_container_remove_actor (parent, self);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
clutter_actor_unparent (self);
|
clutter_actor_unparent (self);
|
||||||
|
|
||||||
if (CLUTTER_IS_CONTAINER (new_parent))
|
|
||||||
/* Note, will call parent() */
|
/* Note, will call parent() */
|
||||||
|
if (CLUTTER_IS_CONTAINER (new_parent))
|
||||||
clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
|
clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
|
||||||
else
|
else
|
||||||
clutter_actor_set_parent (self, new_parent);
|
clutter_actor_set_parent (self, new_parent);
|
||||||
@ -9471,3 +9491,83 @@ clutter_actor_get_text_direction (ClutterActor *self)
|
|||||||
|
|
||||||
return priv->text_direction;
|
return priv->text_direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_actor_push_internal:
|
||||||
|
*
|
||||||
|
* Should be used by actors implementing the #ClutterContainer and with
|
||||||
|
* internal children added through clutter_actor_set_parent(), for instance:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
* static void
|
||||||
|
* my_actor_init (MyActor *self)
|
||||||
|
* {
|
||||||
|
* self->priv = SELF_ACTOR_GET_PRIVATE (self);
|
||||||
|
*
|
||||||
|
* clutter_actor_push_internal ();
|
||||||
|
*
|
||||||
|
* /* calling clutter_actor_set_parent() now will result in
|
||||||
|
* * the internal flag being set on a child of MyActor
|
||||||
|
* */
|
||||||
|
*
|
||||||
|
* /* internal child: a background texture */
|
||||||
|
* self->priv->background_tex = clutter_texture_new ();
|
||||||
|
* clutter_actor_set_parent (self->priv->background_tex,
|
||||||
|
* CLUTTER_ACTOR (self));
|
||||||
|
*
|
||||||
|
* /* internal child: a label */
|
||||||
|
* self->priv->label = clutter_text_new ();
|
||||||
|
* clutter_actor_set_parent (self->priv->label,
|
||||||
|
* CLUTTER_ACTOR (self));
|
||||||
|
*
|
||||||
|
* clutter_actor_pop_internal ();
|
||||||
|
*
|
||||||
|
* /* calling clutter_actor_set_parent() now will not result in
|
||||||
|
* * the internal flag being set on a child of MyActor
|
||||||
|
* */
|
||||||
|
* }
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* This function will be used by Clutter to toggle an "internal child"
|
||||||
|
* flag whenever clutter_actor_set_parent() is called; internal children
|
||||||
|
* are handled differently by Clutter, specifically when destroying their
|
||||||
|
* parent.
|
||||||
|
*
|
||||||
|
* Call clutter_actor_pop_internal() when you finished adding internal
|
||||||
|
* children.
|
||||||
|
*
|
||||||
|
* Nested calls to clutter_actor_push_internal() are allowed, but each
|
||||||
|
* one must by followed by a clutter_actor_pop_internal() call.
|
||||||
|
*
|
||||||
|
* Since: 1.2
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_actor_push_internal (void)
|
||||||
|
{
|
||||||
|
ClutterMainContext *ctx = _clutter_context_get_default ();
|
||||||
|
|
||||||
|
ctx->internal_child += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_actor_pop_internal:
|
||||||
|
*
|
||||||
|
* Disables the effects of clutter_actor_pop_internal()
|
||||||
|
*
|
||||||
|
* Since: 1.2
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_actor_pop_internal (void)
|
||||||
|
{
|
||||||
|
ClutterMainContext *ctx = _clutter_context_get_default ();
|
||||||
|
|
||||||
|
if (ctx->internal_child == 0)
|
||||||
|
{
|
||||||
|
g_warning ("Mismatched %s: you need to call "
|
||||||
|
"clutter_actor_push_composite() at least once before "
|
||||||
|
"calling this function", G_STRFUNC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->internal_child -= 1;
|
||||||
|
}
|
||||||
|
@ -532,6 +532,9 @@ void clutter_actor_set_text_direction (ClutterActor *sel
|
|||||||
ClutterTextDirection text_dir);
|
ClutterTextDirection text_dir);
|
||||||
ClutterTextDirection clutter_actor_get_text_direction (ClutterActor *self);
|
ClutterTextDirection clutter_actor_get_text_direction (ClutterActor *self);
|
||||||
|
|
||||||
|
void clutter_actor_push_internal (void);
|
||||||
|
void clutter_actor_pop_internal (void);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __CLUTTER_ACTOR_H__ */
|
#endif /* __CLUTTER_ACTOR_H__ */
|
||||||
|
@ -58,13 +58,26 @@ typedef enum {
|
|||||||
CLUTTER_ACTOR_IN_DESTRUCTION = 1 << 0,
|
CLUTTER_ACTOR_IN_DESTRUCTION = 1 << 0,
|
||||||
CLUTTER_ACTOR_IS_TOPLEVEL = 1 << 1,
|
CLUTTER_ACTOR_IS_TOPLEVEL = 1 << 1,
|
||||||
CLUTTER_ACTOR_IN_REPARENT = 1 << 2,
|
CLUTTER_ACTOR_IN_REPARENT = 1 << 2,
|
||||||
CLUTTER_ACTOR_SYNC_MATRICES = 1 << 3, /* Used by stage to indicate GL
|
|
||||||
* viewport / perspective etc
|
/* Used by the stage to indicate GL viewport / perspective etc needs
|
||||||
* needs (re)setting.
|
* (re)setting.
|
||||||
*/
|
*/
|
||||||
CLUTTER_ACTOR_IN_PAINT = 1 << 4, /* Used to avoid recursion */
|
CLUTTER_ACTOR_SYNC_MATRICES = 1 << 3,
|
||||||
CLUTTER_ACTOR_IN_RELAYOUT = 1 << 5, /* Used to avoid recursion */
|
|
||||||
CLUTTER_STAGE_IN_RESIZE = 1 << 6
|
/* Used to avoid recursion */
|
||||||
|
CLUTTER_ACTOR_IN_PAINT = 1 << 4,
|
||||||
|
|
||||||
|
/* Used to avoid recursion */
|
||||||
|
CLUTTER_ACTOR_IN_RELAYOUT = 1 << 5,
|
||||||
|
|
||||||
|
/* Used by the stage if resizing is an asynchronous operation (like on
|
||||||
|
* X11) to delay queueing relayouts until we got a notification from the
|
||||||
|
* event handling
|
||||||
|
*/
|
||||||
|
CLUTTER_STAGE_IN_RESIZE = 1 << 6,
|
||||||
|
|
||||||
|
/* a flag for internal children of Containers */
|
||||||
|
CLUTTER_ACTOR_INTERNAL_CHILD = 1 << 7
|
||||||
} ClutterPrivateFlags;
|
} ClutterPrivateFlags;
|
||||||
|
|
||||||
struct _ClutterInputDevice
|
struct _ClutterInputDevice
|
||||||
@ -133,6 +146,8 @@ struct _ClutterMainContext
|
|||||||
gulong redraw_count;
|
gulong redraw_count;
|
||||||
|
|
||||||
GList *repaint_funcs;
|
GList *repaint_funcs;
|
||||||
|
|
||||||
|
gint internal_child;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CLUTTER_CONTEXT() (_clutter_context_get_default ())
|
#define CLUTTER_CONTEXT() (_clutter_context_get_default ())
|
||||||
|
@ -352,6 +352,8 @@ clutter_actor_lower
|
|||||||
clutter_actor_raise_top
|
clutter_actor_raise_top
|
||||||
clutter_actor_lower_bottom
|
clutter_actor_lower_bottom
|
||||||
clutter_actor_get_stage
|
clutter_actor_get_stage
|
||||||
|
clutter_actor_push_internal
|
||||||
|
clutter_actor_pop_internal
|
||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
clutter_actor_set_depth
|
clutter_actor_set_depth
|
||||||
|
Loading…
Reference in New Issue
Block a user