Bug 1015 - Cloning unparented actors with FBOs doesn't work with
authorNeil Roberts <neil@openedhand.com>
Fri, 4 Jul 2008 10:44:18 +0000 (10:44 +0000)
committerNeil Roberts <neil@openedhand.com>
Fri, 4 Jul 2008 10:44:18 +0000 (10:44 +0000)
new layout code

* clutter/clutter-texture.c (clutter_texture_new_from_actor): Now
parents the source actor if it doesn't already have a parent so
that it will get an allocation during layout.

* tests/test-fbo.c: One of the tests tries to ensure that the
ClutterTexture clone keeps the source actor alive by derefing
it. However as actors have a floating reference then test-fbo
doesn't have its own reference once the source is parented so
unrefing just steals the parent's reference and causes
badness. The test now claims the floating reference before cloning
the source so that it can safely be unref'd later.

ChangeLog
clutter/clutter-texture.c
tests/test-fbo.c

index 6a8ed7f..14bbcaf 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2008-07-04  Neil Roberts  <neil@o-hand.com>
+
+       Bug 1015 - Cloning unparented actors with FBOs doesn't work with
+       new layout code
+
+       * clutter/clutter-texture.c (clutter_texture_new_from_actor): Now
+       parents the source actor if it doesn't already have a parent so
+       that it will get an allocation during layout.
+
+       * tests/test-fbo.c: One of the tests tries to ensure that the
+       ClutterTexture clone keeps the source actor alive by derefing
+       it. However as actors have a floating reference then test-fbo
+       doesn't have its own reference once the source is parented so
+       unrefing just steals the parent's reference and causes
+       badness. The test now claims the floating reference before cloning
+       the source so that it can safely be unref'd later.
+
 2008-07-03  Emmanuele Bassi  <ebassi@openedhand.com>
 
        * clutter/x11/Makefile.am: Fix distchecking by adding the
index a84e170..f8d2b88 100644 (file)
@@ -414,6 +414,23 @@ clutter_texture_get_preferred_height (ClutterActor *self,
 }
 
 static void
+clutter_texture_allocate (ClutterActor          *self,
+                         const ClutterActorBox *box,
+                         gboolean               origin_changed)
+{
+  ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv;
+
+  /* chain up to set actor->allocation */
+  CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->allocate (self, box,
+                                                               origin_changed);
+
+  /* If we adopted the source fbo then allocate that at its preferred
+     size */
+  if (priv->fbo_source && clutter_actor_get_parent (priv->fbo_source) == self)
+    clutter_actor_allocate_preferred_size (priv->fbo_source, origin_changed);
+}
+
+static void
 clutter_texture_paint (ClutterActor *self)
 {
   ClutterTexture *texture = CLUTTER_TEXTURE (self);
@@ -651,8 +668,9 @@ clutter_texture_class_init (ClutterTextureClass *klass)
   actor_class->realize        = clutter_texture_realize;
   actor_class->unrealize      = clutter_texture_unrealize;
 
-  actor_class->get_preferred_width = clutter_texture_get_preferred_width;
+  actor_class->get_preferred_width  = clutter_texture_get_preferred_width;
   actor_class->get_preferred_height = clutter_texture_get_preferred_height;
+  actor_class->allocate             = clutter_texture_allocate;
 
   gobject_class->dispose      = clutter_texture_dispose;
   gobject_class->set_property = clutter_texture_set_property;
@@ -1644,8 +1662,19 @@ on_fbo_parent_change (ClutterActor        *actor,
  * <itemizedlist>
  *   <listitem>
  *     <para>The source actor must be made visible (i.e by calling
- *     #clutter_actor_show). The source actor does not however have to
- *     have a parent.</para>
+ *     #clutter_actor_show).</para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>The source actor must have a parent in order for it to be
+ *     allocated a size from the layouting mechanism. If the source
+ *     actor does not have a parent when this function is called then
+ *     the ClutterTexture will adopt it and allocate it at its
+ *     preferred size. Using this you can clone an actor that is
+ *     otherwise not displayed. Because of this feature if you do
+ *     intend to display the source actor then you must make sure that
+ *     the actor is parented before calling
+ *     clutter_texture_new_from_actor() or that you unparent it before
+ *     adding it to a container.</para>
  *   </listitem>
  *   <listitem>
  *     <para>Avoid reparenting the source with the created texture.</para>
@@ -1709,7 +1738,12 @@ clutter_texture_new_from_actor (ClutterActor *actor)
 
   priv = texture->priv;
 
-  priv->fbo_source = g_object_ref(actor);
+  priv->fbo_source = g_object_ref_sink (actor);
+
+  /* If the actor doesn't have a parent then claim it so that it will
+     get a size allocation during layout */
+  if (clutter_actor_get_parent (actor) == NULL)
+    clutter_actor_set_parent (actor, CLUTTER_ACTOR (texture));
 
   /* Connect up any signals which could change our underlying size */
   g_signal_connect (actor,
@@ -1766,6 +1800,12 @@ texture_fbo_free_resources (ClutterTexture *texture)
 
   if (priv->fbo_source != NULL)
     {
+      /* If we parented the texture then unparent it again so that it
+        will lose the reference */
+      if (clutter_actor_get_parent (priv->fbo_source)
+         == CLUTTER_ACTOR (texture))
+       clutter_actor_unparent (priv->fbo_source);
+
       g_signal_handlers_disconnect_by_func
                             (priv->fbo_source,
                              G_CALLBACK(on_fbo_parent_change),
index 47588a2..5b32428 100644 (file)
@@ -166,6 +166,8 @@ main (gint   argc,
 
   /* non visual breaks */
   foo_source = make_source();
+  g_object_ref_sink (foo_source);
+
   clutter_actor_show_all (foo_source);
   if ((fbo = clutter_texture_new_from_actor (foo_source)) == NULL)
     g_error("foo fbo creation failed");