Enforce invariants on mapped, realized, visibility states
Bug 1138 - No trackable "mapped" state * Add a VISIBLE flag tracking application programmer's expected showing-state for the actor, allowing us to always ensure we keep what the app wants while tracking internal implementation state separately. * Make MAPPED reflect whether the actor will be painted; add notification on a ClutterActor::mapped property. Keep MAPPED state updated as the actor is shown, ancestors are shown, actor is reparented, etc. * Require a stage and realized parents to realize; this means at realization time the correct window system and GL resources are known. But unparented actors can no longer be realized. * Allow children to be unrealized even if parent is realized. Otherwise in effect either all actors or no actors are realized, i.e. it becomes a stage-global flag. * Allow clutter_actor_realize() to "fail" if not inside a toplevel * Rework clutter_actor_unrealize() so internally we have a flavor that does not mess with visibility flag * Add _clutter_actor_rerealize() to encapsulate a somewhat tricky operation we were doing in a couple of places * Do not realize/unrealize children in ClutterGroup, ClutterActor already does it * Do not realize impl by hand in clutter_stage_show(), since showing impl already does that * Do not unrealize in various dispose() methods, since ClutterActor dispose implementation already does it and chaining up is mandatory * ClutterTexture uses COGL while unrealizable (before it's added to a stage). Previously this breakage was affecting ClutterActor because we had to allow realize outside a stage. Move the breakage to ClutterTexture, by making ClutterTexture just use COGL while not realized. * Unrealize before we set parent to NULL in clutter_actor_unparent(). This means unrealize() implementations can get to the stage. Because actors need the stage in order to detach from stage. * Update clutter-actor-invariants.txt to reflect latest changes * Remove explicit hide/unrealize from ClutterActor::dispose since unparent already forces those Instead just assert that unparent() occurred and did the right thing. * Check whether parent implements unrealize before chaining up Needed because ClutterGroup no longer has to implement unrealize. * Perform unrealize in the default handler for the signal. This allows non-containers that have children to work properly, and allows containers to override how it's done. * Add map/unmap virtual methods and set MAPPED flag on self and children in there. This allows subclasses to hook map/unmap. These are not signals, because notify::mapped is better for anything it's legitimate for a non-subclass to do. Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
This commit is contained in:

committed by
Emmanuele Bassi

parent
b73ee6992c
commit
125bded814
@ -335,19 +335,15 @@ clutter_texture_realize (ClutterActor *actor)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_READ_PIXELS))
|
||||
{
|
||||
/* Dont allow realization with no data - note set_data
|
||||
* will set realize flags.
|
||||
*/
|
||||
CLUTTER_NOTE (TEXTURE,
|
||||
"Texture has no image data cannot realize");
|
||||
|
||||
CLUTTER_NOTE (TEXTURE, "flags %i", actor->flags);
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
CLUTTER_NOTE (TEXTURE, "flags %i", actor->flags);
|
||||
return;
|
||||
}
|
||||
/* If we have no data, then realization is a no-op but
|
||||
* we still want to be in REALIZED state to maintain
|
||||
* invariants. We may have already created the texture
|
||||
* if someone set some data earlier, or we may create it
|
||||
* later if someone sets some data later. The fact that
|
||||
* we may have created it earlier is really a bug, since
|
||||
* it means ClutterTexture can have GL resources without
|
||||
* being realized.
|
||||
*/
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (TEXTURE, "Texture realized");
|
||||
@ -539,9 +535,6 @@ clutter_texture_paint (ClutterActor *self)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR(texture)))
|
||||
clutter_actor_realize (CLUTTER_ACTOR(texture));
|
||||
|
||||
if (priv->fbo_handle != COGL_INVALID_HANDLE)
|
||||
{
|
||||
ClutterMainContext *context;
|
||||
@ -1392,6 +1385,12 @@ clutter_texture_get_cogl_texture (ClutterTexture *texture)
|
||||
* @cogl_tex. A reference to the texture is taken so if the handle is
|
||||
* no longer needed it should be deref'd with cogl_handle_unref.
|
||||
*
|
||||
* This should not be called on an unrealizable texture (one that
|
||||
* isn't inside a stage). (Currently the ClutterTexture
|
||||
* implementation relies on being able to have a GL texture while
|
||||
* unrealized, which means you can get away with it, but it's
|
||||
* not correct and may change in the future.)
|
||||
*
|
||||
* Since: 0.8
|
||||
*/
|
||||
void
|
||||
@ -1405,6 +1404,12 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture,
|
||||
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
|
||||
g_return_if_fail (cogl_is_texture (cogl_tex));
|
||||
|
||||
/* FIXME this implementation should realize the actor if it's in a
|
||||
* stage, and warn and return if not in a stage yet. However, right
|
||||
* now everything would break if we did that, so we just fudge it
|
||||
* and we're broken: we can have a texture without being realized.
|
||||
*/
|
||||
|
||||
priv = texture->priv;
|
||||
|
||||
width = cogl_texture_get_width (cogl_tex);
|
||||
@ -1420,6 +1425,14 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture,
|
||||
|
||||
/* Remove old texture */
|
||||
texture_free_gl_resources (texture);
|
||||
|
||||
/* Free any saved data so realization doesn't resend it to GL */
|
||||
if (priv->local_data)
|
||||
{
|
||||
g_free (priv->local_data);
|
||||
priv->local_data = NULL;
|
||||
}
|
||||
|
||||
/* Use the new texture */
|
||||
|
||||
cogl_material_set_layer (priv->material, 0, cogl_tex);
|
||||
@ -1436,8 +1449,6 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture,
|
||||
priv->width,
|
||||
priv->height);
|
||||
|
||||
CLUTTER_ACTOR_SET_FLAGS (CLUTTER_ACTOR (texture), CLUTTER_ACTOR_REALIZED);
|
||||
|
||||
if (size_change)
|
||||
{
|
||||
g_signal_emit (texture, texture_signals[SIZE_CHANGE], 0,
|
||||
@ -1480,6 +1491,10 @@ clutter_texture_set_from_data (ClutterTexture *texture,
|
||||
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
|
||||
flags |= COGL_TEXTURE_AUTO_MIPMAP;
|
||||
|
||||
/* FIXME if we are not realized, we should store the data
|
||||
* for future use, instead of creating the texture.
|
||||
*/
|
||||
|
||||
new_texture = cogl_texture_new_from_data (width, height,
|
||||
max_waste, flags,
|
||||
source_format,
|
||||
@ -2004,15 +2019,8 @@ clutter_texture_set_filter_quality (ClutterTexture *texture,
|
||||
filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) &&
|
||||
CLUTTER_ACTOR_IS_REALIZED (texture))
|
||||
{
|
||||
gboolean was_visible;
|
||||
|
||||
was_visible = CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (texture));
|
||||
|
||||
clutter_actor_unrealize (CLUTTER_ACTOR (texture));
|
||||
clutter_actor_realize (CLUTTER_ACTOR (texture));
|
||||
|
||||
if (was_visible)
|
||||
clutter_actor_show (CLUTTER_ACTOR (texture));
|
||||
_clutter_actor_rerealize (CLUTTER_ACTOR (texture),
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (texture), "filter-quality");
|
||||
@ -2172,9 +2180,13 @@ clutter_texture_get_base_size (ClutterTexture *texture,
|
||||
|
||||
/* Attempt to realize, mainly for subclasses ( such as labels )
|
||||
* which may not create pixbuf data and thus base size until
|
||||
* realization happens.
|
||||
* realization happens. If we aren't in a stage we can't realize
|
||||
* though. Doing this here is probably just broken; instead
|
||||
* we could virtualize get_base_size, or have the subclasses
|
||||
* create the pixbufs sooner, or something better.
|
||||
*/
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (texture))
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (texture) &&
|
||||
clutter_actor_get_stage (CLUTTER_ACTOR (texture)) != NULL)
|
||||
clutter_actor_realize (CLUTTER_ACTOR (texture));
|
||||
|
||||
if (width)
|
||||
@ -2251,8 +2263,15 @@ clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
|
||||
if ((flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT))
|
||||
source_format |= COGL_PREMULT_BIT;
|
||||
|
||||
clutter_actor_realize (CLUTTER_ACTOR (texture));
|
||||
/* attempt to realize ... */
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (texture) &&
|
||||
clutter_actor_get_stage (CLUTTER_ACTOR (texture)) != NULL)
|
||||
clutter_actor_realize (CLUTTER_ACTOR (texture));
|
||||
|
||||
/* due to the fudging of clutter_texture_set_cogl_texture()
|
||||
* which allows setting a texture pre-realize, we may end
|
||||
* up having a texture even if we couldn't realize yet.
|
||||
*/
|
||||
cogl_texture = clutter_texture_get_cogl_texture (texture);
|
||||
if (cogl_texture == COGL_INVALID_HANDLE)
|
||||
{
|
||||
@ -2329,8 +2348,6 @@ on_fbo_source_size_change (GObject *object,
|
||||
if (priv->fbo_handle == COGL_INVALID_HANDLE)
|
||||
{
|
||||
g_warning ("%s: Offscreen texture creation failed", G_STRLOC);
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (CLUTTER_ACTOR (texture),
|
||||
CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user