2008-06-10 Emmanuele Bassi <ebassi@openedhand.com>
authorEmmanuele Bassi <ebassi@openedhand.com>
Tue, 10 Jun 2008 17:07:52 +0000 (17:07 +0000)
committerEmmanuele Bassi <ebassi@openedhand.com>
Tue, 10 Jun 2008 17:07:52 +0000 (17:07 +0000)
Bug #815 - Split up request, allocation, and paint box

* clutter/clutter-actor.[ch]: Rework the size allocation,
request and paint area. Now ::request_coords() is called
::allocate(), and ::query_coords() has been split into
::get_preferred_width() and ::get_preferred_height(). See
the documentation and the layout test on how to implement
a container and layout manager with the new API. (#915,
based on a patch by Havoc Pennington, Lucas Rocha and Johan
Bilien)

* clutter/clutter-clone-texture.c: Port CloneTexture to
the new size negotiation API; it just means forwarding
the requests to the parent texture.

* clutter/clutter-deprecated.h: Add deprecated and replaced
API.

* clutter/clutter-entry.c: Port Entry to the new size
negotiation API.

* clutter/clutter-group.c: Port Group to the new size
negotiation API; the semantics of the Group actor do not
change.

* clutter/clutter-label.c: Port Label to the new size
negotiation API, and vastly simplify the code.

* clutter/clutter-main.[ch]: Add API for executing a
relayout when needed.

* clutter/clutter-private.h: Add new Stage private API.

* clutter/clutter-rectangle.c: Update the get_abs_opacity()
call to get_paint_opacity().

* clutter/clutter-stage.c:
(clutter_stage_get_preferred_width),
(clutter_stage_get_preferred_height),
(clutter_stage_allocate),
(clutter_stage_class_init): Port Stage to the new size
negotiation API.

* clutter/clutter-texture.c: Port Texture to the new size
negotiation API.

* clutter/clutter-types.h: Add ClutterRequestMode enumeration.

* clutter/x11/clutter-stage-x11.c: Port the X11 stage
implementation to the new size negotiation API.

* tests/Makefile.am: Add the layout manager test case.

* tests/test-opacity.c: Update.

* tests/test-project.c: Update.

* tests/test-layout.c: Test case for a layout manager implemented
using the new size negotiation API; the layout manager handles
both transformed and untransformed children.

19 files changed:
ChangeLog
clutter/clutter-actor.c
clutter/clutter-actor.h
clutter/clutter-clone-texture.c
clutter/clutter-deprecated.h
clutter/clutter-entry.c
clutter/clutter-group.c
clutter/clutter-label.c
clutter/clutter-main.c
clutter/clutter-main.h
clutter/clutter-private.h
clutter/clutter-rectangle.c
clutter/clutter-stage.c
clutter/clutter-texture.c
clutter/x11/clutter-stage-x11.c
tests/Makefile.am
tests/test-layout.c [new file with mode: 0644]
tests/test-opacity.c
tests/test-project.c

index 9aa2825..b1e8d3b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,68 @@
 2008-06-10  Emmanuele Bassi  <ebassi@openedhand.com>
 
+       Bug #815 - Split up request, allocation, and paint box
+
+       * clutter/clutter-actor.[ch]: Rework the size allocation,
+       request and paint area. Now ::request_coords() is called
+       ::allocate(), and ::query_coords() has been split into
+       ::get_preferred_width() and ::get_preferred_height(). See
+       the documentation and the layout test on how to implement
+       a container and layout manager with the new API. (#915,
+       based on a patch by Havoc Pennington, Lucas Rocha and Johan
+       Bilien)
+
+       * clutter/clutter-clone-texture.c: Port CloneTexture to
+       the new size negotiation API; it just means forwarding
+       the requests to the parent texture.
+
+       * clutter/clutter-deprecated.h: Add deprecated and replaced
+       API.
+
+       * clutter/clutter-entry.c: Port Entry to the new size
+       negotiation API.
+
+       * clutter/clutter-group.c: Port Group to the new size
+       negotiation API; the semantics of the Group actor do not
+       change.
+
+       * clutter/clutter-label.c: Port Label to the new size
+       negotiation API, and vastly simplify the code.
+
+       * clutter/clutter-main.[ch]: Add API for executing a
+       relayout when needed.
+
+       * clutter/clutter-private.h: Add new Stage private API.
+
+       * clutter/clutter-rectangle.c: Update the get_abs_opacity()
+       call to get_paint_opacity().
+
+       * clutter/clutter-stage.c:
+       (clutter_stage_get_preferred_width),
+       (clutter_stage_get_preferred_height),
+       (clutter_stage_allocate),
+       (clutter_stage_class_init): Port Stage to the new size
+       negotiation API.
+
+       * clutter/clutter-texture.c: Port Texture to the new size
+       negotiation API.
+
+       * clutter/clutter-types.h: Add ClutterRequestMode enumeration.
+
+       * clutter/x11/clutter-stage-x11.c: Port the X11 stage
+       implementation to the new size negotiation API.
+
+       * tests/Makefile.am: Add the layout manager test case.
+
+       * tests/test-opacity.c: Update.
+
+       * tests/test-project.c: Update.
+
+       * tests/test-layout.c: Test case for a layout manager implemented
+       using the new size negotiation API; the layout manager handles
+       both transformed and untransformed children.
+
+2008-06-10  Emmanuele Bassi  <ebassi@openedhand.com>
+
        * Makefile.am: Add the po/ directory to the build.
 
 2008-06-10  Emmanuele Bassi  <ebassi@openedhand.com>
index 80d1413..18fdb81 100644 (file)
@@ -158,10 +158,40 @@ typedef struct _ShaderData ShaderData;
 
 struct _ClutterActorPrivate
 {
-  ClutterActorBox coords;
+  /* fixed_x, fixed_y, and the allocation box are all in parent
+   * coordinates.
+   */
+  ClutterUnit fixed_x;
+  ClutterUnit fixed_y;
+
+  /* request mode */
+  ClutterRequestMode request_mode;
+
+  /* our cached request width is for this height */
+  ClutterUnit request_width_for_height;
+  ClutterUnit request_min_width;
+  ClutterUnit request_natural_width;
+  /* our cached request height is for this width */
+  ClutterUnit request_height_for_width;
+  ClutterUnit request_min_height;
+  ClutterUnit request_natural_height;
+
+  ClutterActorBox allocation;
+
+  guint position_set         : 1;
+  guint min_width_set        : 1;
+  guint min_height_set       : 1;
+  guint natural_width_set    : 1;
+  guint natural_height_set   : 1;
+  /* cached request is invalid (implies allocation is too) */
+  guint needs_width_request  : 1;
+  /* cached request is invalid (implies allocation is too) */
+  guint needs_height_request : 1;
+  /* cached allocation is invalid (request has changed, probably) */
+  guint needs_allocation     : 1;
 
-  ClutterUnit     clip[4];
   guint           has_clip : 1;
+  ClutterUnit     clip[4];
 
   /* Rotation angles */
   ClutterFixed    rxang;
@@ -208,10 +238,43 @@ enum
 
   PROP_NAME,
 
+  /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
+   * when set they force a size request, when gotten they
+   * get the allocation if the allocation is valid, and the
+   * request otherwise. Also, they are in pixels, while
+   * all the underlying properties are in ClutterUnit.
+   */
   PROP_X,
   PROP_Y,
   PROP_WIDTH,
   PROP_HEIGHT,
+
+  /* Then the rest of these size-related properties are the "actual"
+   * underlying properties set or gotten by X, Y, WIDTH, HEIGHT. All
+   * of these are in ClutterUnit not in pixels.
+   */
+  PROP_FIXED_X,
+  PROP_FIXED_Y,
+
+  PROP_FIXED_POSITION_SET,
+
+  PROP_MIN_WIDTH,
+  PROP_MIN_WIDTH_SET,
+
+  PROP_MIN_HEIGHT,
+  PROP_MIN_HEIGHT_SET,
+
+  PROP_NATURAL_WIDTH,
+  PROP_NATURAL_WIDTH_SET,
+
+  PROP_NATURAL_HEIGHT,
+  PROP_NATURAL_HEIGHT_SET,
+
+  PROP_REQUEST_MODE,
+
+  /* Allocation properties are read-only */
+  PROP_ALLOCATION,
+
   PROP_DEPTH,
 
   PROP_CLIP,
@@ -277,6 +340,29 @@ static void clutter_actor_shader_post_paint (ClutterActor *actor);
 
 static void destroy_shader_data (ClutterActor *self);
 
+/* These setters are all static for now, maybe they should be in the
+ * public API, but they are perhaps obscure enough to leave only as
+ * properties
+ */
+static void clutter_actor_set_min_width          (ClutterActor *self,
+                                                  ClutterUnit   min_width);
+static void clutter_actor_set_min_height         (ClutterActor *self,
+                                                  ClutterUnit   min_height);
+static void clutter_actor_set_natural_width      (ClutterActor *self,
+                                                  ClutterUnit   natural_width);
+static void clutter_actor_set_natural_height     (ClutterActor *self,
+                                                  ClutterUnit   natural_height);
+static void clutter_actor_set_min_width_set      (ClutterActor *self,
+                                                  gboolean      use_min_width);
+static void clutter_actor_set_min_height_set     (ClutterActor *self,
+                                                  gboolean      use_min_height);
+static void clutter_actor_set_natural_width_set  (ClutterActor *self,
+                                                  gboolean  use_natural_width);
+static void clutter_actor_set_natural_height_set (ClutterActor *self,
+                                                  gboolean  use_natural_height);
+static void clutter_actor_set_request_mode       (ClutterActor *self,
+                                                  ClutterRequestMode mode);
+
 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor,
                                   clutter_actor,
                                   G_TYPE_INITIALLY_UNOWNED,
@@ -292,7 +378,7 @@ clutter_actor_real_show (ClutterActor *self)
       if (!CLUTTER_ACTOR_IS_REALIZED (self))
         clutter_actor_realize (self);
 
-      /* the mapped flag on the top-level actors is set by the
+      /* the mapped flag on the top-level actors must be set by the
        * per-backend implementation because it might be asynchronous
        */
       if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
@@ -300,6 +386,8 @@ clutter_actor_real_show (ClutterActor *self)
 
       if (CLUTTER_ACTOR_IS_VISIBLE (self))
         clutter_actor_queue_redraw (self);
+
+      clutter_actor_queue_relayout (self);
     }
 }
 
@@ -313,7 +401,8 @@ clutter_actor_real_show (ClutterActor *self)
  * Actors are visible by default.
  *
  * If this function is called on an actor without a parent, the
- * ClutterActor:show-on-set-parent will be set to %TRUE as a side effect.
+ * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
+ * effect.
  */
 void
 clutter_actor_show (ClutterActor *self)
@@ -345,7 +434,7 @@ clutter_actor_show (ClutterActor *self)
  * clutter_actor_show_all:
  * @self: a #ClutterActor
  *
- * Call show() on all children of an actor (if any).
+ * Calls clutter_actor_show() on all children of an actor (if any).
  *
  * Since: 0.2
  */
@@ -372,7 +461,7 @@ clutter_actor_real_hide (ClutterActor *self)
       if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
         CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
 
-      clutter_actor_queue_redraw (self);
+      clutter_actor_queue_relayout (self);
     }
 }
 
@@ -386,7 +475,7 @@ clutter_actor_real_hide (ClutterActor *self)
  * Actors are visible by default.
  *
  * If this function is called on an actor without a parent, the
- * ClutterActor:show-on-set-parent property will be set to %FALSE
+ * #ClutterActor:show-on-set-parent property will be set to %FALSE
  * as a side-effect.
  */
 void
@@ -419,7 +508,7 @@ clutter_actor_hide (ClutterActor *self)
  * clutter_actor_hide_all:
  * @self: a #ClutterActor
  *
- * Call hide() on all child actors (if any).
+ * Calls clutter_actor_hide() on all child actors (if any).
  *
  * Since: 0.2
  */
@@ -479,12 +568,15 @@ static void
 clutter_actor_real_pick (ClutterActor       *self,
                         const ClutterColor *color)
 {
+  /* the default implementation is just to paint a rectangle
+   * with the same size of the actor using the passed color
+   */
   if (clutter_actor_should_pick_paint (self))
     {
       cogl_color (color);
       cogl_rectangle (0, 0,
-                      clutter_actor_get_width(self),
-                      clutter_actor_get_height(self));
+                      clutter_actor_get_width (self),
+                      clutter_actor_get_height (self));
     }
 }
 
@@ -512,7 +604,7 @@ clutter_actor_pick (ClutterActor       *self,
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
   g_return_if_fail (color != NULL);
 
-  CLUTTER_ACTOR_GET_CLASS (self)->pick(self, color);
+  CLUTTER_ACTOR_GET_CLASS (self)->pick (self, color);
 }
 
 /**
@@ -543,6 +635,117 @@ clutter_actor_should_pick_paint (ClutterActor *self)
   return FALSE;
 }
 
+static void
+clutter_actor_real_get_preferred_width (ClutterActor *self,
+                                        ClutterUnit   for_height,
+                                        ClutterUnit  *min_width_p,
+                                        ClutterUnit  *natural_width_p)
+{
+  /* Default implementation is always 0x0, usually an actor
+   * using this default is relying on someone to set the
+   * request manually
+   */
+
+  if (min_width_p)
+    *min_width_p = 0;
+
+  if (natural_width_p)
+    *natural_width_p = 0;
+}
+
+static void
+clutter_actor_real_get_preferred_height (ClutterActor *self,
+                                         ClutterUnit   for_width,
+                                         ClutterUnit  *min_height_p,
+                                         ClutterUnit  *natural_height_p)
+{
+  /* Default implementation is always 0x0, usually an actor
+   * using this default is relying on someone to set the
+   * request manually
+   */
+
+  if (min_height_p)
+    *min_height_p = 0;
+
+  if (natural_height_p)
+    *natural_height_p = 0;
+}
+
+static void
+clutter_actor_store_old_geometry (ClutterActor    *self,
+                                  ClutterGeometry *geom)
+{
+  clutter_actor_get_geometry (self, geom);
+}
+
+static inline void
+clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
+                                          const ClutterGeometry *old)
+{
+  ClutterGeometry geom;
+
+  clutter_actor_get_geometry (self, &geom);
+
+  g_object_freeze_notify (G_OBJECT (self));
+
+  if (geom.x != old->x)
+    g_object_notify (G_OBJECT (self), "x");
+
+  if (geom.y != old->y)
+    g_object_notify (G_OBJECT (self), "y");
+
+  if (geom.width != old->width)
+    g_object_notify (G_OBJECT (self), "width");
+
+  if (geom.height != old->height)
+    g_object_notify (G_OBJECT (self), "height");
+
+  g_object_thaw_notify (G_OBJECT (self));
+}
+
+static void
+clutter_actor_real_allocate (ClutterActor          *self,
+                             const ClutterActorBox *box,
+                             gboolean               absolute_origin_changed)
+{
+  ClutterActorPrivate *priv = self->priv;
+  gboolean x1_changed, y1_changed, x2_changed, y2_changed;
+  ClutterGeometry old;
+
+  clutter_actor_store_old_geometry (self, &old);
+
+  x1_changed = priv->allocation.x1 != box->x1;
+  y1_changed = priv->allocation.y1 != box->y1;
+  x2_changed = priv->allocation.x2 != box->x2;
+  y2_changed = priv->allocation.y2 != box->y2;
+
+  priv->allocation = *box;
+  priv->needs_allocation = FALSE;
+
+  g_object_freeze_notify (G_OBJECT (self));
+
+  if (x1_changed || y1_changed || x2_changed || y2_changed)
+    g_object_notify (G_OBJECT (self), "allocation");
+
+  clutter_actor_notify_if_geometry_changed (self, &old);
+
+  g_object_thaw_notify (G_OBJECT (self));
+}
+
+static void
+clutter_actor_real_get_paint_area (ClutterActor    *self,
+                                   ClutterActorBox *box)
+{
+  /* Default implementation is to just return allocation,
+   * i.e. assume the actor draws inside its allocation.
+   *
+   * Note that the virtual get_paint_area method does not
+   * apply the transform; that is done in the wrapper
+   * function.
+   */
+  *box = self->priv->allocation;
+}
+
 /*
  * Utility functions for manipulating transformation matrix
  *
@@ -562,18 +765,18 @@ mtx_transform (ClutterFixed m[16],
     _z = *z;
     _w = *w;
 
-    /* We care lot about precission here, so have to use QMUL */
-    *x = CFX_QMUL (M (m,0,0), _x) + CFX_QMUL (M (m,0,1), _y) +
-        CFX_QMUL (M (m,0,2), _z) + CFX_QMUL (M (m,0,3), _w);
+    /* We care lot about precision here, so have to use QMUL */
+    *x = CFX_QMUL (M (m, 0, 0), _x) + CFX_QMUL (M (m, 0, 1), _y) +
+        CFX_QMUL (M (m, 0, 2), _z) + CFX_QMUL (M (m, 0, 3), _w);
 
-    *y = CFX_QMUL (M (m,1,0), _x) + CFX_QMUL (M (m,1,1), _y) +
-        CFX_QMUL (M (m,1,2), _z) + CFX_QMUL (M (m,1,3), _w);
+    *y = CFX_QMUL (M (m, 1, 0), _x) + CFX_QMUL (M (m, 1, 1), _y) +
+        CFX_QMUL (M (m, 1, 2), _z) + CFX_QMUL (M (m, 1, 3), _w);
 
-    *z = CFX_QMUL (M (m,2,0), _x) + CFX_QMUL (M (m,2,1), _y) +
-        CFX_QMUL (M (m,2,2), _z) + CFX_QMUL (M (m,2,3), _w);
+    *z = CFX_QMUL (M (m, 2, 0), _x) + CFX_QMUL (M (m, 2, 1), _y) +
+        CFX_QMUL (M (m, 2, 2), _z) + CFX_QMUL (M (m, 2, 3), _w);
 
-    *w = CFX_QMUL (M (m,3,0), _x) + CFX_QMUL (M (m,3,1), _y) +
-        CFX_QMUL (M (m,3,2), _z) + CFX_QMUL (M (m,3,3), _w);
+    *w = CFX_QMUL (M (m, 3, 0), _x) + CFX_QMUL (M (m, 3, 1), _y) +
+        CFX_QMUL (M (m, 3, 2), _z) + CFX_QMUL (M (m, 3, 3), _w);
 
     /* Specially for Matthew: was going to put a comment here, but could not
      * think of anything at all to say ;)
@@ -594,16 +797,12 @@ clutter_actor_transform_point_relative (ClutterActor *actor,
                                        ClutterUnit  *z,
                                        ClutterUnit  *w)
 {
-  ClutterFixed           mtx[16];
-  ClutterActorPrivate   *priv;
-
-  priv = actor->priv;
+  ClutterFixed mtx[16];
 
   cogl_push_matrix();
-  _clutter_actor_apply_modelview_transform_recursive (actor, ancestor);
 
+  _clutter_actor_apply_modelview_transform_recursive (actor, ancestor);
   cogl_get_modelview_matrix (mtx);
-
   mtx_transform (mtx, x, y, z, w);
 
   cogl_pop_matrix();
@@ -620,16 +819,12 @@ clutter_actor_transform_point (ClutterActor *actor,
                               ClutterUnit  *z,
                               ClutterUnit  *w)
 {
-  ClutterFixed           mtx[16];
-  ClutterActorPrivate   *priv;
-
-  priv = actor->priv;
+  ClutterFixed mtx[16];
 
   cogl_push_matrix();
-  _clutter_actor_apply_modelview_transform_recursive (actor, NULL);
 
+  _clutter_actor_apply_modelview_transform_recursive (actor, NULL);
   cogl_get_modelview_matrix (mtx);
-
   mtx_transform (mtx, x, y, z, w);
 
   cogl_pop_matrix();
@@ -638,8 +833,8 @@ clutter_actor_transform_point (ClutterActor *actor,
 /* Help macros to scale from OpenGL <-1,1> coordinates system to our
  * X-window based <0,window-size> coordinates
  */
-#define MTX_GL_SCALE_X(x,w,v1,v2) (CFX_MUL (((CFX_DIV ((x), (w)) + CFX_ONE) >> 1), (v1)) + (v2))
-#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - CFX_MUL (((CFX_DIV ((y), (w)) + CFX_ONE) >> 1), (v1)) + (v2))
+#define MTX_GL_SCALE_X(x,w,v1,v2) (CFX_QMUL (((CFX_QDIV ((x), (w)) + CFX_ONE) >> 1), (v1)) + (v2))
+#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - CFX_QMUL (((CFX_QDIV ((y), (w)) + CFX_ONE) >> 1), (v1)) + (v2))
 #define MTX_GL_SCALE_Z(z,w,v1,v2) (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
 
 /**
@@ -684,9 +879,9 @@ clutter_actor_apply_relative_transform_to_point (ClutterActor  *self,
    * The w[3] parameter should always be 1.0 here, so we ignore it; otherwise
    * we would have to divide the original verts with it.
    */
-  vertex->x = CFX_MUL ((point->x + CFX_ONE/2), v[2]);
-  vertex->y = CFX_MUL ((CFX_ONE/2 - point->y), v[3]);
-  vertex->z = CFX_MUL ((point->z + CFX_ONE/2), v[2]);
+  vertex->x = CFX_QMUL ((point->x + CFX_ONE / 2), v[2]);
+  vertex->y = CFX_QMUL ((CFX_ONE / 2 - point->y), v[3]);
+  vertex->z = CFX_QMUL ((point->z + CFX_ONE / 2), v[2]);
 }
 
 /**
@@ -739,17 +934,10 @@ clutter_actor_transform_vertices_relative (ClutterActor  *self,
 {
   ClutterFixed    mtx[16];
   ClutterFixed    _x, _y, _z, _w;
-  ClutterActorBox coords;
-
-  /*
-   * Need to query coords here, so that we get coorect values for actors that
-   * do not modify priv->coords.
-   */
-  clutter_actor_query_coords (self, &coords);
 
   cogl_push_matrix();
-  _clutter_actor_apply_modelview_transform_recursive (self, ancestor);
 
+  _clutter_actor_apply_modelview_transform_recursive (self, ancestor);
   cogl_get_modelview_matrix (mtx);
 
   _x = 0;
@@ -764,7 +952,7 @@ clutter_actor_transform_vertices_relative (ClutterActor  *self,
   verts[0].z = _z;
   w[0] = _w;
 
-  _x = coords.x2 - coords.x1;
+  _x = self->priv->allocation.x2 - self->priv->allocation.x1;
   _y = 0;
   _z = 0;
   _w = CFX_ONE;
@@ -777,7 +965,7 @@ clutter_actor_transform_vertices_relative (ClutterActor  *self,
   w[1] = _w;
 
   _x = 0;
-  _y = coords.y2 - coords.y1;
+  _y = self->priv->allocation.y2 - self->priv->allocation.y1;
   _z = 0;
   _w = CFX_ONE;
 
@@ -788,8 +976,8 @@ clutter_actor_transform_vertices_relative (ClutterActor  *self,
   verts[2].z = _z;
   w[2] = _w;
 
-  _x = coords.x2 - coords.x1;
-  _y = coords.y2 - coords.y1;
+  _x = self->priv->allocation.x2 - self->priv->allocation.x1;
+  _y = self->priv->allocation.y2 - self->priv->allocation.y1;
   _z = 0;
   _w = CFX_ONE;
 
@@ -814,13 +1002,6 @@ clutter_actor_transform_vertices (ClutterActor  *self,
 {
   ClutterFixed           mtx[16];
   ClutterFixed           _x, _y, _z, _w;
-  ClutterActorBox        coords;
-
-  /*
-   * Need to query coords here, so that we get coorect values for actors that
-   * do not modify priv->coords.
-   */
-  clutter_actor_query_coords (self, &coords);
 
   cogl_push_matrix();
   _clutter_actor_apply_modelview_transform_recursive (self, NULL);
@@ -839,7 +1020,7 @@ clutter_actor_transform_vertices (ClutterActor  *self,
   verts[0].z = _z;
   w[0] = _w;
 
-  _x = coords.x2 - coords.x1;
+  _x = self->priv->allocation.x2 - self->priv->allocation.x1;
   _y = 0;
   _z = 0;
   _w = CFX_ONE;
@@ -852,7 +1033,7 @@ clutter_actor_transform_vertices (ClutterActor  *self,
   w[1] = _w;
 
   _x = 0;
-  _y = coords.y2 - coords.y1;
+  _y = self->priv->allocation.y2 - self->priv->allocation.y1;
   _z = 0;
   _w = CFX_ONE;
 
@@ -863,8 +1044,8 @@ clutter_actor_transform_vertices (ClutterActor  *self,
   verts[2].z = _z;
   w[2] = _w;
 
-  _x = coords.x2 - coords.x1;
-  _y = coords.y2 - coords.y1;
+  _x = self->priv->allocation.x2 - self->priv->allocation.x1;
+  _y = self->priv->allocation.y2 - self->priv->allocation.y1;
   _z = 0;
   _w = CFX_ONE;
 
@@ -879,7 +1060,7 @@ clutter_actor_transform_vertices (ClutterActor  *self,
 }
 
 /**
- * clutter_actor_get_relative_vertices:
+ * clutter_actor_get_allocation_vertices:
  * @self: A #ClutterActor
  * @ancestor: A #ClutterActor to calculate the vertices against, or %NULL
  *   to use the default #ClutterStage
@@ -899,14 +1080,14 @@ clutter_actor_transform_vertices (ClutterActor  *self,
  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
  * this case, the coordinates returned will be the coordinates on
  * the stage before the projection is applied. This is different from
- * the behaviour of clutter_actor_get_vertices().
+ * the behaviour of clutter_actor_get_abs_allocation_vertices().
  *
  * Since: 0.6
  */
 void
-clutter_actor_get_relative_vertices (ClutterActor  *self,
-                                    ClutterActor  *ancestor,
-                                    ClutterVertex  verts[4])
+clutter_actor_get_allocation_vertices (ClutterActor  *self,
+                                       ClutterActor  *ancestor,
+                                       ClutterVertex  verts[4])
 {
   ClutterFixed           v[4];
   ClutterFixed           w[4];
@@ -933,23 +1114,8 @@ clutter_actor_get_relative_vertices (ClutterActor  *self,
   if (stage == NULL)
     stage = clutter_stage_get_default ();
 
-  clutter_stage_ensure_current (CLUTTER_STAGE(stage));
-
-  if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
-    {
-      ClutterPerspective perspective;
-
-      clutter_stage_get_perspectivex (CLUTTER_STAGE (stage), &perspective);
-
-      cogl_setup_viewport (clutter_actor_get_width (stage),
-                          clutter_actor_get_height (stage),
-                          perspective.fovy,
-                          perspective.aspect,
-                          perspective.z_near,
-                          perspective.z_far);
-
-      CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
-    }
+  clutter_stage_ensure_current (CLUTTER_STAGE (stage));
+  _clutter_stage_maybe_setup_viewport (CLUTTER_STAGE (stage));
 
   clutter_actor_transform_vertices_relative (self, ancestor, verts, w);
   cogl_get_viewport (v);
@@ -958,25 +1124,25 @@ clutter_actor_get_relative_vertices (ClutterActor  *self,
    * The w[3] parameter should always be 1.0 here, so we ignore it; otherwise
    * we would have to devide the original verts with it.
    */
-  verts[0].x = CFX_MUL ((verts[0].x + CFX_ONE/2), v[2]);
-  verts[0].y = CFX_MUL ((CFX_ONE/2 - verts[0].y), v[3]);
-  verts[0].z = CFX_MUL ((verts[0].z + CFX_ONE/2), v[2]);
+  verts[0].x = CFX_QMUL ((verts[0].x + CFX_ONE / 2), v[2]);
+  verts[0].y = CFX_QMUL ((CFX_ONE / 2 - verts[0].y), v[3]);
+  verts[0].z = CFX_QMUL ((verts[0].z + CFX_ONE / 2), v[2]);
 
-  verts[1].x = CFX_MUL ((verts[1].x + CFX_ONE/2), v[2]);
-  verts[1].y = CFX_MUL ((CFX_ONE/2 - verts[1].y), v[3]);
-  verts[1].z = CFX_MUL ((verts[1].z + CFX_ONE/2), v[2]);
+  verts[1].x = CFX_QMUL ((verts[1].x + CFX_ONE / 2), v[2]);
+  verts[1].y = CFX_QMUL ((CFX_ONE / 2 - verts[1].y), v[3]);
+  verts[1].z = CFX_QMUL ((verts[1].z + CFX_ONE / 2), v[2]);
 
-  verts[2].x = CFX_MUL ((verts[2].x + CFX_ONE/2), v[2]);
-  verts[2].y = CFX_MUL ((CFX_ONE/2 - verts[2].y), v[3]);
-  verts[2].z = CFX_MUL ((verts[2].z + CFX_ONE/2), v[2]);
+  verts[2].x = CFX_QMUL ((verts[2].x + CFX_ONE / 2), v[2]);
+  verts[2].y = CFX_QMUL ((CFX_ONE / 2 - verts[2].y), v[3]);
+  verts[2].z = CFX_QMUL ((verts[2].z + CFX_ONE / 2), v[2]);
 
-  verts[3].x = CFX_MUL ((verts[3].x + CFX_ONE/2), v[2]);
-  verts[3].y = CFX_MUL ((CFX_ONE/2 - verts[3].y), v[3]);
-  verts[3].z = CFX_MUL ((verts[3].z + CFX_ONE/2), v[2]);
+  verts[3].x = CFX_QMUL ((verts[3].x + CFX_ONE / 2), v[2]);
+  verts[3].y = CFX_QMUL ((CFX_ONE / 2 - verts[3].y), v[3]);
+  verts[3].z = CFX_QMUL ((verts[3].z + CFX_ONE / 2), v[2]);
 }
 
 /**
- * clutter_actor_get_vertices:
+ * clutter_actor_get_abs_allocation_vertices:
  * @self: A #ClutterActor
  * @verts: Pointer to a location of an array of 4 #ClutterVertex where to
  * store the result.
@@ -994,8 +1160,8 @@ clutter_actor_get_relative_vertices (ClutterActor  *self,
  * Since: 0.4
  */
 void
-clutter_actor_get_vertices (ClutterActor  *self,
-                            ClutterVertex  verts[4])
+clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
+                                           ClutterVertex  verts[4])
 {
   ClutterFixed           mtx_p[16];
   ClutterFixed           v[4];
@@ -1022,23 +1188,8 @@ clutter_actor_get_vertices (ClutterActor  *self,
   if (stage == NULL)
     stage = clutter_stage_get_default ();
 
-  clutter_stage_ensure_current (CLUTTER_STAGE(stage));
-
-  if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
-    {
-      ClutterPerspective perspective;
-
-      clutter_stage_get_perspectivex (CLUTTER_STAGE (stage), &perspective);
-
-      cogl_setup_viewport (clutter_actor_get_width (stage),
-                          clutter_actor_get_height (stage),
-                          perspective.fovy,
-                          perspective.aspect,
-                          perspective.z_near,
-                          perspective.z_far);
-
-      CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
-    }
+  clutter_stage_ensure_current (CLUTTER_STAGE (stage));
+  _clutter_stage_maybe_setup_viewport (CLUTTER_STAGE (stage));
 
   clutter_actor_transform_vertices (self, verts, w);
   cogl_get_projection_matrix (mtx_p);
@@ -1092,17 +1243,15 @@ clutter_actor_get_vertices (ClutterActor  *self,
  * of the caller to do so as appropriate
  */
 static void
-_clutter_actor_apply_modelview_transform (ClutterActor * self)
+_clutter_actor_apply_modelview_transform (ClutterActor *self)
 {
   ClutterActorPrivate *priv = self->priv;
   gboolean             is_stage = CLUTTER_IS_STAGE (self);
 
   if (!is_stage)
-    {
-      cogl_translatex (CLUTTER_UNITS_TO_FIXED (priv->coords.x1),
-                      CLUTTER_UNITS_TO_FIXED (priv->coords.y1),
-                      0);
-    }
+    cogl_translatex (CLUTTER_UNITS_TO_FIXED (priv->allocation.x1),
+                    CLUTTER_UNITS_TO_FIXED (priv->allocation.y1),
+                    0);
 
   /*
    * because the rotation involves translations, we must scale before
@@ -1110,11 +1259,8 @@ _clutter_actor_apply_modelview_transform (ClutterActor * self)
    * the translations included in the rotation are not scaled and so the
    * entire object will move on the screen as a result of rotating it).
    */
-  if (priv->scale_x != CFX_ONE ||
-      priv->scale_y != CFX_ONE)
-    {
-      cogl_scale (priv->scale_x, priv->scale_y);
-    }
+  if (priv->scale_x != CFX_ONE || priv->scale_y != CFX_ONE)
+    cogl_scale (priv->scale_x, priv->scale_y);
 
    if (priv->rzang)
     {
@@ -1156,11 +1302,9 @@ _clutter_actor_apply_modelview_transform (ClutterActor * self)
     }
 
   if (!is_stage && (priv->anchor_x || priv->anchor_y))
-    {
-      cogl_translatex (CLUTTER_UNITS_TO_FIXED (-priv->anchor_x),
-                      CLUTTER_UNITS_TO_FIXED (-priv->anchor_y),
-                      0);
-    }
+    cogl_translatex (CLUTTER_UNITS_TO_FIXED (-priv->anchor_x),
+                    CLUTTER_UNITS_TO_FIXED (-priv->anchor_y),
+                    0);
 
   if (priv->z)
     cogl_translatex (0, 0, priv->z);
@@ -1221,6 +1365,7 @@ clutter_actor_paint (ClutterActor *self)
   ClutterMainContext *context;
 
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
   priv = self->priv;
 
   if (!CLUTTER_ACTOR_IS_REALIZED (self))
@@ -1273,118 +1418,6 @@ clutter_actor_paint (ClutterActor *self)
   cogl_pop_matrix();
 }
 
-static void
-clutter_actor_real_request_coords (ClutterActor    *self,
-                                   ClutterActorBox *box)
-{
-  self->priv->coords = *box;
-}
-
-/**
- * clutter_actor_request_coords:
- * @self: A #ClutterActor
- * @box: A #ClutterActorBox with the new coordinates, in ClutterUnits
- *
- * Requests new untransformed coordinates for the bounding box of
- * a #ClutterActor. The coordinates must be relative to the current
- * parent of the actor.
- *
- * This function should not be called directly by applications;
- * instead, the various position/geometry methods should be used.
- *
- * Note: Actors overriding the ClutterActor::request_coords() virtual
- * function should always chain up to the parent class request_coords()
- * method. Actors should override this function only if they need to
- * recompute some internal state or need to reposition their children.
- */
-void
-clutter_actor_request_coords (ClutterActor    *self,
-                             ClutterActorBox *box)
-{
-  ClutterActorPrivate *priv;
-  gboolean x_change, y_change, width_change, height_change;
-
-  g_return_if_fail (CLUTTER_IS_ACTOR (self));
-  g_return_if_fail (box != NULL);
-
-  priv = self->priv;
-
-  /* avoid calling request coords if the coordinates did not change */
-  x_change      = (priv->coords.x1 != box->x1);
-  y_change      = (priv->coords.y1 != box->y1);
-  width_change  = ((priv->coords.x2 - priv->coords.x1) != (box->x2 - box->x1));
-  height_change = ((priv->coords.y2 - priv->coords.y1) != (box->y2 - box->y1));
-
-  if (x_change || y_change || width_change || height_change)
-    {
-      g_object_ref (self);
-      g_object_freeze_notify (G_OBJECT (self));
-
-      CLUTTER_ACTOR_GET_CLASS (self)->request_coords (self, box);
-
-      if (CLUTTER_ACTOR_IS_VISIBLE (self))
-       clutter_actor_queue_redraw (self);
-
-      if (x_change)
-       g_object_notify (G_OBJECT (self), "x");
-
-      if (y_change)
-       g_object_notify (G_OBJECT (self), "y");
-
-      if (width_change)
-       g_object_notify (G_OBJECT (self), "width");
-
-      if (height_change)
-       g_object_notify (G_OBJECT (self), "height");
-
-      g_object_thaw_notify (G_OBJECT (self));
-      g_object_unref (self);
-    }
-}
-
-/**
- * clutter_actor_query_coords:
- * @self: A #ClutterActor
- * @box: A location to store the actor's #ClutterActorBox
- *
- * Requests the untransformed co-ordinates (in #ClutterUnit<!-- -->s) for
- * the #ClutterActor, relative to any parent.
- *
- * This function should not be called directly by applications.
- * The various position/geometry methods should be used instead.
- */
-void
-clutter_actor_query_coords (ClutterActor    *self,
-                           ClutterActorBox *box)
-{
-  ClutterActorClass *klass;
-
-  g_return_if_fail (CLUTTER_IS_ACTOR (self));
-  g_return_if_fail (box != NULL);
-
-  klass = CLUTTER_ACTOR_GET_CLASS (self);
-
-  box->x1 = self->priv->coords.x1;
-  box->y1 = self->priv->coords.y1;
-  box->x2 = self->priv->coords.x2;
-  box->y2 = self->priv->coords.y2;
-
-  if (klass->query_coords)
-    {
-      /* FIXME: This is kind of a cludge - we pass out *private*
-       *        co-ords down to any subclasses so they can modify
-       *        we then resync any changes. Needed for group class.
-       *        Need to figure out nicer way.
-      */
-      klass->query_coords(self, box);
-
-      self->priv->coords.x1 = box->x1;
-      self->priv->coords.y1 = box->y1;
-      self->priv->coords.x2 = box->x2;
-      self->priv->coords.y2 = box->y2;
-    }
-}
-
 /* fixed point, unit based rotation setter, to be used by
  * set_property() so that we don't lose precision in the
  * center coordinates by converting them to and from units
@@ -1419,6 +1452,7 @@ clutter_actor_set_rotation_internal (ClutterActor      *self,
       g_object_notify (G_OBJECT (self), "rotation-angle-y");
       g_object_notify (G_OBJECT (self), "rotation-center-y");
       break;
+
     case CLUTTER_Z_AXIS:
       priv->rzang = angle;
       priv->rzx = center_x;
@@ -1462,6 +1496,42 @@ clutter_actor_set_property (GObject      *object,
     case PROP_HEIGHT:
       clutter_actor_set_height (actor, g_value_get_int (value));
       break;
+    case PROP_FIXED_X:
+      clutter_actor_set_xu (actor, clutter_value_get_unit (value));
+      break;
+    case PROP_FIXED_Y:
+      clutter_actor_set_yu (actor, clutter_value_get_unit (value));
+      break;
+    case PROP_FIXED_POSITION_SET:
+      clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
+      break;
+    case PROP_MIN_WIDTH:
+      clutter_actor_set_min_width (actor, clutter_value_get_unit (value));
+      break;
+    case PROP_MIN_HEIGHT:
+      clutter_actor_set_min_height (actor, clutter_value_get_unit (value));
+      break;
+    case PROP_NATURAL_WIDTH:
+      clutter_actor_set_natural_width (actor, clutter_value_get_unit (value));
+      break;
+    case PROP_NATURAL_HEIGHT:
+      clutter_actor_set_natural_height (actor, clutter_value_get_unit (value));
+      break;
+    case PROP_MIN_WIDTH_SET:
+      clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
+      break;
+    case PROP_MIN_HEIGHT_SET:
+      clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
+      break;
+    case PROP_NATURAL_WIDTH_SET:
+      clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
+      break;
+    case PROP_NATURAL_HEIGHT_SET:
+      clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
+      break;
+    case PROP_REQUEST_MODE:
+      clutter_actor_set_request_mode (actor, g_value_get_enum (value));
+      break;
     case PROP_DEPTH:
       clutter_actor_set_depth (actor, g_value_get_int (value));
       break;
@@ -1620,6 +1690,45 @@ clutter_actor_get_property (GObject    *object,
     case PROP_HEIGHT:
       g_value_set_int (value, clutter_actor_get_height (actor));
       break;
+    case PROP_FIXED_X:
+      clutter_value_set_unit (value, priv->fixed_x);
+      break;
+    case PROP_FIXED_Y:
+      clutter_value_set_unit (value, priv->fixed_y);
+      break;
+    case PROP_FIXED_POSITION_SET:
+      g_value_set_boolean (value, priv->position_set);
+      break;
+    case PROP_MIN_WIDTH:
+      clutter_value_set_unit (value, priv->request_min_width);
+      break;
+    case PROP_MIN_HEIGHT:
+      clutter_value_set_unit (value, priv->request_min_height);
+      break;
+    case PROP_NATURAL_WIDTH:
+      clutter_value_set_unit (value, priv->request_natural_width);
+      break;
+    case PROP_NATURAL_HEIGHT:
+      clutter_value_set_unit (value, priv->request_natural_height);
+      break;
+    case PROP_MIN_WIDTH_SET:
+      g_value_set_boolean (value, priv->min_width_set);
+      break;
+    case PROP_MIN_HEIGHT_SET:
+      g_value_set_boolean (value, priv->min_height_set);
+      break;
+    case PROP_NATURAL_WIDTH_SET:
+      g_value_set_boolean (value, priv->natural_width_set);
+      break;
+    case PROP_NATURAL_HEIGHT_SET:
+      g_value_set_boolean (value, priv->natural_height_set);
+      break;
+    case PROP_REQUEST_MODE:
+      g_value_set_enum (value, priv->request_mode);
+      break;
+    case PROP_ALLOCATION:
+      g_value_set_boxed (value, &priv->allocation);
+      break;
     case PROP_DEPTH:
       g_value_set_int (value, clutter_actor_get_depth (actor));
       break;
@@ -1765,111 +1874,382 @@ clutter_actor_class_init (ClutterActorClass *klass)
   /**
    * ClutterActor:x:
    *
-   * X coordinate of the actor.
+   * X coordinate of the actor in pixels. If written, forces a fixed
+   * position for the actor. If read, returns the fixed position if any,
+   * otherwise the allocation if available, otherwise 0.
    */
   g_object_class_install_property (object_class,
-                                   PROP_X,
-                                   g_param_spec_int ("x",
-                                                     "X co-ord",
-                                                     "X co-ord of actor",
-                                                     -G_MAXINT, G_MAXINT,
-                                                     0,
-                                                     CLUTTER_PARAM_READWRITE));
+    PROP_X,
+    g_param_spec_int ("x",
+                      "X coordinate",
+                      "X coordinate of the actor",
+                      -G_MAXINT, G_MAXINT,
+                      0,
+                      CLUTTER_PARAM_READWRITE));
   /**
    * ClutterActor:y:
    *
-   * Y coordinate of the actor.
+   * Y coordinate of the actor in pixels. If written, forces a fixed
+   * position for the actor.  If read, returns the fixed position if
+   * any, otherwise the allocation if available, otherwise 0.
    */
   g_object_class_install_property (object_class,
-                                   PROP_Y,
-                                   g_param_spec_int ("y",
-                                                     "Y co-ord",
-                                                     "Y co-ord of actor",
-                                                     -G_MAXINT, G_MAXINT,
-                                                     0,
-                                                     CLUTTER_PARAM_READWRITE));
+    PROP_Y,
+    g_param_spec_int ("y",
+                      "Y coordinate",
+                      "Y coordinate of the actor",
+                      -G_MAXINT, G_MAXINT,
+                      0,
+                      CLUTTER_PARAM_READWRITE));
   /**
    * ClutterActor:width:
    *
-   * Width of the actor (in pixels).
+   * Width of the actor (in pixels). If written, forces the minimum and
+   * natural size request of the actor to the given width. If read, returns
+   * the allocated width if available, otherwise the width request.
    */
   g_object_class_install_property (object_class,
-                                   PROP_WIDTH,
-                                   g_param_spec_int ("width",
-                                                     "Width",
-                                                     "Width of actor in pixels",
-                                                     0, G_MAXINT,
-                                                     0,
-                                                     CLUTTER_PARAM_READWRITE));
+    PROP_WIDTH,
+    g_param_spec_int ("width",
+                      "Width",
+                      "Width of the actor",
+                      0, G_MAXINT,
+                      0,
+                      CLUTTER_PARAM_READWRITE));
   /**
    * ClutterActor:height:
    *
-   * Height of the actor (in pixels).
+   * Height of the actor (in pixels).  If written, forces the minimum and
+   * natural size request of the actor to the given height. If read, returns
+   * the allocated height if available, otherwise the height request.
    */
   g_object_class_install_property (object_class,
-                                   PROP_HEIGHT,
-                                   g_param_spec_int ("height",
-                                                     "Height",
-                                                     "Height of actor in pixels",
-                                                     0, G_MAXINT,
-                                                     0,
-                                                     CLUTTER_PARAM_READWRITE));
+    PROP_HEIGHT,
+    g_param_spec_int ("height",
+                      "Height",
+                      "Height of the actor",
+                      0, G_MAXINT,
+                      0,
+                      CLUTTER_PARAM_READWRITE));
+
   /**
-   * ClutterActor:depth:
+   * ClutterActor:fixed-x
    *
-   * Depth of the actor.
+   * The fixed X position of the actor in ClutterUnit<!-- -->s. Writing this
+   * property sets the fixed-position-set property as well, as a side effect.
    *
-   * Since: 0.6
+   * Since: 0.8
    */
-  g_object_class_install_property (object_class,
-                                   PROP_DEPTH,
-                                   g_param_spec_int ("depth",
-                                                     "Depth",
-                                                     "Depth of actor",
-                                                     -G_MAXINT, G_MAXINT,
-                                                     0,
-                                                     CLUTTER_PARAM_READWRITE));
+  g_object_class_install_property
+                   (object_class,
+                    PROP_FIXED_X,
+                    clutter_param_spec_unit ("fixed-x",
+                                             "Fixed X",
+                                             "Forced X position of the actor",
+                                             CLUTTER_MINUNIT, CLUTTER_MAXUNIT,
+                                             0,
+                                             CLUTTER_PARAM_READWRITE));
+
   /**
-   * ClutterActor:opacity:
+   * ClutterActor:fixed-y
    *
-   * Opacity of the actor.
+   * The fixed Y position of the actor in ClutterUnit<!-- -->s. Writing
+   * this property sets the fixed-position-set property as well, as a side
+   * effect.
+   *
+   * Since: 0.8
    */
-  g_object_class_install_property (object_class,
-                                   PROP_OPACITY,
-                                   g_param_spec_uchar ("opacity",
-                                                       "Opacity",
-                                                       "Opacity of actor",
-                                                       0, 0xff,
-                                                       0xff,
-                                                       CLUTTER_PARAM_READWRITE));
+  g_object_class_install_property
+                   (object_class,
+                    PROP_FIXED_Y,
+                    clutter_param_spec_unit ("fixed-y",
+                                             "Fixed Y",
+                                             "Forced Y position of the actor",
+                                             CLUTTER_MINUNIT, CLUTTER_MAXUNIT,
+                                             0,
+                                             CLUTTER_PARAM_READWRITE));
   /**
-   * ClutterActor:visible:
+   * ClutterActor:fixed-position-set
    *
-   * Whether the actor is visible or not.
+   * This flag controls whether the fixed-x and fixed-y properties are used.
+   *
+   * Since: 0.8
    */
-  g_object_class_install_property (object_class,
-                                   PROP_VISIBLE,
-                                   g_param_spec_boolean ("visible",
-                                                         "Visible",
-                                                         "Whether the actor is visible or not",
-                                                         FALSE,
-                                                         CLUTTER_PARAM_READWRITE));
+  g_object_class_install_property
+        (object_class,
+         PROP_FIXED_POSITION_SET,
+         g_param_spec_boolean ("fixed-position-set",
+                               "Fixed position set",
+                               "Whether to use fixed positioning for the actor",
+                               FALSE,
+                               CLUTTER_PARAM_READWRITE));
   /**
-   * ClutterActor:reactive:
+   * ClutterActor:min-width
    *
-   * Whether the actor is reactive to events or not.
+   * A forced minimum width request for the actor, in ClutterUnit<!-- -->s.
+   * Writing this property sets the min-width-set property as well, as a side
+   * effect. This property overrides the usual width request of the actor.
    *
-   * Since: 0.6
+   * Since: 0.8
    */
-  g_object_class_install_property (object_class,
-                                   PROP_REACTIVE,
-                                   g_param_spec_boolean ("reactive",
-                                                         "Reactive",
-                                                         "Whether the actor is reactive to events or not",
-                                                         FALSE,
-                                                         CLUTTER_PARAM_READWRITE));
+  g_object_class_install_property 
+        (object_class,
+         PROP_MIN_WIDTH,
+         clutter_param_spec_unit ("min-width",
+                                  "Min Width",
+                                  "Forced minimum width request for the actor",
+                                  0, CLUTTER_MAXUNIT,
+                                  0,
+                                  CLUTTER_PARAM_READWRITE));
   /**
-   * ClutterActor:has-clip:
+   * ClutterActor:min-height
+   *
+   * A forced minimum height request for the actor, in
+   * ClutterUnit<!-- -->s. Writing this property sets the min-height-set
+   * property as well, as a side effect. This property overrides the usual
+   * height request of the actor.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property
+        (object_class,
+         PROP_MIN_HEIGHT,
+         clutter_param_spec_unit ("min-height",
+                                  "Min Height",
+                                  "Forced minimum height request for the actor",
+                                  0, CLUTTER_MAXUNIT,
+                                  0,
+                                  CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:natural-width
+   *
+   * A forced natural width request for the actor, in ClutterUnit<!-- -->s.
+   * Writing this property sets the natural-width-set property as
+   * well, as a side effect. This property overrides the usual width request
+   * of the actor.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property
+        (object_class,
+         PROP_NATURAL_WIDTH,
+         clutter_param_spec_unit ("natural-width",
+                                  "Natural Width",
+                                  "Forced natural width request for the actor",
+                                  0, CLUTTER_MAXUNIT,
+                                  0,
+                                  CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:natural-height
+   *
+   * A forced natural height request for the actor, in ClutterUnit<!-- -->s.
+   * Writing this property sets the natural-height-set property as well, as
+   * a side effect. This property overrides the usual height request
+   * of the actor.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property
+        (object_class,
+         PROP_NATURAL_HEIGHT,
+         clutter_param_spec_unit ("natural-height",
+                                  "Natural Height",
+                                  "Forced natural height request for the actor",
+                                  0, CLUTTER_MAXUNIT,
+                                  0,
+                                  CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:min-width-set
+   *
+   * This flag controls whether the min-width property is used.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property
+        (object_class,
+         PROP_MIN_WIDTH_SET,
+         g_param_spec_boolean ("min-width-set",
+                               "Minimum width set",
+                               "Whether to use the min-width property",
+                               FALSE,
+                               CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:min-height-set
+   *
+   * This flag controls whether the min-height property is used.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property
+        (object_class,
+         PROP_MIN_HEIGHT_SET,
+         g_param_spec_boolean ("min-height-set",
+                               "Minimum height set",
+                               "Whether to use the min-height property",
+                               FALSE,
+                               CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:natural-width-set
+   *
+   * This flag controls whether the natural-width property is used.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property
+        (object_class,
+         PROP_NATURAL_WIDTH_SET,
+         g_param_spec_boolean ("natural-width-set",
+                               "Natural width set",
+                               "Whether to use the natural-width property",
+                               FALSE,
+                               CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:natural-height-set
+   *
+   * This flag controls whether the natural-height property is used.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property
+        (object_class,
+         PROP_NATURAL_HEIGHT_SET,
+         g_param_spec_boolean ("natural-height-set",
+                               "Natural height set",
+                               "Whether to use the natural-height property",
+                               FALSE,
+                               CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:allocation:
+   *
+   * The allocation for the actor, in ClutterUnit<!-- -->s. This is
+   * read-only, but you might monitor this property to know when an
+   * actor moves or resizes.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_ALLOCATION,
+                                   g_param_spec_boxed ("allocation",
+                                                       "Allocation",
+                                                       "The actor's allocation",
+                                                       CLUTTER_TYPE_ACTOR_BOX,
+                                                       CLUTTER_PARAM_READABLE));
+  /**
+   * ClutterActor:request-mode:
+   *
+   * Request mode for the #ClutterActor. The request mode determines the
+   * type of geometry management used by the actor, either height for width
+   * (the default) or width for height.
+   *
+   * For actors implementing height for width, the parent container should get
+   * the preferred width first, and then the preferred height for that width.
+   *
+   * For actors implementing width for height, the parent container should get
+   * the preferred height first, and then the preferred width for that height.
+   *
+   * For instance:
+   *
+   * |[
+   *   ClutterRequestMode mode;
+   *   ClutterUnit natural_width, min_width;
+   *   ClutterUnit natural_height, min_height;
+   *
+   *   g_object_get (G_OBJECT (child), "request-mode", &amp;mode, NULL);
+   *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
+   *     {
+   *       clutter_actor_get_preferred_width (child, -1,
+   *                                          &amp;min_width,
+   *                                          &amp;natural_width);
+   *       clutter_actor_get_preferred_height (child, natural_width,
+   *                                           &amp;min_height,
+   *                                           &amp;natural_height);
+   *     }
+   *   else
+   *     {
+   *       clutter_actor_get_preferred_height (child, -1,
+   *                                           &amp;min_height,
+   *                                           &amp;natural_height);
+   *       clutter_actor_get_preferred_width (child, natural_height,
+   *                                          &amp;min_width,
+   *                                          &amp;natural_width);
+   *     }
+   * ]|
+   *
+   * will retrieve the minimum and natural width and height depending on the
+   * preferred request mode of the #ClutterActor "child".
+   *
+   * The clutter_actor_get_preferred_size() function will implement this
+   * check for you.
+   *
+   * Since: 0.8
+   */
+  g_object_class_install_property (object_class,
+    PROP_REQUEST_MODE,
+    g_param_spec_enum ("request-mode",
+                       "Request Mode",
+                       "The actor's request mode",
+                       CLUTTER_TYPE_REQUEST_MODE,
+                       CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
+                       CLUTTER_PARAM_READWRITE));
+
+  /**
+   * ClutterActor:depth:
+   *
+   * Depth of the actor.
+   *
+   * Since: 0.6
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_DEPTH,
+                                   g_param_spec_int ("depth",
+                                                     "Depth",
+                                                     "Depth of actor",
+                                                     -G_MAXINT, G_MAXINT,
+                                                     0,
+                                                     CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:opacity:
+   *
+   * Opacity of the actor.
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_OPACITY,
+                                   g_param_spec_uchar ("opacity",
+                                                       "Opacity",
+                                                       "Opacity of actor",
+                                                       0, 0xff,
+                                                       0xff,
+                                                       CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:visible:
+   *
+   * Whether the actor is visible or not.
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_VISIBLE,
+                                   g_param_spec_boolean ("visible",
+                                                         "Visible",
+                                                         "Whether the actor is visible or not",
+                                                         FALSE,
+                                                         CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:reactive:
+   *
+   * Whether the actor is reactive to events or not.
+   *
+   * Since: 0.6
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_REACTIVE,
+                                   g_param_spec_boolean ("reactive",
+                                                         "Reactive",
+                                                         "Whether the actor "
+                                                         "is reactive to "
+                                                         "events or not",
+                                                         FALSE,
+                                                         CLUTTER_PARAM_READWRITE));
+  /**
+   * ClutterActor:has-clip:
    *
    * Whether the actor has the clip property set or not.
    */
@@ -1877,7 +2257,9 @@ clutter_actor_class_init (ClutterActorClass *klass)
                                    PROP_HAS_CLIP,
                                    g_param_spec_boolean ("has-clip",
                                                          "Has Clip",
-                                                         "Whether the actor has a clip set or not",
+                                                         "Whether the actor "
+                                                         "has a clip set or "
+                                                         "not",
                                                          FALSE,
                                                          CLUTTER_PARAM_READABLE));
   /**
@@ -1889,7 +2271,8 @@ clutter_actor_class_init (ClutterActorClass *klass)
                                    PROP_CLIP,
                                    g_param_spec_boxed ("clip",
                                                        "Clip",
-                                                       "The clip region for the actor",
+                                                       "The clip region for "
+                                                       "the actor",
                                                        CLUTTER_TYPE_GEOMETRY,
                                                        CLUTTER_PARAM_READWRITE));
   /**
@@ -2489,14 +2872,16 @@ clutter_actor_class_init (ClutterActorClass *klass)
   klass->hide = clutter_actor_real_hide;
   klass->hide_all = clutter_actor_hide;
   klass->pick = clutter_actor_real_pick;
-  klass->request_coords = clutter_actor_real_request_coords;
+  klass->get_preferred_width = clutter_actor_real_get_preferred_width;
+  klass->get_preferred_height = clutter_actor_real_get_preferred_height;
+  klass->allocate = clutter_actor_real_allocate;
+  klass->get_paint_area = clutter_actor_real_get_paint_area;
 }
 
 static void
 clutter_actor_init (ClutterActor *self)
 {
   ClutterActorPrivate *priv;
-  ClutterActorBox box = { 0, };
 
   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
 
@@ -2509,9 +2894,11 @@ clutter_actor_init (ClutterActor *self)
   priv->shader_data  = NULL;
   priv->show_on_set_parent = TRUE;
 
-  memset (priv->clip, 0, sizeof (ClutterUnit) * 4);
+  priv->needs_width_request  = TRUE;
+  priv->needs_height_request = TRUE;
+  priv->needs_allocation     = TRUE;
 
-  clutter_actor_request_coords (self, &box);
+  memset (priv->clip, 0, sizeof (ClutterUnit) * 4);
 }
 
 /**
@@ -2578,86 +2965,551 @@ clutter_actor_queue_redraw (ClutterActor *self)
 }
 
 /**
- * clutter_actor_set_geometry:
+ * clutter_actor_queue_relayout:
  * @self: A #ClutterActor
- * @geometry: A #ClutterGeometry
  *
- * Sets the actor's untransformed geometry in pixels relative to any
- * parent actor.
+ * Indicates that the actor's size request or other layout-affecting
+ * properties may have changed. This function is used inside #ClutterActor
+ * subclass implementations, not by applications directly.
+ *
+ * Queueing a new layout automatically queues a redraw as well.
+ *
+ * Since: 0.8
  */
 void
-clutter_actor_set_geometry (ClutterActor          *self,
-                           const ClutterGeometry *geometry)
+clutter_actor_queue_relayout (ClutterActor *self)
 {
-  ClutterActorBox box;
+  ClutterActorPrivate *priv;
+
+  priv = self->priv;
+
+  if (priv->needs_width_request &&
+      priv->needs_height_request &&
+      priv->needs_allocation)
+    return; /* save some cpu cycles */
+
+  self->priv->needs_width_request  = TRUE;
+  self->priv->needs_height_request = TRUE;
+  self->priv->needs_allocation     = TRUE;
 
-  box.x1 = CLUTTER_UNITS_FROM_INT (geometry->x);
-  box.y1 = CLUTTER_UNITS_FROM_INT (geometry->y);
-  box.x2 = CLUTTER_UNITS_FROM_INT (geometry->x + geometry->width);
-  box.y2 = CLUTTER_UNITS_FROM_INT (geometry->y + geometry->height);
+  /* always repaint also */
+  if (CLUTTER_ACTOR_IS_VISIBLE (self))
+    clutter_actor_queue_redraw (self);
 
-  clutter_actor_request_coords (self, &box);
+  /* We need to go all the way up the hierarchy */
+  if (self->priv->parent_actor)
+    clutter_actor_queue_relayout (self->priv->parent_actor);
 }
 
 /**
- * clutter_actor_get_geometry:
+ * clutter_actor_get_preferred_size:
+ * @self: a #ClutterActor
+ * @min_width_p: return location for the minimum width, or %NULL
+ * @min_height_p: return location for the minimum height, or %NULL
+ * @natural_width_p: return location for the natural width, or %NULL
+ * @natural_height_p: return location for the natural height, or %NULL
+ *
+ * Computes the preferred minimum and natural size of an actor, taking into
+ * account the actor's geometry management (either height-for-width
+ * or width-for-height).
+ *
+ * The width and height used to compute the preferred height and preferred
+ * width are the actor's natural ones.
+ *
+ * If you need to control the height for the preferred width, or the width for
+ * the preferred height, you should use clutter_actor_get_preferred_width()
+ * and clutter_actor_get_preferred_height(), and check the actor's preferred
+ * geometry management using the #ClutterActor:request-mode property.
+ *
+ * Since: 0.8
+ */
+void
+clutter_actor_get_preferred_size (ClutterActor *self,
+                                  ClutterUnit  *min_width_p,
+                                  ClutterUnit  *min_height_p,
+                                  ClutterUnit  *natural_width_p,
+                                  ClutterUnit  *natural_height_p)
+{
+  ClutterActorPrivate *priv;
+  ClutterUnit for_width, for_height;
+  ClutterUnit min_width, min_height;
+  ClutterUnit natural_width, natural_height;
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  priv = self->priv;
+
+  for_width = for_height = 0;
+  min_width = min_height = 0;
+  natural_width = natural_height = 0;
+
+  if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
+    {
+      clutter_actor_get_preferred_width (self, -1,
+                                         &min_width,
+                                         &natural_width);
+      clutter_actor_get_preferred_height (self, natural_width,
+                                          &min_height,
+                                          &natural_height);
+    }
+  else
+    {
+      clutter_actor_get_preferred_height (self, -1,
+                                          &min_height,
+                                          &natural_height);
+      clutter_actor_get_preferred_width (self, natural_height,
+                                         &min_width,
+                                         &natural_width);
+    }
+
+  if (min_width_p)
+    *min_width_p = min_width;
+
+  if (min_height_p)
+    *min_height_p = min_height;
+
+  if (natural_width_p)
+    *natural_width_p = natural_width;
+
+  if (natural_height_p)
+    *natural_height_p = natural_height;
+}
+
+/**
+ * clutter_actor_get_preferred_width:
  * @self: A #ClutterActor
- * @geometry: A location to store actors #ClutterGeometry
+ * @for_height: available height when computing the preferred width,
+ *   or a negative value to indicate that no height is defined
+ * @min_width_p: return location for min width, or %NULL
+ * @natural_width_p: return location for min width, or %NULL
  *
- * Gets the actor's untransformed geometry in pixels relative to any
- * parent actor.
+ * Computes the requested minimum and natural widths for an actor,
+ * optionally depending on the specified height, or if they are
+ * already computed, returns the cached values.
+ *
+ * An actor may not get its request - depending on the layout
+ * manager that's in effect.
+ *
+ * A request should not incorporate the actor's scale or anchor point;
+ * those transformations do not affect layout, only rendering.
+ *
+ * Since: 0.8
  */
 void
-clutter_actor_get_geometry (ClutterActor    *self,
-                           ClutterGeometry *geometry)
+clutter_actor_get_preferred_width (ClutterActor *self,
+                                   ClutterUnit   for_height,
+                                   ClutterUnit  *min_width_p,
+                                   ClutterUnit  *natural_width_p)
+{
+  ClutterActorClass *klass;
+  ClutterActorPrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  klass = CLUTTER_ACTOR_GET_CLASS (self);
+  priv = self->priv;
+
+  if (priv->needs_width_request ||
+      priv->request_width_for_height != for_height)
+    {
+      ClutterUnit min_width, natural_width;
+
+      min_width = natural_width = 0;
+
+      klass->get_preferred_width (self, for_height,
+                                  &min_width,
+                                  &natural_width);
+
+      if (natural_width < min_width)
+        {
+          g_warning ("Actor of type %s reported a natural width of %d (%d px) "
+                     "lower than min width %d (%d px)",
+                     G_OBJECT_TYPE_NAME (self),
+                     natural_width, CLUTTER_UNITS_TO_DEVICE (natural_width),
+                     min_width, CLUTTER_UNITS_TO_DEVICE (min_width));
+        }
+
+      if (!priv->min_width_set)
+        priv->request_min_width = min_width;
+
+      if (!priv->natural_width_set)
+        priv->request_natural_width = natural_width;
+
+      priv->request_width_for_height = for_height;
+      priv->needs_width_request = FALSE;
+    }
+
+  if (min_width_p)
+    *min_width_p = priv->request_min_width;
+
+  if (natural_width_p)
+    *natural_width_p = priv->request_natural_width;
+}
+
+/**
+ * clutter_actor_get_preferred_height:
+ * @self: A #ClutterActor
+ * @for_width: available width to assume in computing desired height,
+ *   or a negative value to indicate that no width is defined
+ * @min_height_p: return location for min height, or %NULL
+ * @natural_height_p: return location for natural height, or %NULL
+ *
+ * Computes the requested minimum and natural heights for an actor,
+ * or if they are already computed, returns the cached values.
+ *
+ * An actor may not get its request - depending on the layout
+ * manager that's in effect.
+ *
+ * A request should not incorporate the actor's scale or anchor point;
+ * those transformations do not affect layout, only rendering.
+ *
+ * Since: 0.8
+ */
+void
+clutter_actor_get_preferred_height (ClutterActor *self,
+                                    ClutterUnit   for_width,
+                                    ClutterUnit  *min_height_p,
+                                    ClutterUnit  *natural_height_p)
+{
+  ClutterActorClass *klass;
+  ClutterActorPrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  klass = CLUTTER_ACTOR_GET_CLASS (self);
+  priv = self->priv;
+
+  if (priv->needs_height_request ||
+      priv->request_height_for_width != for_width)
+    {
+      ClutterUnit min_height, natural_height;
+
+      min_height = natural_height = 0;
+
+      klass->get_preferred_height (self, for_width,
+                                   &min_height,
+                                   &natural_height);
+
+      if (natural_height < min_height)
+        {
+          g_warning ("Actor of type %s reported a natural height of %d "
+                     "(%d px) lower than min height %d (%d px)",
+                     G_OBJECT_TYPE_NAME (self),
+                     natural_height, CLUTTER_UNITS_TO_DEVICE (natural_height),
+                     min_height, CLUTTER_UNITS_TO_DEVICE (min_height));
+        }
+
+      if (!priv->min_height_set)
+        priv->request_min_height = min_height;
+
+      if (!priv->natural_height_set)
+        priv->request_natural_height = natural_height;
+
+      priv->request_height_for_width = for_width;
+      priv->needs_height_request = FALSE;
+    }
+
+  if (min_height_p)
+    *min_height_p = priv->request_min_height;
+
+  if (natural_height_p)
+    *natural_height_p = priv->request_natural_height;
+}
+
+/**
+ * clutter_actor_get_allocation_coords:
+ * @self: A #ClutterActor
+ * @x1: x1 coord
+ * @y1: y1 coord
+ * @x2: x2 coord
+ * @y2: y2 coord
+ *
+ * Gets the layout box an actor has been assigned.  The allocation can
+ * only be assumed valid inside a paint() method; anywhere else, it
+ * may be out-of-date.
+ *
+ * An allocation does not incorporate the actor's scale or anchor point;
+ * those transformations do not affect layout, only rendering.
+ *
+ * The returned coordinates are in pixels.
+ *
+ * Since: 0.8
+ */
+void
+clutter_actor_get_allocation_coords (ClutterActor  *self,
+                                     gint          *x1,
+                                     gint          *y1,
+                                     gint          *x2,
+                                     gint          *y2)
+{
+  ClutterActorBox allocation = { 0, };
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  clutter_actor_get_allocation_box (self, &allocation);
+
+  if (x1)
+    *x1 = CLUTTER_UNITS_TO_DEVICE (allocation.x1);
+
+  if (y1)
+    *y1 = CLUTTER_UNITS_TO_DEVICE (allocation.y1);
+
+  if (x2)
+    *x2 = CLUTTER_UNITS_TO_DEVICE (allocation.x2);
+
+  if (y2)
+    *y2 = CLUTTER_UNITS_TO_DEVICE (allocation.y2);
+}
+
+/**
+ * clutter_actor_get_allocation_box:
+ * @self: A #ClutterActor
+ * @box: the function fills this in with the actor's allocation
+ *
+ * Gets the layout box an actor has been assigned. The allocation can
+ * only be assumed valid inside a paint() method; anywhere else, it
+ * may be out-of-date.
+ *
+ * An allocation does not incorporate the actor's scale or anchor point;
+ * those transformations do not affect layout, only rendering.
+ *
+ * <note>Do not call any of the clutter_actor_get_allocation_*() family
+ * of functions inside the implementation of the get_preferred_width()
+ * or get_preferred_height() virtual functions.</note>
+ *
+ * Since: 0.8
+ */
+void
+clutter_actor_get_allocation_box (ClutterActor    *self,
+                                  ClutterActorBox *box)
+{
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  /* FIXME - if needs_allocation=TRUE, we can either 1)
+   * g_return_if_fail, which limits calling get_allocation to inside
+   * paint() basically; or we can 2) force a layout, which could be
+   * expensive if someone calls get_allocation somewhere silly; or we
+   * can 3) just return the latest value, allowing it to be
+   * out-of-date, and assume people know what they are doing.
+   *
+   * The least-surprises approach that keeps existing code working is
+   * likely to be 2). People can end up doing some inefficient things,
+   * though, and in general code that requires 2) is probably broken.
+   */
+
+  /* this implements 2) */
+  if (G_UNLIKELY (self->priv->needs_allocation))
+    {
+      ClutterActor *stage = clutter_actor_get_stage (self);
+
+      /* do not queue a relayout on an unparented actor */
+      if (stage)
+        _clutter_stage_maybe_relayout (stage);
+    }
+
+  /* commenting out the code above and just keeping this assigment
+   * implements 3)
+   */
+  *box = self->priv->allocation;
+}
+
+/**
+ * clutter_actor_get_allocation_geometry:
+ * @self: A #ClutterActor
+ * @geom: allocation geometry in pixels
+ *
+ * Gets the layout box an actor has been assigned.  The allocation can
+ * only be assumed valid inside a paint() method; anywhere else, it
+ * may be out-of-date.
+ *
+ * An allocation does not incorporate the actor's scale or anchor point;
+ * those transformations do not affect layout, only rendering.
+ *
+ * The returned rectangle is in pixels.
+ *
+ * Since: 0.8
+ */
+void
+clutter_actor_get_allocation_geometry (ClutterActor    *self,
+                                       ClutterGeometry *geom)
+{
+  int x2, y2;
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  clutter_actor_get_allocation_coords (self, &geom->x, &geom->y, &x2, &y2);
+  geom->width = x2 - geom->x;
+  geom->height = y2 - geom->y;
+}
+
+/**
+ * clutter_actor_get_paint_area:
+ * @self: A #ClutterActor
+ * @box: the function fills this in with the actor's paint area
+ *
+ * Gets where an actor will be painted, which is generally the union
+ * of the paint boxes of the actor's children, plus anything the actor
+ * draws itself, transformed by the scale factor and anchor point. The
+ * result is a "paint area", i.e. where the actor will actually be
+ * painted.
+ *
+ * The returned #ClutterActorBox is in the coordinates of the actor's
+ * parent, just as an allocation is.
+ *
+ * <note>This function is only valid if the allocation is valid,
+ * which means for the most part only inside a paint() method.</note>
+ *
+ * Since: 0.8
+ */
+void
+clutter_actor_get_paint_area (ClutterActor    *self,
+                              ClutterActorBox *box)
 {
-  ClutterActorBox box;
+  ClutterActorClass *klass;
+  ClutterActorBox transformed = { 0, };
 
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_query_coords (self, &box);
+  klass = CLUTTER_ACTOR_GET_CLASS (self);
+
+  klass->get_paint_area (self, &transformed);
 
-  geometry->x      = CLUTTER_UNITS_TO_DEVICE (box.x1);
-  geometry->y      = CLUTTER_UNITS_TO_DEVICE (box.y1);
-  geometry->width  = CLUTTER_UNITS_TO_DEVICE (box.x2 - box.x1);
-  geometry->height = CLUTTER_UNITS_TO_DEVICE (box.y2 - box.y1);
+  /* FIXME also do scale and rotation; without these, get_stage_area()
+   * behaviour is the same as query_coords() called in ClutterGroup
+   * in Clutter 0.6.
+   */
+#if 0
+  if (clutter_actor_is_scaled (child) ||
+      clutter_actor_is_rotated (child))
+    {
+      ClutterVertex vtx[4];
+
+      clutter_actor_get_allocation_vertices (child, self, vtx);
+      clutter_actor_box_get_from_vertices (vtx, &transformed);
+    }
+  else
+#endif
+    {
+      ClutterUnit anchor_x;
+      ClutterUnit anchor_y;
+
+      clutter_actor_get_anchor_pointu (self, &anchor_x, &anchor_y);
+
+      transformed.x1 -= anchor_x;
+      transformed.x2 -= anchor_x;
+      transformed.y1 -= anchor_y;
+      transformed.y2 -= anchor_y;
+    }
+
+  *box = transformed;
 }
 
 /**
- * clutter_actor_get_coords:
+ * clutter_actor_allocate:
  * @self: A #ClutterActor
- * @x_1: A location to store actors left position, or %NULL.
- * @y_1: A location to store actors top position, or %NULL.
- * @x_2: A location to store actors right position, or %NULL.
- * @y_2: A location to store actors bottom position, or %NULL.
+ * @box: new allocation of the actor, in parent-relative coordinates
+ * @absolute_origin_changed: whether the position of the parent has
+ *   changed in stage coordinates
+ *
+ * Called by the parent of an actor to assign the actor its size.
+ * Should never be called by applications (except when implementing
+ * a container or layout manager).
  *
- * Gets the actor's untransformed bounding rectangle coordinates in pixels
- * relative to any parent actor.
+ * Actors can know from their allocation box whether they have moved
+ * with respect to their parent actor. The absolute_origin_changed
+ * parameter additionally indicates whether the parent has moved with
+ * respect to the stage, for example because a grandparent's origin
+ * has moved.
+ *
+ * Since: 0.8
  */
 void
-clutter_actor_get_coords (ClutterActor *self,
-                         gint         *x_1,
-                         gint         *y_1,
-                         gint         *x_2,
-                         gint         *y_2)
+clutter_actor_allocate (ClutterActor          *self,
+                        const ClutterActorBox *box,
+                        gboolean               absolute_origin_changed)
 {
-  ClutterActorBox box;
+  ClutterActorPrivate *priv;
+  ClutterActorClass *klass;
+  gboolean child_moved;
 
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_query_coords (self, &box);
+  priv = self->priv;
+  klass = CLUTTER_ACTOR_GET_CLASS (self);
 
-  if (x_1)
-    *x_1 = CLUTTER_UNITS_TO_DEVICE (box.x1);
+  child_moved = (box->x1 == priv->allocation.x1 ||
+                 box->y1 == priv->allocation.y1);
 
-  if (y_1)
-    *y_1 = CLUTTER_UNITS_TO_DEVICE (box.y1);
+  /* If we get an allocation "out of the blue"
+   * (we did not queue relayout), then we want to
+   * ignore it. But if we have needs_allocation set,
+   * we want to guarantee that allocate() virtual
+   * method is always called, i.e. that queue_relayout()
+   * always results in an allocate() invocation on
+   * an actor.
+   *
+   * The optimization here is to avoid re-allocating
+   * actors that did not queue relayout and were
+   * not moved.
+   */
 
-  if (x_2)
-    *x_2 = CLUTTER_UNITS_TO_DEVICE (box.x2);
+  if (!priv->needs_allocation &&
+      !absolute_origin_changed &&
+      !child_moved &&
+      box->x2 == priv->allocation.x2 &&
+      box->y2 == priv->allocation.y2)
+    {
+      CLUTTER_NOTE (ACTOR, "No allocation needed");
+      return;
+    }
 
-  if (y_2)
-    *y_2 = CLUTTER_UNITS_TO_DEVICE (box.y2);
+  /* When absolute_origin_changed is passed in to
+   * clutter_actor_allocate(), it indicates whether the parent has its
+   * absolute origin moved; when passed in to ClutterActor::allocate()
+   * virtual method though, it indicates whether the child has its
+   * absolute origin moved.  So we set it to TRUE if child_moved.
+   */
+  klass->allocate (self, box, absolute_origin_changed || child_moved);
+}
+
+/**
+ * clutter_actor_set_geometry:
+ * @self: A #ClutterActor
+ * @geometry: A #ClutterGeometry
+ *
+ * Sets the actor's fixed position and forces its minimum and natural
+ * size, in pixels. This means the untransformed actor will have the
+ * given geometry. This is the same as calling clutter_actor_set_position()
+ * and clutter_actor_set_size().
+ */
+void
+clutter_actor_set_geometry (ClutterActor          *self,
+                           const ClutterGeometry *geometry)
+{
+  g_object_freeze_notify (G_OBJECT (self));
+  clutter_actor_set_position (self, geometry->x, geometry->y);
+  clutter_actor_set_size (self, geometry->width, geometry->height);
+  g_object_thaw_notify (G_OBJECT (self));
+}
+
+/**
+ * clutter_actor_get_geometry:
+ * @self: A #ClutterActor
+ * @geometry: A location to store actors #ClutterGeometry
+ *
+ * Gets the size and position of an actor relative to its parent
+ * actor. This is the same as calling clutter_actor_get_position() and
+ * clutter_actor_get_size(). It tries to "do what you mean" and get the
+ * requested size and position if the actor's allocation is invalid.
+ */
+void
+clutter_actor_get_geometry (ClutterActor    *self,
+                           ClutterGeometry *geometry)
+{
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  clutter_actor_get_position (self, &geometry->x, &geometry->y);
+  clutter_actor_get_size (self, &geometry->width, &geometry->height);
 }
 
 /**
@@ -2666,26 +3518,23 @@ clutter_actor_get_coords (ClutterActor *self,
  * @x: New left position of actor in pixels.
  * @y: New top position of actor in pixels.
  *
- * Sets the actor's position in pixels relative to any parent actor.
+ * Sets the actor's fixed position in pixels relative to any parent
+ * actor.
+ *
+ * If a layout manager is in use, this position will override the
+ * layout manager and force a fixed position.
  */
 void
 clutter_actor_set_position (ClutterActor *self,
                            gint          x,
                            gint          y)
 {
-  ClutterActorBox box;
-
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_query_coords (self, &box);
-
-  box.x2 += (CLUTTER_UNITS_FROM_INT (x) - box.x1);
-  box.y2 += (CLUTTER_UNITS_FROM_INT (y) - box.y1);
-
-  box.x1 = CLUTTER_UNITS_FROM_INT (x);
-  box.y1 = CLUTTER_UNITS_FROM_INT (y);
-
-  clutter_actor_request_coords (self, &box);
+  g_object_freeze_notify (G_OBJECT (self));
+  clutter_actor_set_x (self, x);
+  clutter_actor_set_y (self, y);
+  g_object_thaw_notify (G_OBJECT (self));
 }
 
 /**
@@ -2697,6 +3546,9 @@ clutter_actor_set_position (ClutterActor *self,
  * Sets the actor's position in #ClutterUnit<!-- -->s relative to any
  * parent actor.
  *
+ * If a layout manager is in use, this position will override the
+ * layout manager and force a fixed position.
+ *
  * Since: 0.6
  */
 void
@@ -2704,116 +3556,311 @@ clutter_actor_set_positionu (ClutterActor *self,
                             ClutterUnit   x,
                             ClutterUnit   y)
 {
-  ClutterActorBox box;
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  g_object_freeze_notify (G_OBJECT (self));
+  clutter_actor_set_xu (self, x);
+  clutter_actor_set_yu (self, y);
+  g_object_thaw_notify (G_OBJECT (self));
+}
+
+/**
+ * clutter_actor_get_fixed_position_set:
+ * @self: A #ClutterActor
+ *
+ * Checks whether an actor has a fixed position set (and will thus be
+ * unaffected by any layout manager).
+ *
+ * Return value: %TRUE if the fixed position is set on the actor
+ *
+ * Since: 0.8
+ */
+gboolean
+clutter_actor_get_fixed_position_set (ClutterActor *self)
+{
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
+
+  return self->priv->position_set;
+}
+
+/**
+ * clutter_actor_set_fixed_position_set:
+ * @self: A #ClutterActor
+ * @is_set: whether to use fixed position
+ *
+ * Sets whether an actor has a fixed position set (and will thus be
+ * unaffected by any layout manager).
+ *
+ * Since: 0.8
+ */
+void
+clutter_actor_set_fixed_position_set (ClutterActor *self,
+                                      gboolean      is_set)
+{
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  if (self->priv->position_set == (is_set != FALSE))
+    return;
+
+  self->priv->position_set = is_set != FALSE;
+  g_object_notify (G_OBJECT (self), "fixed-position-set");
+  clutter_actor_queue_relayout (self);
+}
+
+/**
+ * clutter_actor_move_by:
+ * @self: A #ClutterActor
+ * @dx: Distance to move Actor on X axis.
+ * @dy: Distance to move Actor on Y axis.
+ *
+ * Moves an actor by the specified distance relative to its current
+ * position in pixels. This function modifies the fixed position of an
+ * actor and thus removes it from any layout management. Another way
+ * to move an actor is with an anchor point, see
+ * clutter_actor_set_anchor_point().
+ *
+ * Since: 0.2
+ */
+void
+clutter_actor_move_by (ClutterActor *self,
+                      gint          dx,
+                      gint          dy)
+{
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  clutter_actor_move_byu (self,
+                          CLUTTER_UNITS_FROM_DEVICE (dx),
+                          CLUTTER_UNITS_FROM_DEVICE (dy));
+}
+
+/**
+ * clutter_actor_move_byu:
+ * @self: A #ClutterActor
+ * @dx: Distance to move Actor on X axis, in #ClutterUnit<!-- -->s.
+ * @dy: Distance to move Actor on Y axis, in #ClutterUnit<!-- -->s.
+ *
+ * Moves an actor by the specified distance relative to its current
+ * position.
+ *
+ * The move is accomplished by setting a fixed position, overriding
+ * any layout manager, see clutter_actor_set_positionu().
+ *
+ * Since: 0.6
+ */
+void
+clutter_actor_move_byu (ClutterActor *self,
+                        ClutterUnit   dx,
+                        ClutterUnit   dy)
+{
+  ClutterUnit x, y;
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  x = self->priv->fixed_x;
+  y = self->priv->fixed_y;
+
+  clutter_actor_set_positionu (self, x + dx, y + dy);
+}
+
+static void
+clutter_actor_set_min_width (ClutterActor *self,
+                             ClutterUnit   min_width)
+{
+  ClutterActorPrivate *priv = self->priv;
+  ClutterGeometry old = { 0, };
+
+  if (priv->min_width_set && min_width == priv->request_min_width)
+    return;
+
+  g_object_freeze_notify (G_OBJECT (self));
+
+  clutter_actor_store_old_geometry (self, &old);
+
+  priv->request_min_width = min_width;
+  g_object_notify (G_OBJECT (self), "min-width");
+  clutter_actor_set_min_width_set (self, TRUE);
+
+  clutter_actor_notify_if_geometry_changed (self, &old);
+
+  g_object_thaw_notify (G_OBJECT (self));
+
+  clutter_actor_queue_relayout (self);
+}
+
+static void
+clutter_actor_set_min_height (ClutterActor *self,
+                              ClutterUnit   min_height)
+
+{
+  ClutterActorPrivate *priv = self->priv;
+  ClutterGeometry old = { 0, };
+
+  if (priv->min_height_set && min_height == priv->request_min_height)
+    return;
+
+  g_object_freeze_notify (G_OBJECT (self));
+
+  clutter_actor_store_old_geometry (self, &old);
+
+  priv->request_min_height = min_height;
+  g_object_notify (G_OBJECT (self), "min-height");
+  clutter_actor_set_min_height_set (self, TRUE);
+
+  clutter_actor_notify_if_geometry_changed (self, &old);
+
+  g_object_thaw_notify (G_OBJECT (self));
+
+  clutter_actor_queue_relayout (self);
+}
+
+static void
+clutter_actor_set_natural_width (ClutterActor *self,
+                                 ClutterUnit   natural_width)
+{
+  ClutterActorPrivate *priv = self->priv;
+  ClutterGeometry old = { 0, };
+
+  if (priv->natural_width_set &&
+      natural_width == priv->request_natural_width)
+    return;
+
+  g_object_freeze_notify (G_OBJECT (self));
+
+  clutter_actor_store_old_geometry (self, &old);
+
+  priv->request_natural_width = natural_width;
+  g_object_notify (G_OBJECT (self), "natural-width");
+  clutter_actor_set_natural_width_set (self, TRUE);
+
+  clutter_actor_notify_if_geometry_changed (self, &old);
+
+  g_object_thaw_notify (G_OBJECT (self));
+
+  clutter_actor_queue_relayout (self);
+}
+
+static void
+clutter_actor_set_natural_height (ClutterActor *self,
+                                  ClutterUnit   natural_height)
+{
+  ClutterActorPrivate *priv = self->priv;
+  ClutterGeometry old = { 0, };
+
+  if (priv->natural_height_set &&
+      natural_height == priv->request_natural_height)
+    return;
+
+  g_object_freeze_notify (G_OBJECT (self));
+
+  clutter_actor_store_old_geometry (self, &old);
+
+  priv->request_natural_height = natural_height;
+  g_object_notify (G_OBJECT (self), "natural-height");
+  clutter_actor_set_natural_height_set (self, TRUE);
+
+  clutter_actor_notify_if_geometry_changed (self, &old);
+
+  g_object_thaw_notify (G_OBJECT (self));
+
+  clutter_actor_queue_relayout (self);
+}
+
+static void
+clutter_actor_set_min_width_set (ClutterActor *self,
+                                 gboolean      use_min_width)
+{
+  ClutterActorPrivate *priv = self->priv;
+  ClutterGeometry old = { 0, };
 
-  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+  if (priv->min_width_set == (use_min_width != FALSE))
+    return;
 
-  clutter_actor_query_coords (self, &box);
+  clutter_actor_store_old_geometry (self, &old);
 
-  box.x2 += (x - box.x1);
-  box.y2 += (y - box.y1);
+  priv->min_width_set = use_min_width != FALSE;
+  g_object_notify (G_OBJECT (self), "min-width-set");
 
-  box.x1 = x;
-  box.y1 = y;
+  clutter_actor_notify_if_geometry_changed (self, &old);
 
-  clutter_actor_request_coords (self, &box);
+  clutter_actor_queue_relayout (self);
 }
 
-/**
- * clutter_actor_move_by:
- * @self: A #ClutterActor
- * @dx: Distance to move Actor on X axis.
- * @dy: Distance to move Actor on Y axis.
- *
- * Moves an actor by the specified distance relative to its
- * current position in pixels.
- *
- * Since: 0.2
- */
-void
-clutter_actor_move_by (ClutterActor *self,
-                      gint          dx,
-                      gint          dy)
+static void
+clutter_actor_set_min_height_set (ClutterActor *self,
+                                  gboolean      use_min_height)
 {
-  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+  ClutterActorPrivate *priv = self->priv;
+  ClutterGeometry old = { 0, };
 
-  clutter_actor_move_byu (self,
-                          CLUTTER_UNITS_FROM_DEVICE (dx),
-                          CLUTTER_UNITS_FROM_DEVICE (dy));
+  if (priv->min_height_set == (use_min_height != FALSE))
+    return;
+
+  clutter_actor_store_old_geometry (self, &old);
+
+  priv->min_height_set = use_min_height != FALSE;
+  g_object_notify (G_OBJECT (self), "min-height-set");
+
+  clutter_actor_notify_if_geometry_changed (self, &old);
+
+  clutter_actor_queue_relayout (self);
 }
 
-/**
- * clutter_actor_move_byu:
- * @self: A #ClutterActor
- * @dx: Distance to move Actor on X axis, in #ClutterUnit<!-- -->s.
- * @dy: Distance to move Actor on Y axis, in #ClutterUnit<!-- -->s.
- *
- * Moves an actor by the specified distance relative to its current
- * position.
- *
- * Since: 0.6
- */
-void
-clutter_actor_move_byu (ClutterActor *self,
-                        ClutterUnit   dx,
-                        ClutterUnit   dy)
+static void
+clutter_actor_set_natural_width_set (ClutterActor *self,
+                                     gboolean      use_natural_width)
 {
-  ClutterActorBox box;
+  ClutterActorPrivate *priv = self->priv;
+  ClutterGeometry old = { 0, };
 
-  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+  if (priv->natural_width_set == (use_natural_width != FALSE))
+    return;
+
+  clutter_actor_store_old_geometry (self, &old);
 
-  clutter_actor_query_coords (self, &box);
+  priv->natural_width_set = use_natural_width != FALSE;
+  g_object_notify (G_OBJECT (self), "natural-width-set");
 
-  box.x2 += dx;
-  box.y2 += dy;
-  box.x1 += dx;
-  box.y1 += dy;
+  clutter_actor_notify_if_geometry_changed (self, &old);
 
-  clutter_actor_request_coords (self, &box);
+  clutter_actor_queue_relayout (self);
 }
 
-/* local inline version, without type checking to be used by
- * set_width() and set_height(). if one of the dimensions is < 0
- * it will not be changed
- */
-static inline void
-clutter_actor_set_size_internal (ClutterActor *self,
-                                 gint          width,
-                                 gint          height)
+static void
+clutter_actor_set_natural_height_set (ClutterActor *self,
+                                      gboolean      use_natural_height)
 {
-  ClutterActorBox box;
+  ClutterActorPrivate *priv = self->priv;
+  ClutterGeometry old = { 0, };
 
-  clutter_actor_query_coords (self, &box);
+  if (priv->natural_height_set == (use_natural_height != FALSE))
+    return;
+
+  clutter_actor_store_old_geometry (self, &old);
 
-  if (width > 0)
-    box.x2 = box.x1 + CLUTTER_UNITS_FROM_INT (width);
+  priv->natural_height_set = use_natural_height != FALSE;
+  g_object_notify (G_OBJECT (self), "natural-height-set");
 
-  if (height > 0)
-    box.y2 = box.y1 + CLUTTER_UNITS_FROM_INT (height);
+  clutter_actor_notify_if_geometry_changed (self, &old);
 
-  clutter_actor_request_coords (self, &box);
+  clutter_actor_queue_relayout (self);
 }
 
-/* local inline unit version, without type checking to be used by
- * set_width() and set_height(). if one of the dimensions is < 0
- * it will not be changed
- */
-static inline void
-clutter_actor_set_size_internalu (ClutterActor *self,
-                                 ClutterUnit   width,
-                                  ClutterUnit   height)
+static void
+clutter_actor_set_request_mode (ClutterActor *self,
+                                ClutterRequestMode mode)
 {
-  ClutterActorBox box;
+  ClutterActorPrivate *priv = self->priv;
+
+  if (priv->request_mode == mode)
+    return;
 
-  clutter_actor_query_coords (self, &box);
+  priv->request_mode = mode;
 
-  if (width > 0)
-    box.x2 = box.x1 + width;
+  priv->needs_width_request = TRUE;
+  priv->needs_height_request = TRUE;
 
-  if (height > 0)
-    box.y2 = box.y1 + height;
+  g_object_notify (G_OBJECT (self), "request-mode");
 
-  clutter_actor_request_coords (self, &box);
+  clutter_actor_queue_relayout (self);
 }
 
 /**
@@ -2822,16 +3869,16 @@ clutter_actor_set_size_internalu (ClutterActor *self,
  * @width: New width of actor in pixels, or -1
  * @height: New height of actor in pixels, or -1
  *
- * Sets the actor's size in pixels.
+ * Sets the actor's size request in pixels. This overrides any
+ * "normal" size request the actor would have. For example
+ * a text actor might normally request the size of the text;
+ * this function would force a specific size instead.
  *
- * If @width and/or @height are -1 the actor will assume the same size
- * of its bounding box.
+ * If @width and/or @height are -1 the actor will use its
+ * "normal" size request instead of overriding it, i.e.
+ * you can "unset" the size with -1.
  *
- * <note>This function is a "request" to the #ClutterActor. Depending
- * on the actual implementation, calling clutter_actor_set_size() might
- * not produce visible results. Calling this function on a #ClutterGroup,
- * for instance, will not resize the group - as its size is dependant
- * on bounding box of actual contents</note>
+ * This function sets or unsets both the minimum and natural size.
  */
 void
 clutter_actor_set_size (ClutterActor *self,
@@ -2840,7 +3887,9 @@ clutter_actor_set_size (ClutterActor *self,
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_size_internal (self, width, height);
+  clutter_actor_set_sizeu (self,
+                           CLUTTER_UNITS_FROM_DEVICE (width),
+                           CLUTTER_UNITS_FROM_DEVICE (height));
 }
 
 /**
@@ -2849,8 +3898,11 @@ clutter_actor_set_size (ClutterActor *self,
  * @width: New width of actor in #ClutterUnit<!-- -->s, or -1
  * @height: New height of actor in #ClutterUnit<!-- -->s, or -1
  *
- * Sets the actor's size in #ClutterUnit<!-- -->s. If @width and/or @height
- * are -1 the actor will assume the same size as its bounding box.
+ * Overrides the actor's size request in #ClutterUnit<!-- -->s. If @width
+ * and/or @height are -1 the actor will use its normal size request (the
+ * override is removed).
+ *
+ * This function sets or unsets both the minimum and natural size.
  *
  * Since: 0.6
  */
@@ -2861,7 +3913,31 @@ clutter_actor_set_sizeu (ClutterActor *self,
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_size_internalu (self, width, height);
+  g_object_freeze_notify (G_OBJECT (self));
+
+  if (width >= 0)
+    {
+      clutter_actor_set_min_width (self, width);
+      clutter_actor_set_natural_width (self, width);
+    }
+  else
+    {
+      clutter_actor_set_min_width_set (self, FALSE);
+      clutter_actor_set_natural_width_set (self, FALSE);
+    }
+
+  if (height >= 0)
+    {
+      clutter_actor_set_min_height (self, height);
+      clutter_actor_set_natural_height (self, height);
+    }
+  else
+    {
+      clutter_actor_set_min_height_set (self, FALSE);
+      clutter_actor_set_natural_height_set (self, FALSE);
+    }
+
+  g_object_thaw_notify (G_OBJECT (self));
 }
 
 /**
@@ -2870,7 +3946,15 @@ clutter_actor_set_sizeu (ClutterActor *self,
  * @width: return location for the width, or %NULL.
  * @height: return location for the height, or %NULL.
  *
- * Gets the size of an actor in pixels, ignoring any scaling factors.
+ * This function tries to "do what you mean" and return
+ * the size an actor will have. If the actor has a valid
+ * allocation, the allocation will be returned; otherwise,
+ * the actors natural size request will be returned.
+ *
+ * If you care whether you get the request vs. the allocation, you
+ * should probably call a different function like
+ * clutter_actor_get_allocation_coords() or
+ * clutter_actor_get_preferred_width().
  *
  * Since: 0.2
  */
@@ -2879,17 +3963,13 @@ clutter_actor_get_size (ClutterActor *self,
                        guint        *width,
                        guint        *height)
 {
-  ClutterActorBox box;
-
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_query_coords (self, &box);
-
   if (width)
-    *width = CLUTTER_UNITS_TO_DEVICE (box.x2 - box.x1);
+    *width = clutter_actor_get_width (self);
 
   if (height)
-    *height = CLUTTER_UNITS_TO_DEVICE (box.y2 - box.y1);
+    *height = clutter_actor_get_height (self);
 }
 
 /**
@@ -2898,8 +3978,15 @@ clutter_actor_get_size (ClutterActor *self,
  * @width: return location for the width, or %NULL
  * @height: return location for the height, or %NULL
  *
- * Gets the size of an actor in #ClutterUnit<!-- -->s, ignoring any scaling
- * factors.
+ * This function tries to "do what you mean" and return
+ * the size an actor will have. If the actor has a valid
+ * allocation, the allocation will be returned; otherwise,
+ * the actors natural size request will be returned.
+ *
+ * If you care whether you get the request vs. the allocation, you
+ * should probably call a different function like
+ * clutter_actor_get_allocation_coords() or
+ * clutter_actor_get_preferred_width().
  *
  * Since: 0.6
  */
@@ -2908,17 +3995,13 @@ clutter_actor_get_sizeu (ClutterActor *self,
                          ClutterUnit  *width,
                          ClutterUnit  *height)
 {
-  ClutterActorBox box;
-
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_query_coords (self, &box);
-
   if (width)
-    *width = box.x2 - box.x1;
+    *width = clutter_actor_get_widthu (self);
 
   if (height)
-    *height = box.y2 - box.y1;
+    *height = clutter_actor_get_heightu (self);
 }
 
 /**
@@ -2927,7 +4010,13 @@ clutter_actor_get_sizeu (ClutterActor *self,
  * @x: return location for the X coordinate, or %NULL
  * @y: return location for the Y coordinate, or %NULL
  *
- * Retrieves the position of an actor.
+ * This function tries to "do what you mean" and tell you where the
+ * actor is, prior to any transformations. Retrieves the fixed
+ * position of an actor in pixels, if one has been set; otherwise, if
+ * the allocation is valid, returns the actor's allocated position;
+ * otherwise, returns 0,0.
+ *
+ * The returned position is in pixels.
  *
  * Since: 0.6
  */
@@ -2936,17 +4025,13 @@ clutter_actor_get_position (ClutterActor *self,
                             gint         *x,
                             gint         *y)
 {
-  ClutterActorBox box = { 0, };
-
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_query_coords (self, &box);
-
   if (x)
-    *x = CLUTTER_UNITS_TO_DEVICE (box.x1);
+    *x = clutter_actor_get_x (self);
 
   if (y)
-    *y = CLUTTER_UNITS_TO_DEVICE (box.y1);
+    *y = clutter_actor_get_y (self);
 }
 
 /**
@@ -2955,7 +4040,13 @@ clutter_actor_get_position (ClutterActor *self,
  * @x: return location for the X coordinate, or %NULL
  * @y: return location for the Y coordinate, or %NULL
  *
- * Retrieves the position of an actor in #ClutterUnit<!-- -->s.
+ * This function tries to "do what you mean" and tell you where the
+ * actor is, prior to any transformations. Retrieves the fixed
+ * position of an actor in pixels, if one has been set; otherwise, if
+ * the allocation is valid, returns the actor's allocated position;
+ * otherwise, returns 0,0.
+ *
+ * The returned position is in #ClutterUnit<!-- -->s.
  *
  * Since: 0.6
  */
@@ -2964,21 +4055,17 @@ clutter_actor_get_positionu (ClutterActor *self,
                              ClutterUnit  *x,
                              ClutterUnit  *y)
 {
-  ClutterActorBox box = { 0, };
-
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_query_coords (self, &box);
-
   if (x)
-    *x = box.x1;
+    *x = clutter_actor_get_xu (self);
 
   if (y)
-    *y = box.y1;
+    *y = clutter_actor_get_yu (self);
 }
 
-/*
- * clutter_actor_get_abs_position_units
+/**
+ * clutter_actor_get_transformed_positionu
  * @self: A #ClutterActor
  * @x: return location for the X coordinate, or %NULL
  * @y: return location for the Y coordinate, or %NULL
@@ -2986,17 +4073,16 @@ clutter_actor_get_positionu (ClutterActor *self,
  * Gets the absolute position of an actor, in #ClutterUnit<!-- -->s,
  * relative to the stage.
  *
- * Since: 0.4
+ * Since: 0.8
  */
-static void
-clutter_actor_get_abs_position_units (ClutterActor *self,
-                                     gint32       *x,
-                                     gint32       *y)
+void
+clutter_actor_get_transformed_positionu (ClutterActor *self,
+                                         ClutterUnit  *x,
+                                         ClutterUnit  *y)
 {
-  ClutterVertex v1;
-  ClutterVertex v2;
+  ClutterVertex v1 = { 0, };
+  ClutterVertex v2 = { 0, };
 
-  v1.x = v1.y = v1.z = 0;
   clutter_actor_apply_transform_to_point (self, &v1, &v2);
 
   if (x)
@@ -3006,25 +4092,27 @@ clutter_actor_get_abs_position_units (ClutterActor *self,
 }
 
 /**
- * clutter_actor_get_abs_position
+ * clutter_actor_get_transformed_position
  * @self: A #ClutterActor
  * @x: return location for the X coordinate, or %NULL
  * @y: return location for the Y coordinate, or %NULL
  *
  * Gets the absolute position of an actor, in pixels, relative
  * to the stage.
+ *
+ * Since: 0.8
  */
 void
-clutter_actor_get_abs_position (ClutterActor *self,
-                               gint         *x,
-                               gint         *y)
+clutter_actor_get_transformed_position (ClutterActor *self,
+                                        gint         *x,
+                                        gint         *y)
 {
   ClutterUnit xu, yu;
 
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
   xu = yu = 0;
-  clutter_actor_get_abs_position_units (self, &xu, &yu);
+  clutter_actor_get_transformed_positionu (self, &xu, &yu);
 
   if (x)
     *x = CLUTTER_UNITS_TO_DEVICE (xu);
@@ -3032,8 +4120,8 @@ clutter_actor_get_abs_position (ClutterActor *self,
     *y = CLUTTER_UNITS_TO_DEVICE (yu);
 }
 
-/*
- * clutter_actor_get_abs_size_units:
+/**
+ * clutter_actor_get_transformed_sizeu:
  * @self: A #ClutterActor
  * @width: return location for the width, or %NULL
  * @height: return location for the height, or %NULL
@@ -3047,27 +4135,27 @@ clutter_actor_get_abs_position (ClutterActor *self,
  * of the smallest rectangle that encapsulates the entire quad. Please
  * note that in this case no assumptions can be made about the relative
  * position of this envelope to the absolute position of the actor, as
- * returned by clutter_actor_get_abs_position(); if you need this
- * information, you need to use clutter_actor_get_vertices() to get the
- * coords of the actual quadrangle.
+ * returned by clutter_actor_get_transformed_position(); if you need this
+ * information, you need to use clutter_actor_get_abs_allocation_vertices()
+ * to get the coords of the actual quadrangle.</note>
  *
- * Since: 0.4
+ * Since: 0.8
  */
-static void
-clutter_actor_get_abs_size_units (ClutterActor *self,
-                                 gint32       *width,
-                                 gint32       *height)
+void
+clutter_actor_get_transformed_sizeu (ClutterActor *self,
+                                     ClutterUnit  *width,
+                                     ClutterUnit  *height)
 {
   ClutterVertex v[4];
   ClutterFixed  x_min, x_max, y_min, y_max;
   gint i;
 
-  clutter_actor_get_vertices (self, v);
+  clutter_actor_get_abs_allocation_vertices (self, v);
 
   x_min = x_max = v[0].x;
   y_min = y_max = v[0].y;
 
-  for (i = 1; i < sizeof(v)/sizeof(v[0]); ++i)
+  for (i = 1; i < G_N_ELEMENTS (v); ++i)
     {
       if (v[i].x < x_min)
        x_min = v[i].x;
@@ -3082,29 +4170,41 @@ clutter_actor_get_abs_size_units (ClutterActor *self,
        y_max = v[i].y;
     }
 
-  *width  = x_max - x_min;
-  *height = y_max - y_min;
+  if (width)
+    *width  = x_max - x_min;
+
+  if (height)
+    *height = y_max - y_min;
 }
 
 /**
- * clutter_actor_get_abs_size:
+ * clutter_actor_get_transformed_size:
  * @self: A #ClutterActor
  * @width: return location for the width, or %NULL
  * @height: return location for the height, or %NULL
  *
  * Gets the absolute size of an actor taking into account
- * an scaling factors
+ * any scaling factors
+ *
+ * Since: 0.8
  */
 void
-clutter_actor_get_abs_size (ClutterActor *self,
-                           guint        *width,
-                           guint        *height)
+clutter_actor_get_transformed_size (ClutterActor *self,
+                                    guint        *width,
+                                    guint        *height)
 {
-  gint32 wu, hu;
-  clutter_actor_get_abs_size_units (self, &wu, &hu);
+  ClutterUnit wu, hu;
+
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+  wu = hu = 0;
+  clutter_actor_get_transformed_sizeu (self, &wu, &hu);
 
-  *width  = CLUTTER_UNITS_TO_DEVICE (wu);
-  *height = CLUTTER_UNITS_TO_DEVICE (hu);
+  if (width)
+    *width  = CLUTTER_UNITS_TO_DEVICE (wu);
+
+  if (height)
+    *height = CLUTTER_UNITS_TO_DEVICE (hu);
 }
 
 
@@ -3112,84 +4212,165 @@ clutter_actor_get_abs_size (ClutterActor *self,
  * clutter_actor_get_width
  * @self: A #ClutterActor
  *
- * Retrieves the actor's width ignoring any scaling factors.
+ * Retrieves the width of a #ClutterActor.
  *
- * Return value: the width in pixels
- **/
+ * This function tries to "do what you mean", by returning the correct
+ * value depending on the actor's state.
+ *
+ * If the actor has a valid allocation, this function will return the
+ * width of the allocation box.
+ *
+ * If the actor does not have a valid allocation, this function will
+ * return the actor's natural width request.
+ *
+ * If you care whether you get the width request or the allocation,
+ * you should probably call a different function like
+ * clutter_actor_get_allocation_coords() to retrieve the allocation
+ * or clutter_actor_get_preferred_width() to retrieve the preferred
+ * width.
+ *
+ * Return value: the width of the actor, in pixels
+ */
 guint
 clutter_actor_get_width (ClutterActor *self)
 {
-  ClutterActorBox box;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  clutter_actor_query_coords (self, &box);
-
-  return CLUTTER_UNITS_TO_DEVICE (box.x2 - box.x1);
+  return CLUTTER_UNITS_TO_DEVICE (clutter_actor_get_widthu (self));
 }
 
 /**
  * clutter_actor_get_widthu
  * @self: A #ClutterActor
  *
- * Retrieves the actor's width ignoring any scaling factors.
+ * Retrieves the width of a #ClutterActor, in #ClutterUnit<!-- -->s.
+ *
+ * This function tries to "do what you mean", by returning the correct
+ * value depending on the actor's state.
  *
- * Return value: the width in #ClutterUnit<!-- -->s
+ * If the actor has a valid allocation, this function will return the
+ * width of the allocation box.
+ *
+ * If the actor does not have a valid allocation, this function will
+ * return the actor's natural width request.
+ *
+ * If you care whether you get the width request or the allocation,
+ * you should probably call a different function like
+ * clutter_actor_get_allocation_coords() to retrieve the allocation
+ * or clutter_actor_get_preferred_width() to retrieve the preferred
+ * width.
+ *
+ * Return value: the width of the actor, in #ClutterUnit<!-- -->s
  *
  * since: 0.6
- **/
+ */
 ClutterUnit
 clutter_actor_get_widthu (ClutterActor *self)
 {
-  ClutterActorBox box;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  clutter_actor_query_coords (self, &box);
+  if (self->priv->needs_allocation)
+    {
+      ClutterUnit natural_width = 0;
+
+      if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
+        clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
+      else
+        {
+          ClutterUnit natural_height = 0;
+
+          clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
+          clutter_actor_get_preferred_width (self, natural_height,
+                                             NULL,
+                                             &natural_width);
+        }
 
-  return box.x2 - box.x1;
+      return natural_width;
+    }
+  else
+    return self->priv->allocation.x2 - self->priv->allocation.x1;
 }
 
 /**
  * clutter_actor_get_height
  * @self: A #ClutterActor
  *
- * Retrieves the actor's height ignoring any scaling factors.
+ * Retrieves the height of a #ClutterActor.
  *
- * Return value: the height in pixels
- **/
+ * This function tries to "do what you mean", by returning the correct
+ * value depending on the actor's state.
+ *
+ * If the actor has a valid allocation, this function will return the
+ * height of the allocation box.
+ *
+ * If the actor does not have a valid allocation, this function will
+ * return the actor's natural height request.
+ *
+ * If you care whether you get the height request or the allocation,
+ * you should probably call a different function like
+ * clutter_actor_get_allocation_coords() to retrieve the allocation
+ * or clutter_actor_get_preferred_height() to retrieve the
+ * preferred height.
+ *
+ * Return value: the height of the actor, in pixels
+ */
 guint
 clutter_actor_get_height (ClutterActor *self)
 {
-  ClutterActorBox box;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  clutter_actor_query_coords (self, &box);
-
-  return CLUTTER_UNITS_TO_DEVICE (box.y2 - box.y1);
+  return CLUTTER_UNITS_TO_DEVICE (clutter_actor_get_heightu (self));
 }
 
 /**
  * clutter_actor_get_heightu
  * @self: A #ClutterActor
  *
- * Retrieves the actor's height ignoring any scaling factors.
+ * Retrieves the height of a #ClutterActor, in #ClutterUnit<!-- -->s.
+ *
+ * This function tries to "do what you mean", by returning the correct
+ * value depending on the actor's state.
+ *
+ * If the actor has a valid allocation, this function will return the
+ * height of the allocation box.
  *
- * Return value: the height in #ClutterUnit<!-- -->s
+ * If the actor does not have a valid allocation, this function will
+ * return the actor's natural height request.
+ *
+ * If you care whether you get the height request or the allocation,
+ * you should probably call a different function like
+ * clutter_actor_get_allocation_coords() to retrieve the allocation
+ * or clutter_actor_get_preferred_height() to retrieve the
+ * preferred height.
+ *
+ * Return value: the height of the actor, in #ClutterUnit<!-- -->s
  *
  * since: 0.6
- **/
+ */
 ClutterUnit
 clutter_actor_get_heightu (ClutterActor *self)
 {
-  ClutterActorBox box;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  clutter_actor_query_coords (self, &box);
+  if (self->priv->needs_allocation)
+    {
+      ClutterUnit natural_height = 0;
+
+      if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
+        {
+          ClutterUnit natural_width = 0;
+
+          clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
+          clutter_actor_get_preferred_height (self, natural_width,
+                                              NULL, &natural_height);
+        }
+      else
+        clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
 
-  return box.y2 - box.y1;
+      return natural_height;
+    }
+  else
+    return self->priv->allocation.y2 - self->priv->allocation.y1;
 }
 
 /**
@@ -3197,7 +4378,9 @@ clutter_actor_get_heightu (ClutterActor *self)
  * @self: A #ClutterActor
  * @width: Requested new width for the actor, in pixels
  *
- * Requests a new width for the actor
+ * Forces a width request on an actor, causing the actor's
+ * normal width and height (if any) to be ignored. This function
+ * sets both the minimum and natural size request of the actor.
  *
  * since: 0.2
  **/
@@ -3207,7 +4390,7 @@ clutter_actor_set_width (ClutterActor *self,
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_size_internal (self, width, -1);
+  clutter_actor_set_widthu (self, CLUTTER_UNITS_FROM_DEVICE (width));
 }
 
 /**
@@ -3215,7 +4398,9 @@ clutter_actor_set_width (ClutterActor *self,
  * @self: A #ClutterActor
  * @width: Requested new width for the actor, in #ClutterUnit<!-- -->s
  *
- * Requests a new width for the actor
+ * Forces a width request on an actor, causing the actor's
+ * normal width and height (if any) to be ignored. This function
+ * sets both the minimum and natural size request of the actor.
  *
  * since: 0.6
  **/
@@ -3225,7 +4410,12 @@ clutter_actor_set_widthu (ClutterActor *self,
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_size_internalu (self, width, -1);
+  g_object_freeze_notify (G_OBJECT (self));
+
+  clutter_actor_set_min_width (self, width);
+  clutter_actor_set_natural_width (self, width);
+
+  g_object_thaw_notify (G_OBJECT (self));
 }
 
 /**
@@ -3233,7 +4423,9 @@ clutter_actor_set_widthu (ClutterActor *self,
  * @self: A #ClutterActor
  * @height: Requested new height for the actor, in pixels
  *
- * Requests a new height for the actor
+ * Forces a height request on an actor, causing the actor's
+ * normal width and height (if any) to be ignored. This function
+ * sets both the minimum and natural size request of the actor.
  *
  * since: 0.2
  **/
@@ -3243,7 +4435,7 @@ clutter_actor_set_height (ClutterActor *self,
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_size_internal (self, -1, height);
+  clutter_actor_set_heightu (self, CLUTTER_UNITS_FROM_DEVICE (height));
 }
 
 /**
@@ -3251,17 +4443,24 @@ clutter_actor_set_height (ClutterActor *self,
  * @self: A #ClutterActor
  * @height: Requested new height for the actor, in #ClutterUnit<!-- -->s
  *
- * Requests a new height for the actor
+ * Forces a height request on an actor, causing the actor's
+ * normal width and height (if any) to be ignored. This function
+ * sets both the minimum and natural size request of the actor.
  *
  * since: 0.6
  **/
 void
 clutter_actor_set_heightu (ClutterActor *self,
-                           ClutterUnit   height)
+                          ClutterUnit   height)
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_size_internalu (self, -1, height);
+  g_object_freeze_notify (G_OBJECT (self));
+
+  clutter_actor_set_min_height (self, height);
+  clutter_actor_set_natural_height (self, height);
+
+  g_object_thaw_notify (G_OBJECT (self));
 }
 
 /**
@@ -3269,7 +4468,9 @@ clutter_actor_set_heightu (ClutterActor *self,
  * @self: a #ClutterActor
  * @x: the actor's position on the X axis
  *
- * Sets the actor's X coordinate, relative to its parent.
+ * Sets the actor's X coordinate, relative to its parent, in pixels.
+ * Overrides any layout manager and forces a fixed position for
+ * the actor.
  *
  * Since: 0.6
  */
@@ -3279,9 +4480,7 @@ clutter_actor_set_x (ClutterActor *self,
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_position (self,
-                              x,
-                              clutter_actor_get_y (self));
+  clutter_actor_set_xu (self, CLUTTER_UNITS_FROM_DEVICE (x));
 }
 
 /**
@@ -3290,6 +4489,8 @@ clutter_actor_set_x (ClutterActor *self,
  * @x: the actor's position on the X axis, in #ClutterUnit<!-- -->s
  *
  * Sets the actor's X coordinate, relative to its parent.
+ * Overrides any layout manager and forces a fixed position for
+ * the actor.
  *
  * Since: 0.6
  */
@@ -3297,11 +4498,22 @@ void
 clutter_actor_set_xu (ClutterActor *self,
                      ClutterUnit   x)
 {
+  ClutterGeometry old;
+
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_positionu (self,
-                              x,
-                              clutter_actor_get_yu (self));
+  if (self->priv->position_set &&
+      self->priv->fixed_x == x)
+    return;
+
+  clutter_actor_store_old_geometry (self, &old);
+
+  self->priv->fixed_x = x;
+  clutter_actor_set_fixed_position_set (self, TRUE);
+
+  clutter_actor_notify_if_geometry_changed (self, &old);
+
+  clutter_actor_queue_relayout (self);
 }
 
 /**
@@ -3309,7 +4521,9 @@ clutter_actor_set_xu (ClutterActor *self,
  * @self: a #ClutterActor
  * @y: the actor's position on the Y axis
  *
- * Sets the actor's Y coordinate, relative to its parent.
+ * Sets the actor's Y coordinate, relative to its parent, in pixels.
+ * Overrides any layout manager and forces a fixed position for
+ * the actor.
  *
  * Since: 0.6
  */
@@ -3319,9 +4533,7 @@ clutter_actor_set_y (ClutterActor *self,
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_position (self,
-                              clutter_actor_get_x (self),
-                              y);
+  clutter_actor_set_yu (self, CLUTTER_UNITS_FROM_DEVICE (y));
 }
 
 /**
@@ -3330,6 +4542,8 @@ clutter_actor_set_y (ClutterActor *self,
  * @y: the actor's position on the Y axis, in #ClutterUnit<!-- -->s
  *
  * Sets the actor's Y coordinate, relative to its parent.
+ * Overrides any layout manager and forces a fixed position for
+ * the actor.
  *
  * Since: 0.6
  */
@@ -3337,99 +4551,162 @@ void
 clutter_actor_set_yu (ClutterActor *self,
                      ClutterUnit   y)
 {
+  ClutterGeometry old;
+
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  clutter_actor_set_positionu (self,
-                              clutter_actor_get_xu (self),
-                              y);
+  if (self->priv->position_set &&
+      self->priv->fixed_y == y)
+    return;
+
+  clutter_actor_store_old_geometry (self, &old);
+
+  self->priv->fixed_y = y;
+  clutter_actor_set_fixed_position_set (self, TRUE);
+
+  clutter_actor_notify_if_geometry_changed (self, &old);
+
+  clutter_actor_queue_relayout (self);
 }
 
 /**
  * clutter_actor_get_x
  * @self: A #ClutterActor
  *
- * Retrieves the actor's X coordinate, relative to any parent.
+ * Retrieves the X coordinate of a #ClutterActor.
+ *
+ * This function tries to "do what you mean", by returning the
+ * correct value depending on the actor's state.
+ *
+ * If the actor has a valid allocation, this function will return
+ * the X coordinate of the origin of the allocation box.
+ *
+ * If the actor has any fixed coordinate set using clutter_actor_set_x(),
+ * clutter_actor_set_position() or clutter_actor_set_geometry(), this
+ * function will return that coordinate.
+ *
+ * If both the allocation and a fixed position are missing, this function
+ * will return 0.
  *
  * Return value: the X coordinate, in pixels, ignoring any
- *   transformation (i.e. scaling, rotation).
+ *   transformation (i.e. scaling, rotation)
  */
 gint
 clutter_actor_get_x (ClutterActor *self)
 {
-  ClutterActorBox box;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  clutter_actor_query_coords (self, &box);
-
-  return CLUTTER_UNITS_TO_DEVICE (box.x1);
+  return CLUTTER_UNITS_TO_DEVICE (clutter_actor_get_xu (self));
 }
 
 /**
  * clutter_actor_get_xu
  * @self: A #ClutterActor
  *
- * Retrieves the actor's X coordinate, relative to any parent,
- * in #ClutterUnit<!-- -->s.
+ * Retrieves the X coordinate of a #ClutterActor, in #ClutterUnit<!-- -->s.
+ *
+ * This function tries to "do what you mean", by returning the
+ * correct value depending on the actor's state.
+ *
+ * If the actor has a valid allocation, this function will return
+ * the X coordinate of the origin of the allocation box.
+ *
+ * If the actor has any fixed coordinate set using clutter_actor_set_x(),
+ * clutter_actor_set_position() or clutter_actor_set_geometry(), this
+ * function will return that coordinate.
+ *
+ * If both the allocation and a fixed position are missing, this function
+ * will return 0.
  *
  * Return value: the X coordinate, in #ClutterUnit<!-- -->s, ignoring
- *   any transformation (i.e. scaling, rotation).
+ *   any transformation (i.e. scaling, rotation)
  *
  * Since: 0.6
  */
 ClutterUnit
 clutter_actor_get_xu (ClutterActor *self)
 {
-  ClutterActorBox box;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  clutter_actor_query_coords (self, &box);
-
-  return box.x1;
+  if (self->priv->needs_allocation)
+    {
+      if (self->priv->position_set)
+        return self->priv->fixed_x;
+      else
+        return 0;
+    }
+  else
+    return self->priv->allocation.x1;
 }
 
 /**
- * clutter_actor_get_y:
+ * clutter_actor_get_y
  * @self: A #ClutterActor
  *
- * Retrieves the actor's Y coordinate, relative to any parent.
+ * Retrieves the Y coordinate of a #ClutterActor.
+ *
+ * This function tries to "do what you mean", by returning the
+ * correct value depending on the actor's state.
+ *
+ * If the actor has a valid allocation, this function will return
+ * the Y coordinate of the origin of the allocation box.
+ *
+ * If the actor has any fixed coordinate set using clutter_actor_set_y(),
+ * clutter_actor_set_position() or clutter_actor_set_geometry(), this
+ * function will return that coordinate.
+ *
+ * If both the allocation and a fixed position are missing, this function
+ * will return 0.
  *
  * Return value: the Y coordinate, in pixels, ignoring any
- *   transformation (i.e. scaling, rotation).
+ *   transformation (i.e. scaling, rotation)
  */
 gint
 clutter_actor_get_y (ClutterActor *self)
 {
-  ClutterActorBox box;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  clutter_actor_query_coords (self, &box);
-
-  return CLUTTER_UNITS_TO_DEVICE (box.y1);
+  return CLUTTER_UNITS_TO_DEVICE (clutter_actor_get_yu (self));
 }
 
 /**
- * clutter_actor_get_yu:
+ * clutter_actor_get_yu
  * @self: A #ClutterActor
  *
- * Retrieves the actor's Y coordinate, relative to any parent,
- * in #ClutterUnit<!-- -->s.
+ * Retrieves the Y coordinate of a #ClutterActor, in #ClutterUnit<!-- -->s.
+ *
+ * This function tries to "do what you mean", by returning the
+ * correct value depending on the actor's state.
+ *
+ * If the actor has a valid allocation, this function will return
+ * the Y coordinate of the origin of the allocation box.
+ *
+ * If the actor has any fixed coordinate set using clutter_actor_set_y(),
+ * clutter_actor_set_position() or clutter_actor_set_geometry(), this
+ * function will return that coordinate.
  *
- * Return value: the Y coordinate, in #ClutterUnit<!-- -->s, ignoring any
- *   transformation (i.e. scaling, rotation).
+ * If both the allocation and a fixed position are missing, this function
+ * will return 0.
+ *
+ * Return value: the Y coordinate, in #ClutterUnit<!-- -->s, ignoring
+ *   any transformation (i.e. scaling, rotation)
+ *
+ * Since: 0.6
  */
 ClutterUnit
 clutter_actor_get_yu (ClutterActor *self)
 {
-  ClutterActorBox box;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  clutter_actor_query_coords (self, &box);
-
-  return box.y1;
+  if (self->priv->needs_allocation)
+    {
+      if (self->priv->position_set)
+        return self->priv->fixed_y;
+      else
+        return 0;
+    }
+  else
+    return self->priv->allocation.y1;
 }
 
 /**
@@ -3506,6 +4783,8 @@ clutter_actor_get_scalex (ClutterActor *self,
                          ClutterFixed *scale_x,
                          ClutterFixed *scale_y)
 {
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
   if (scale_x)
     *scale_x = self->priv->scale_x;
 
@@ -3528,6 +4807,8 @@ clutter_actor_get_scale (ClutterActor *self,
                         gdouble      *scale_x,
                         gdouble      *scale_y)
 {
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
   if (scale_x)
     *scale_x = CLUTTER_FIXED_TO_FLOAT (self->priv->scale_x);
 
@@ -3556,7 +4837,7 @@ clutter_actor_set_opacity (ClutterActor *self,
 }
 
 /**
- * clutter_actor_get_abs_opacity:
+ * clutter_actor_get_paint_opacity:
  * @self: A #ClutterActor
  *
  * Retrieves the absolute opacity of the actor, as it appears on the stage.
@@ -3569,10 +4850,10 @@ clutter_actor_set_opacity (ClutterActor *self,
  *
  * Return value: The actor opacity value.
  *
- * Since: 0.6
+ * Since: 0.8
  */
 guint8
-clutter_actor_get_abs_opacity (ClutterActor *self)
+clutter_actor_get_paint_opacity (ClutterActor *self)
 {
   ClutterActorPrivate *priv;
   ClutterActor *parent;
@@ -3586,7 +4867,7 @@ clutter_actor_get_abs_opacity (ClutterActor *self)
   /* Factor in the actual actors opacity with parents */
   if (G_LIKELY (parent))
     {
-      guint8 opacity = clutter_actor_get_abs_opacity (parent);
+      guint8 opacity = clutter_actor_get_paint_opacity (parent);
 
       if (opacity != 0xff)
         return (opacity * priv->opacity) / 0xff;
@@ -3603,7 +4884,7 @@ clutter_actor_get_abs_opacity (ClutterActor *self)
  * clutter_actor_set_opacity().
  *
  * For retrieving the absolute opacity of the actor inside a paint
- * virtual function, see clutter_actor_get_abs_opacity().
+ * virtual function, see clutter_actor_get_paint_opacity().
  *
  * Return value: the opacity of the actor
  */
@@ -3629,15 +4910,10 @@ clutter_actor_set_name (ClutterActor *self,
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  g_object_ref (self);
-
   g_free (self->priv->name);
-
-  if (name && name[0] != '\0')
-    self->priv->name = g_strdup(name);
+  self->priv->name = g_strdup (name);
 
   g_object_notify (G_OBJECT (self), "name");
-  g_object_unref (self);
 }
 
 /**
@@ -4224,6 +5500,7 @@ clutter_actor_set_parent (ClutterActor *self,
                          ClutterActor *parent)
 {
   ClutterMainContext *clutter_context;
+  ClutterActorPrivate *priv;
 
   clutter_context = clutter_context_get_default ();
 
@@ -4232,37 +5509,46 @@ clutter_actor_set_parent (ClutterActor *self,
   g_return_if_fail (self != parent);
   g_return_if_fail (clutter_context != NULL);
 
-  if (self->priv->parent_actor != NULL)
+  priv = self->priv;
+
+  if (priv->parent_actor != NULL)
     {
       g_warning ("Cannot set a parent on an actor which has a parent.\n"
                 "You must use clutter_actor_unparent() first.\n");
-
       return;
     }
 
   if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
     {
       g_warning ("Cannot set a parent on a toplevel actor\n");
-
       return;
     }
 
-
   g_object_ref_sink (self);
-  self->priv->parent_actor = parent;
+  priv->parent_actor = parent;
   g_signal_emit (self, actor_signals[PARENT_SET], 0, NULL);
 
-  if (CLUTTER_ACTOR_IS_REALIZED (self->priv->parent_actor))
+  if (CLUTTER_ACTOR_IS_REALIZED (priv->parent_actor))
     clutter_actor_realize (self);
 
-  if (self->priv->show_on_set_parent)
+  if (priv->show_on_set_parent)
     clutter_actor_show (self);
   
-  if (CLUTTER_ACTOR_IS_VISIBLE (self->priv->parent_actor) &&
+  if (CLUTTER_ACTOR_IS_VISIBLE (priv->parent_actor) &&
       CLUTTER_ACTOR_IS_VISIBLE (self))
     {
       clutter_actor_queue_redraw (self);
     }
+
+  /* Maintain invariant that if an actor needs layout,
+   * its parents do as well.
+   */
+  if (priv->needs_width_request ||
+      priv->needs_height_request ||
+      priv->needs_allocation)
+    {
+      clutter_actor_queue_relayout (self);
+    }
 }
 
 /**
@@ -4318,7 +5604,7 @@ clutter_actor_unparent (ClutterActor *self)
   self->priv->parent_actor = NULL;
   g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
 
-
+  /* remove the reference we acquired in clutter_actor_set_parent() */
   g_object_unref (self);
 }
 
@@ -4369,7 +5655,10 @@ clutter_actor_reparent (ClutterActor *self,
 
       g_object_ref (self);
 
-      /* FIXME: below assumes only containers can reparent */
+      /* XXX: below assumes only containers can reparent, which is
+       * a fair assumption given that composited actors will not call
+       * or need clutter_actor_reparent() for internal children.
+       */
       if (CLUTTER_IS_CONTAINER (priv->parent_actor))
         clutter_container_remove_actor (CLUTTER_CONTAINER (priv->parent_actor),
                                         self);
@@ -4397,6 +5686,7 @@ clutter_actor_reparent (ClutterActor *self,
  * @below: A #ClutterActor to raise above.
  *
  * Puts @self above @below.
+ *
  * Both actors must have the same parent.
  */
 void
@@ -4428,9 +5718,6 @@ clutter_actor_raise (ClutterActor *self,
     }
 
   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
-
-  if (CLUTTER_ACTOR_IS_VISIBLE (self))
-    clutter_actor_queue_redraw (self);
 }
 
 /**
@@ -4470,9 +5757,6 @@ clutter_actor_lower (ClutterActor *self,
     }
 
   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
-
-  if (CLUTTER_ACTOR_IS_VISIBLE (self))
-    clutter_actor_queue_redraw (self);
 }
 
 /**
@@ -4687,16 +5971,14 @@ clutter_actor_move_anchor_point (ClutterActor *self,
 
   priv = self->priv;
 
-  dx = priv->anchor_x - ax;
-  dy = priv->anchor_y - ay;
+  dx = ax - priv->anchor_x;
+  dy = ay - priv->anchor_y;
 
   priv->anchor_x = ax;
   priv->anchor_y = ay;
 
-  priv->coords.x1 -= dx;
-  priv->coords.x2 -= dx;
-  priv->coords.y1 -= dy;
-  priv->coords.y2 -= dy;
+  if (priv->position_set)
+    clutter_actor_move_by (self, -dx, -dy);
 }
 
 /**
@@ -4798,10 +6080,8 @@ clutter_actor_move_anchor_pointu (ClutterActor *self,
   priv->anchor_x = anchor_x;
   priv->anchor_y = anchor_y;
 
-  priv->coords.x1 -= dx;
-  priv->coords.x2 -= dx;
-  priv->coords.y1 -= dy;
-  priv->coords.y2 -= dy;
+  if (priv->position_set)
+    clutter_actor_move_byu (self, -dx, -dy);
 }
 
 /**
@@ -4862,10 +6142,10 @@ clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
   dx = ax - priv->anchor_x;
   dy = ay - priv->anchor_y;
 
-  priv->coords.x1 -= dx;
-  priv->coords.x2 -= dx;
-  priv->coords.y1 -= dy;
-  priv->coords.y2 -= dy;
+  if (priv->position_set)
+    {
+      clutter_actor_move_byu (self, -dx, -dy);
+    }
 }
 
 /**
@@ -4883,19 +6163,15 @@ clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
                                             ClutterGravity  gravity)
 {
   ClutterActorPrivate *priv;
-  ClutterActorBox box;
   ClutterUnit w, h, x, y;
 
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
   priv = self->priv;
 
-  clutter_actor_query_coords (self, &box);
-
   x = 0;
   y = 0;
-  w  = box.x2 - box.x1;
-  h  = box.y2 - box.y1;
+  clutter_actor_get_sizeu (self, &w, &h);
 
   switch (gravity)
     {
@@ -5348,6 +6624,8 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface)
  *
  * Note: This function is fairly computationally intensive.
  *
+ * Note: This function only works when the allocation is up-to-date, i.e. inside of paint()
+ *
  * Return value: %TRUE if conversion was successful.
  *
  * Since: 0.6
@@ -5383,14 +6661,14 @@ clutter_actor_transform_stage_point (ClutterActor  *self,
    * calls have been unrolled, and most of the math is done in fixed point.
    */
 
-  clutter_actor_get_vertices (self, v);
+  clutter_actor_get_abs_allocation_vertices (self, v);
 
   /*
    * Keeping these as ints simplifies the multiplication (no significant loss
-   * of precission here).
+   * of precision here).
    */
-  du = CLUTTER_UNITS_TO_DEVICE (priv->coords.x2 - priv->coords.x1);
-  dv = CLUTTER_UNITS_TO_DEVICE (priv->coords.y2 - priv->coords.y1);
+  du = CLUTTER_UNITS_TO_DEVICE (priv->allocation.x2 - priv->allocation.x1);
+  dv = CLUTTER_UNITS_TO_DEVICE (priv->allocation.y2 - priv->allocation.y1);
 
   if (!du || !dv)
     return FALSE;
@@ -5914,7 +7192,7 @@ clutter_actor_is_scaled (ClutterActor *self)
  * @box: return location for a #ClutterActorBox
  *
  * Calculates the bounding box represented by the four vertices; for details
- * of the vertex array see clutter_actor_get_vertices().
+ * of the vertex array see clutter_actor_get_abs_allocation_vertices().
  *
  * Since: 0.6
  */
index b9b6d30..5f6e932 100644 (file)
@@ -157,13 +157,13 @@ struct _ClutterActor
 
 /**
  * ClutterActorClass:
- * @show: signal class handler for ClutterActor::show; it must chain
+ * @show: signal class handler for #ClutterActor::show; it must chain
  *   up to the parent's implementation
  * @show_all: virtual function for containers and composite actors, to
  *   determine which children should be shown when calling
  *   clutter_actor_show_all() on the actor. Defaults to calling
  *   clutter_actor_show().
- * @hide: signal class handler for ClutterActor::hide; it must chain
+ * @hide: signal class handler for #ClutterActor::hide; it must chain
  *   up to the parent's implementation
  * @hide_all: virtual function for containers and composite actors, to
  *   determine which children should be shown when calling
@@ -172,31 +172,36 @@ struct _ClutterActor
  * @realize: virtual function, used to allocate resources for the actor;
  *   it should chain up to the parent's implementation
  * @unrealize: virtual function, used to deallocate resources allocated
- *   in ::realized; it should chain up to the parent's implementation
+ *   in ::realize; it should chain up to the parent's implementation
  * @paint: virtual function, used to paint the actor
- * @request_coords: virtual function, used when setting the coordinates
- *   of an actor
- * @query_coords: virtual function, used when querying the actor for
- *   its coordinates; it must chain up to the parent's implementation
- * @parent_set: signal class closure for the ClutterActor::parent-set
- * @destroy: signal class closure for ClutterActor::destroy
+ * @get_preferred_width: virtual function, used when querying the minimum and
+ *   natural widths of an actor
+ * @get_preferred_height: virtual function, used when querying the minimum and
+ *   natural heights of an actor
+ * @allocate: virtual function, used when settings the coordinates of an
+ *   actor
+ * @get_paint_area: virtual function, used when querying the untrasformed
+ *   bounding box of an actor; it's used internally by
+ *   clutter_actor_get_stage_area()
+ * @parent_set: signal class closure for the #ClutterActor::parent-set
+ * @destroy: signal class closure for #ClutterActor::destroy
  * @pick: virtual function, used to draw an outline of the actor with
- *   the given colour
- * @event: signal class closure for ClutterActor::event
+ *   the given color
+ * @event: signal class closure for #ClutterActor::event
  * @button_press_event: signal class closure for
- *   ClutterActor::button-press-event
+ *   #ClutterActor::button-press-event
  * @button_release_event: signal class closure for
- *   ClutterActor::button-release-event
- * @scroll_event: signal class closure for ClutterActor::scroll-event
- * @key_press_event: signal class closure for ClutterActor::key-press-event
+ *   #ClutterActor::button-release-event
+ * @scroll_event: signal class closure for #ClutterActor::scroll-event
+ * @key_press_event: signal class closure for #ClutterActor::key-press-event
  * @key_release_event: signal class closure for
- *   ClutterActor::key-release-event
- * @motion_event: signal class closure for ClutterActor::motion-event
- * @enter_event: signal class closure for ClutterActor::enter-event
- * @leave_event: signal class closure for ClutterActor::leave-event
- * @captured_event: signal class closure for ClutterActor::captured-event
- * @focus_in: signal class closure for ClutterActor::focus-in
- * @focus_out: signal class closure for ClutterActor::focus-out
+ *   #ClutterActor::key-release-event
+ * @motion_event: signal class closure for #ClutterActor::motion-event
+ * @enter_event: signal class closure for #ClutterActor::enter-event
+ * @leave_event: signal class closure for #ClutterActor::leave-event
+ * @captured_event: signal class closure for #ClutterActor::captured-event
+ * @focus_in: signal class closure for #ClutterActor::focus-in
+ * @focus_out: signal class closure for #ClutterActor::focus-out
  *
  * Base class for actors.
  */
@@ -206,23 +211,34 @@ struct _ClutterActorClass
   GInitiallyUnownedClass parent_class;
 
   /*< public >*/
-  void (* show)            (ClutterActor        *actor);
-  void (* show_all)        (ClutterActor        *actor);
-  void (* hide)            (ClutterActor        *actor);
-  void (* hide_all)        (ClutterActor        *actor);
-  void (* realize)         (ClutterActor        *actor);
-  void (* unrealize)       (ClutterActor        *actor);
-  void (* paint)           (ClutterActor        *actor);
-  void (* request_coords)  (ClutterActor        *actor,
-                            ClutterActorBox     *box);
-  void (* query_coords)    (ClutterActor        *actor,
-                            ClutterActorBox     *box);
-  void (* parent_set)      (ClutterActor        *actor,
-                            ClutterActor        *old_parent);
-
-  void (* destroy)         (ClutterActor        *actor);
-  void (* pick)            (ClutterActor        *actor,
-                            const ClutterColor  *color);
+  void (* show)                 (ClutterActor          *actor);
+  void (* show_all)             (ClutterActor          *actor);
+  void (* hide)                 (ClutterActor          *actor);
+  void (* hide_all)             (ClutterActor          *actor);
+  void (* realize)              (ClutterActor          *actor);
+  void (* unrealize)            (ClutterActor          *actor);
+  void (* paint)                (ClutterActor          *actor);
+  void (* parent_set)           (ClutterActor          *actor,
+                                 ClutterActor          *old_parent);
+
+  void (* destroy)              (ClutterActor          *actor);
+  void (* pick)                 (ClutterActor          *actor,
+                                 const ClutterColor    *color);
+
+  /* size negotiation */
+  void (* get_preferred_width)  (ClutterActor          *actor,
+                                 ClutterUnit            for_height,
+                                 ClutterUnit           *min_width_p,
+                                 ClutterUnit           *natural_width_p);
+  void (* get_preferred_height) (ClutterActor          *actor,
+                                 ClutterUnit            for_width,
+                                 ClutterUnit           *min_height_p,
+                                 ClutterUnit           *natural_height_p);
+  void (* allocate)             (ClutterActor          *actor,
+                                 const ClutterActorBox *box,
+                                 gboolean               absolute_origin_changed);
+  void (* get_paint_area)       (ClutterActor          *actor,
+                                 ClutterActorBox       *box);
 
   /* event signals */
   gboolean (* event)                (ClutterActor         *actor,
@@ -253,216 +269,246 @@ struct _ClutterActorClass
   gpointer _padding_dummy[32];
 };
 
-GType                 clutter_actor_get_type                 (void) G_GNUC_CONST;
-
-void                  clutter_actor_show                     (ClutterActor          *self);
-void                  clutter_actor_show_all                 (ClutterActor          *self);
-void                  clutter_actor_hide                     (ClutterActor          *self);
-void                  clutter_actor_hide_all                 (ClutterActor          *self);
-void                  clutter_actor_realize                  (ClutterActor          *self);
-void                  clutter_actor_unrealize                (ClutterActor          *self);
-void                  clutter_actor_paint                    (ClutterActor          *self);
-void                  clutter_actor_pick                     (ClutterActor          *self,
-                                                              const ClutterColor    *color);
-void                  clutter_actor_queue_redraw             (ClutterActor          *self);
-void                  clutter_actor_destroy                  (ClutterActor          *self);
-
-void                  clutter_actor_request_coords           (ClutterActor          *self,
-                                                              ClutterActorBox       *box);
-void                  clutter_actor_query_coords             (ClutterActor          *self,
-                                                              ClutterActorBox       *box);
-void                  clutter_actor_set_geometry             (ClutterActor          *self,
-                                                              const ClutterGeometry *geometry);
-void                  clutter_actor_get_geometry             (ClutterActor          *self,
-                                                              ClutterGeometry       *geometry);
-void                  clutter_actor_get_coords               (ClutterActor          *self,
-                                                              gint                  *x_1,
-                                                              gint                  *y_1,
-                                                              gint                  *x_2,
-                                                              gint                  *y_2);
-void                  clutter_actor_set_size                 (ClutterActor          *self,
-                                                              gint                   width,
-                                                              gint                   height);
-void                  clutter_actor_set_sizeu                (ClutterActor          *self,
-                                                              ClutterUnit            width,
-                                                              ClutterUnit            height);
-void                  clutter_actor_get_size                 (ClutterActor          *self,
-                                                              guint                 *width,
-                                                              guint                 *height);
-void                  clutter_actor_get_sizeu                (ClutterActor          *self,
-                                                              ClutterUnit           *width,
-                                                              ClutterUnit           *height);
-void                  clutter_actor_get_abs_size             (ClutterActor          *self,
-                                                              guint                 *width,
-                                                              guint                 *height);
-void                  clutter_actor_set_position             (ClutterActor          *self,
-                                                              gint                   x,
-                                                              gint                   y);
-void                  clutter_actor_set_positionu            (ClutterActor          *self,
-                                                              ClutterUnit            x,
-                                                              ClutterUnit            y);
-void                  clutter_actor_get_position             (ClutterActor          *self,
-                                                              gint                  *x,
-                                                              gint                  *y);
-void                  clutter_actor_get_positionu            (ClutterActor          *self,
-                                                              ClutterUnit           *x,
-                                                              ClutterUnit           *y);
-void                  clutter_actor_get_abs_position         (ClutterActor          *self,
-                                                              gint                  *x,
-                                                              gint                  *y);
-guint                 clutter_actor_get_width                (ClutterActor          *self);
-ClutterUnit           clutter_actor_get_widthu               (ClutterActor          *self);
-guint                 clutter_actor_get_height               (ClutterActor          *self);
-ClutterUnit           clutter_actor_get_heightu              (ClutterActor          *self);
-void                  clutter_actor_set_width                (ClutterActor          *self,
-                                                              guint                  width);
-void                  clutter_actor_set_widthu               (ClutterActor          *self,
-                                                              ClutterUnit            width);
-void                  clutter_actor_set_height               (ClutterActor          *self,
-                                                              guint                  height);
-void                  clutter_actor_set_heightu              (ClutterActor          *self,
-                                                              ClutterUnit            height);
-gint                  clutter_actor_get_x                    (ClutterActor          *self);
-ClutterUnit           clutter_actor_get_xu                   (ClutterActor          *self);
-gint                  clutter_actor_get_y                    (ClutterActor          *self);
-ClutterUnit           clutter_actor_get_yu                   (ClutterActor          *self);
-void                  clutter_actor_set_x                    (ClutterActor          *self,
-                                                              gint                   x);
-void                  clutter_actor_set_xu                   (ClutterActor          *self,
-                                                              ClutterUnit            x);
-void                  clutter_actor_set_y                    (ClutterActor          *self,
-                                                              gint                   y);
-void                  clutter_actor_set_yu                   (ClutterActor          *self,
-                                                              ClutterUnit            y);
-void                  clutter_actor_set_rotation             (ClutterActor          *self,
-                                                              ClutterRotateAxis      axis,
-                                                              gdouble                angle,
-                                                              gint                   x,
-                                                              gint                   y,
-                                                              gint                   z);
-void                  clutter_actor_set_rotationx            (ClutterActor          *self,
-                                                              ClutterRotateAxis      axis,
-                                                              ClutterFixed           angle,
-                                                              gint                   x,
-                                                              gint                   y,
-                                                              gint                   z);
-void                  clutter_actor_set_rotationu            (ClutterActor          *self,
-                                                              ClutterRotateAxis      axis,
-                                                              gdouble                angle,
-                                                              ClutterUnit            x,
-                                                              ClutterUnit            y,
-                                                              ClutterUnit            z);
-gdouble               clutter_actor_get_rotation             (ClutterActor          *self,
-                                                              ClutterRotateAxis      axis,
-                                                              gint                  *x,
-                                                              gint                  *y,
-                                                              gint                  *z);
-ClutterFixed          clutter_actor_get_rotationx            (ClutterActor          *self,
-                                                              ClutterRotateAxis      axis,
-                                                              gint                  *x,
-                                                              gint                  *y,
-                                                              gint                  *z);
-gdouble               clutter_actor_get_rotationu            (ClutterActor          *self,
-                                                              ClutterRotateAxis      axis,
-                                                              ClutterUnit           *x,
-                                                              ClutterUnit           *y,
-                                                              ClutterUnit           *z);
-
-void                  clutter_actor_set_opacity              (ClutterActor          *self,
-                                                              guint8                 opacity);
-guint8                clutter_actor_get_opacity              (ClutterActor          *self);
-guint8                clutter_actor_get_abs_opacity          (ClutterActor          *self);
-void                  clutter_actor_set_name                 (ClutterActor          *self,
-                                                              const gchar           *name);
-G_CONST_RETURN gchar *clutter_actor_get_name                 (ClutterActor          *self);
-guint32               clutter_actor_get_gid                  (ClutterActor          *self);
-void                  clutter_actor_set_clip                 (ClutterActor          *self,
-                                                              gint                   xoff,
-                                                              gint                   yoff,
-                                                              gint                   width,
-                                                              gint                   height);
-void                  clutter_actor_set_clipu                (ClutterActor          *self,
-                                                              ClutterUnit            xoff,
-                                                              ClutterUnit            yoff,
-                                                              ClutterUnit            width,
-                                                              ClutterUnit            height);
-void                  clutter_actor_remove_clip              (ClutterActor          *self);
-gboolean              clutter_actor_has_clip                 (ClutterActor          *self);
-void                  clutter_actor_get_clip                 (ClutterActor          *self,
-                                                              gint                  *xoff,
-                                                              gint                  *yoff,
-                                                              gint                  *width,
-                                                              gint                  *height);
-void                  clutter_actor_get_clipu                (ClutterActor          *self,
-                                                              ClutterUnit           *xoff,
-                                                              ClutterUnit           *yoff,
-                                                              ClutterUnit           *width,
-                                                              ClutterUnit           *height);
-void                  clutter_actor_set_parent               (ClutterActor          *self,
-                                                              ClutterActor          *parent);
-ClutterActor *        clutter_actor_get_parent               (ClutterActor          *self);
-void                  clutter_actor_reparent                 (ClutterActor          *self,
-                                                              ClutterActor          *new_parent);
-void                  clutter_actor_unparent                 (ClutterActor          *self);
-void                  clutter_actor_raise                    (ClutterActor          *self,
-                                                              ClutterActor          *below);
-void                  clutter_actor_lower                    (ClutterActor          *self,
-                                                              ClutterActor          *above);
-void                  clutter_actor_raise_top                (ClutterActor          *self);
-void                  clutter_actor_lower_bottom             (ClutterActor          *self);
-void                  clutter_actor_set_depth                (ClutterActor          *self,
-                                                              gint                   depth);
-gint                  clutter_actor_get_depth                (ClutterActor          *self);
-void                  clutter_actor_set_depthu               (ClutterActor          *self,
-                                                              ClutterUnit            depth);
-ClutterUnit           clutter_actor_get_depthu               (ClutterActor          *self);
-void                  clutter_actor_set_reactive             (ClutterActor          *actor,
-                                                              gboolean               reactive);
-gboolean              clutter_actor_get_reactive             (ClutterActor          *actor);
-void                  clutter_actor_set_scalex               (ClutterActor          *self,
-                                                              ClutterFixed           scale_x,
-                                                              ClutterFixed           scale_y);
-void                  clutter_actor_set_scale                (ClutterActor          *self,
-                                                              gdouble                scale_x,
-                                                              gdouble                scale_y);
-void                  clutter_actor_get_scalex               (ClutterActor          *self,
-                                                              ClutterFixed          *scale_x,
-                                                              ClutterFixed          *scale_y);
-void                  clutter_actor_get_scale                (ClutterActor          *self,
-                                                              gdouble               *scale_x,
-                                                              gdouble               *scale_y);
-
-void                  clutter_actor_move_by                  (ClutterActor          *self,
-                                                              gint                   dx,
-                                                              gint                   dy);
-void                  clutter_actor_move_byu                 (ClutterActor          *self,
-                                                              ClutterUnit            dx,
-                                                              ClutterUnit            dy);
-void                  clutter_actor_get_vertices             (ClutterActor          *self,
-                                                              ClutterVertex          verts[4]);
-void                  clutter_actor_get_relative_vertices    (ClutterActor          *self,
-                                                             ClutterActor          *ancestor,
-                                                              ClutterVertex          verts[4]);
-void                  clutter_actor_apply_transform_to_point (ClutterActor          *self,
-                                                              ClutterVertex         *point,
-                                                              ClutterVertex         *vertex);
-void                  clutter_actor_apply_relative_transform_to_point (ClutterActor          *self,
-                                                                      ClutterActor          *ancestor,
-                                                                      ClutterVertex         *point,
-                                                                      ClutterVertex         *vertex);
-gboolean              clutter_actor_event                    (ClutterActor          *actor,
-                                                              ClutterEvent          *event,
-                                                              gboolean               capture);
-ClutterActor *        clutter_get_actor_by_gid               (guint32                id);
-
-gboolean              clutter_actor_should_pick_paint        (ClutterActor          *self);
-
-gboolean              clutter_actor_set_shader               (ClutterActor          *self,
-                                                              ClutterShader         *shader);
-ClutterShader *       clutter_actor_get_shader               (ClutterActor          *self);
-void                  clutter_actor_set_shader_param         (ClutterActor          *self,
-                                                              const gchar           *param,
-                                                              gfloat                 value);
+GType                 clutter_actor_get_type                  (void) G_GNUC_CONST;
+
+void                  clutter_actor_show                      (ClutterActor          *self);
+void                  clutter_actor_show_all                  (ClutterActor          *self);
+void                  clutter_actor_hide                      (ClutterActor          *self);
+void                  clutter_actor_hide_all                  (ClutterActor          *self);
+void                  clutter_actor_realize                   (ClutterActor          *self);
+void                  clutter_actor_unrealize                 (ClutterActor          *self);
+void                  clutter_actor_paint                     (ClutterActor          *self);
+void                  clutter_actor_pick                      (ClutterActor          *self,
+                                                               const ClutterColor    *color);
+void                  clutter_actor_queue_redraw              (ClutterActor          *self);
+void                  clutter_actor_queue_relayout            (ClutterActor          *self);
+void                  clutter_actor_destroy                   (ClutterActor          *self);
+
+/* size negotiation */
+void                  clutter_actor_get_preferred_width       (ClutterActor          *self,
+                                                               ClutterUnit            for_height,
+                                                               ClutterUnit           *min_width_p,
+                                                               ClutterUnit           *natural_width_p);
+void                  clutter_actor_get_preferred_height      (ClutterActor          *self,
+                                                               ClutterUnit            for_width,
+                                                               ClutterUnit           *min_height_p,
+                                                               ClutterUnit           *natural_height_p);
+void                  clutter_actor_get_preferred_size        (ClutterActor          *self,
+                                                               ClutterUnit           *min_width_p,
+                                                               ClutterUnit           *min_height_p,
+                                                               ClutterUnit           *natural_width_p,
+                                                               ClutterUnit           *natural_height_p);
+void                  clutter_actor_allocate                  (ClutterActor          *self,
+                                                               const ClutterActorBox *box,
+                                                               gboolean               absolute_origin_changed);
+void                  clutter_actor_get_allocation_coords     (ClutterActor          *self,
+                                                               gint                  *x1,
+                                                               gint                  *y1,
+                                                               gint                  *x2,
+                                                               gint                  *y2);
+void                  clutter_actor_get_allocation_box        (ClutterActor          *self,
+                                                               ClutterActorBox       *box);
+void                  clutter_actor_get_allocation_geometry   (ClutterActor          *self,
+                                                               ClutterGeometry       *geom);
+void                  clutter_actor_get_allocation_vertices   (ClutterActor          *self,
+                                                              ClutterActor          *ancestor,
+                                                               ClutterVertex          verts[4]);
+void                  clutter_actor_get_paint_area            (ClutterActor          *self,
+                                                               ClutterActorBox       *box);
+
+void                  clutter_actor_set_geometry              (ClutterActor          *self,
+                                                               const ClutterGeometry *geometry);
+void                  clutter_actor_get_geometry              (ClutterActor          *self,
+                                                               ClutterGeometry       *geometry);
+void                  clutter_actor_set_size                  (ClutterActor          *self,
+                                                               gint                   width,
+                                                               gint                   height);
+void                  clutter_actor_set_sizeu                 (ClutterActor          *self,
+                                                               ClutterUnit            width,
+                                                               ClutterUnit            height);
+void                  clutter_actor_get_size                  (ClutterActor          *self,
+                                                               guint                 *width,
+                                                               guint                 *height);
+void                  clutter_actor_get_sizeu                 (ClutterActor          *self,
+                                                               ClutterUnit           *width,
+                                                               ClutterUnit           *height);
+void                  clutter_actor_get_transformed_size      (ClutterActor          *self,
+                                                               guint                 *width,
+                                                               guint                 *height);
+void                  clutter_actor_get_transformed_sizeu     (ClutterActor          *self,
+                                                               ClutterUnit           *width,
+                                                               ClutterUnit           *height);
+void                  clutter_actor_set_position              (ClutterActor          *self,
+                                                               gint                   x,
+                                                               gint                   y);
+void                  clutter_actor_set_positionu             (ClutterActor          *self,
+                                                               ClutterUnit            x,
+                                                               ClutterUnit            y);
+void                  clutter_actor_get_position              (ClutterActor          *self,
+                                                               gint                  *x,
+                                                               gint                  *y);
+void                  clutter_actor_get_positionu             (ClutterActor          *self,
+                                                               ClutterUnit           *x,
+                                                               ClutterUnit           *y);
+void                  clutter_actor_get_transformed_position  (ClutterActor          *self,
+                                                               gint                  *x,
+                                                               gint                  *y);
+void                  clutter_actor_get_transformed_positionu (ClutterActor          *self,
+                                                               ClutterUnit           *x,
+                                                               ClutterUnit           *y);
+
+gboolean              clutter_actor_get_fixed_position_set    (ClutterActor          *self);
+void                  clutter_actor_set_fixed_position_set    (ClutterActor          *self,
+                                                               gboolean               is_set);
+
+guint                 clutter_actor_get_width                 (ClutterActor          *self);
+ClutterUnit           clutter_actor_get_widthu                (ClutterActor          *self);
+guint                 clutter_actor_get_height                (ClutterActor          *self);
+ClutterUnit           clutter_actor_get_heightu               (ClutterActor          *self);
+void                  clutter_actor_set_width                 (ClutterActor          *self,
+                                                               guint                  width);
+void                  clutter_actor_set_widthu                (ClutterActor          *self,
+                                                               ClutterUnit            width);
+void                  clutter_actor_set_height                (ClutterActor          *self,
+                                                               guint                  height);
+void                  clutter_actor_set_heightu               (ClutterActor          *self,
+                                                               ClutterUnit            height);
+gint                  clutter_actor_get_x                     (ClutterActor          *self);
+ClutterUnit           clutter_actor_get_xu                    (ClutterActor          *self);
+gint                  clutter_actor_get_y                     (ClutterActor          *self);
+ClutterUnit           clutter_actor_get_yu                    (ClutterActor          *self);
+void                  clutter_actor_set_x                     (ClutterActor          *self,
+                                                               gint                   x);
+void                  clutter_actor_set_xu                    (ClutterActor          *self,
+                                                               ClutterUnit            x);
+void                  clutter_actor_set_y                     (ClutterActor          *self,
+                                                               gint                   y);
+void                  clutter_actor_set_yu                    (ClutterActor          *self,
+                                                               ClutterUnit            y);
+void                  clutter_actor_set_rotation              (ClutterActor          *self,
+                                                               ClutterRotateAxis      axis,
+                                                               gdouble                angle,
+                                                               gint                   x,
+                                                               gint                   y,
+                                                               gint                   z);
+void                  clutter_actor_set_rotationx             (ClutterActor          *self,
+                                                               ClutterRotateAxis      axis,
+                                                               ClutterFixed           angle,
+                                                               gint                   x,
+                                                               gint                   y,
+                                                               gint                   z);
+void                  clutter_actor_set_rotationu             (ClutterActor          *self,
+                                                               ClutterRotateAxis      axis,
+                                                               gdouble                angle,
+                                                               ClutterUnit            x,
+                                                               ClutterUnit            y,
+                                                               ClutterUnit            z);
+gdouble               clutter_actor_get_rotation              (ClutterActor          *self,
+                                                               ClutterRotateAxis      axis,
+                                                               gint                  *x,
+                                                               gint                  *y,
+                                                               gint                  *z);
+ClutterFixed          clutter_actor_get_rotationx             (ClutterActor          *self,
+                                                               ClutterRotateAxis      axis,
+                                                               gint                  *x,
+                                                               gint                  *y,
+                                                               gint                  *z);
+gdouble               clutter_actor_get_rotationu             (ClutterActor          *self,
+                                                               ClutterRotateAxis      axis,
+                                                               ClutterUnit           *x,
+                                                               ClutterUnit           *y,
+                                                               ClutterUnit           *z);
+
+void                  clutter_actor_set_opacity               (ClutterActor          *self,
+                                                               guint8                 opacity);
+guint8                clutter_actor_get_opacity               (ClutterActor          *self);
+guint8                clutter_actor_get_paint_opacity         (ClutterActor          *self);
+
+void                  clutter_actor_set_name                  (ClutterActor          *self,
+                                                               const gchar           *name);
+G_CONST_RETURN gchar *clutter_actor_get_name                  (ClutterActor          *self);
+
+guint32               clutter_actor_get_gid                   (ClutterActor          *self);
+void                  clutter_actor_set_clip                  (ClutterActor          *self,
+                                                               gint                   xoff,
+                                                               gint                   yoff,
+                                                               gint                   width,
+                                                               gint                   height);
+void                  clutter_actor_set_clipu                 (ClutterActor          *self,
+                                                               ClutterUnit            xoff,
+                                                               ClutterUnit            yoff,
+                                                               ClutterUnit            width,
+                                                               ClutterUnit            height);
+void                  clutter_actor_remove_clip               (ClutterActor          *self);
+gboolean              clutter_actor_has_clip                  (ClutterActor          *self);
+void                  clutter_actor_get_clip                  (ClutterActor          *self,
+                                                               gint                  *xoff,
+                                                               gint                  *yoff,
+                                                               gint                  *width,
+                                                               gint                  *height);
+void                  clutter_actor_get_clipu                 (ClutterActor          *self,
+                                                               ClutterUnit           *xoff,
+                                                               ClutterUnit           *yoff,
+                                                               ClutterUnit           *width,
+                                                               ClutterUnit           *height);
+
+void                  clutter_actor_set_parent                (ClutterActor          *self,
+                                                               ClutterActor          *parent);
+ClutterActor *        clutter_actor_get_parent                (ClutterActor          *self);
+void                  clutter_actor_reparent                  (ClutterActor          *self,
+                                                               ClutterActor          *new_parent);
+void                  clutter_actor_unparent                  (ClutterActor          *self);
+ClutterActor*         clutter_actor_get_stage                 (ClutterActor          *actor);
+
+void                  clutter_actor_raise                     (ClutterActor          *self,
+                                                               ClutterActor          *below);
+void                  clutter_actor_lower                     (ClutterActor          *self,
+                                                               ClutterActor          *above);
+void                  clutter_actor_raise_top                 (ClutterActor          *self);
+void                  clutter_actor_lower_bottom              (ClutterActor          *self);
+void                  clutter_actor_set_depth                 (ClutterActor          *self,
+                                                               gint                   depth);
+gint                  clutter_actor_get_depth                 (ClutterActor          *self);
+void                  clutter_actor_set_depthu                (ClutterActor          *self,
+                                                               ClutterUnit            depth);
+ClutterUnit           clutter_actor_get_depthu                (ClutterActor          *self);
+
+void                  clutter_actor_set_scalex                (ClutterActor          *self,
+                                                               ClutterFixed           scale_x,
+                                                               ClutterFixed           scale_y);
+void                  clutter_actor_set_scale                 (ClutterActor          *self,
+                                                               gdouble                scale_x,
+                                                               gdouble                scale_y);
+void                  clutter_actor_get_scalex                (ClutterActor          *self,
+                                                               ClutterFixed          *scale_x,
+                                                               ClutterFixed          *scale_y);
+void                  clutter_actor_get_scale                 (ClutterActor          *self,
+                                                               gdouble               *scale_x,
+                                                               gdouble               *scale_y);
+
+void                  clutter_actor_move_by                   (ClutterActor          *self,
+                                                               gint                   dx,
+                                                               gint                   dy);
+void                  clutter_actor_move_byu                  (ClutterActor          *self,
+                                                               ClutterUnit            dx,
+                                                               ClutterUnit            dy);
+
+void                  clutter_actor_set_reactive              (ClutterActor          *actor,
+                                                               gboolean               reactive);
+gboolean              clutter_actor_get_reactive              (ClutterActor          *actor);
+
+gboolean              clutter_actor_event                     (ClutterActor          *actor,
+                                                               ClutterEvent          *event,
+                                                               gboolean               capture);
+
+ClutterActor *        clutter_get_actor_by_gid                (guint32                id);
+
+gboolean              clutter_actor_set_shader                (ClutterActor          *self,
+                                                               ClutterShader         *shader);
+ClutterShader *       clutter_actor_get_shader                (ClutterActor          *self);
+void                  clutter_actor_set_shader_param          (ClutterActor          *self,
+                                                               const gchar           *param,
+                                                               gfloat                 value);
 
 void     clutter_actor_set_anchor_point               (ClutterActor   *self,
                                                        gint            anchor_x,
@@ -484,9 +530,9 @@ void     clutter_actor_get_anchor_pointu              (ClutterActor   *self,
                                                        ClutterUnit    *anchor_y);
 void     clutter_actor_set_anchor_point_from_gravity  (ClutterActor   *self,
                                                        ClutterGravity  gravity);
-
 void     clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
                                                        ClutterGravity  gravity);
+
 gboolean clutter_actor_transform_stage_point          (ClutterActor   *self,
                                                        ClutterUnit     x,
                                                        ClutterUnit     y,
@@ -494,12 +540,21 @@ gboolean clutter_actor_transform_stage_point          (ClutterActor   *self,
                                                        ClutterUnit    *y_out);
 gboolean clutter_actor_is_rotated                     (ClutterActor   *self);
 gboolean clutter_actor_is_scaled                      (ClutterActor   *self);
+gboolean clutter_actor_should_pick_paint              (ClutterActor   *self);
 
 void     clutter_actor_box_get_from_vertices          (ClutterVertex    vtx[4],
                                                       ClutterActorBox *box);
 
-ClutterActor* clutter_actor_get_stage                 (ClutterActor *actor);
+void clutter_actor_get_abs_allocation_vertices       (ClutterActor  *self,
+                                                      ClutterVertex  verts[4]);
 
+void clutter_actor_apply_transform_to_point          (ClutterActor  *self,
+                                                      ClutterVertex *point,
+                                                      ClutterVertex *vertex);
+void clutter_actor_apply_relative_transform_to_point (ClutterActor  *self,
+                                                      ClutterActor  *ancestor,
+                                                      ClutterVertex *point,
+                                                      ClutterVertex *vertex);
 G_END_DECLS
 
 #endif /* _HAVE_CLUTTER_ACTOR_H */
index 58cd7eb..bab9673 100644 (file)
@@ -69,6 +69,74 @@ struct _ClutterCloneTexturePrivate
 };
 
 static void
+clutter_clone_texture_get_preferred_width (ClutterActor *self,
+                                           ClutterUnit   for_height,
+                                           ClutterUnit  *min_width_p,
+                                           ClutterUnit  *natural_width_p)
+{
+  ClutterCloneTexturePrivate *priv = CLUTTER_CLONE_TEXTURE (self)->priv;
+  ClutterActor *parent_texture;
+  ClutterActorClass *parent_texture_class;
+
+  /* Note that by calling the get_width_request virtual method directly
+   * and skipping the clutter_actor_get_preferred_width() wrapper, we
+   * are ignoring any size request override set on the parent texture
+   * and just getting the normal size of the parent texture.
+   */
+  parent_texture = CLUTTER_ACTOR (priv->parent_texture);
+  if (!parent_texture)
+    {
+      if (min_width_p)
+        *min_width_p = 0;
+
+      if (natural_width_p)
+        *natural_width_p = 0;
+
+      return;
+    }
+
+  parent_texture_class = CLUTTER_ACTOR_GET_CLASS (parent_texture);
+  parent_texture_class->get_preferred_width (parent_texture,
+                                             for_height,
+                                             min_width_p,
+                                             natural_width_p);
+}
+
+static void
+clutter_clone_texture_get_preferred_height (ClutterActor *self,
+                                            ClutterUnit   for_width,
+                                            ClutterUnit  *min_height_p,
+                                            ClutterUnit  *natural_height_p)
+{
+  ClutterCloneTexturePrivate *priv = CLUTTER_CLONE_TEXTURE (self)->priv;
+  ClutterActor *parent_texture;
+  ClutterActorClass *parent_texture_class;
+
+  /* Note that by calling the get_height_request virtual method directly
+   * and skipping the clutter_actor_get_preferred_height() wrapper, we
+   * are ignoring any size request override set on the parent texture and
+   * just getting the normal size of the parent texture.
+   */
+  parent_texture = CLUTTER_ACTOR (priv->parent_texture);
+  if (!parent_texture)
+    {
+      if (min_height_p)
+        *min_height_p = 0;
+
+      if (natural_height_p)
+        *natural_height_p = 0;
+
+      return;
+    }
+
+  parent_texture_class = CLUTTER_ACTOR_GET_CLASS (parent_texture);
+  parent_texture_class->get_preferred_height (parent_texture,
+                                              for_width,
+                                              min_height_p,
+                                              natural_height_p);
+}
+
+static void
 clutter_clone_texture_paint (ClutterActor *self)
 {
   ClutterCloneTexturePrivate  *priv;
@@ -99,10 +167,10 @@ clutter_clone_texture_paint (ClutterActor *self)
 
   cogl_push_matrix ();
 
-  col.alpha = clutter_actor_get_abs_opacity (self);
+  col.alpha = clutter_actor_get_paint_opacity (self);
   cogl_color (&col);
 
-  clutter_actor_get_coords (self, &x_1, &y_1, &x_2, &y_2);
+  clutter_actor_get_allocation_coords (self, &x_1, &y_1, &x_2, &y_2);
 
   CLUTTER_NOTE (PAINT, "paint to x1: %i, y1: %i x2: %i, y2: %i "
                "opacity: %i",
@@ -156,14 +224,8 @@ set_parent_texture (ClutterCloneTexture *ctexture,
 
   if (texture) 
     {
-      gint width, height;
-
       priv->parent_texture = g_object_ref (texture);
 
-      /* Sync up the size to parent texture base pixbuf size. */
-      clutter_texture_get_base_size (texture, &width, &height);
-      clutter_actor_set_size (actor, width, height);
-
       /* queue a redraw if the cloned texture is already visible */
       if (CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture) &&
           was_visible)
@@ -171,6 +233,8 @@ set_parent_texture (ClutterCloneTexture *ctexture,
           clutter_actor_show (actor);
           clutter_actor_queue_redraw (actor);
         }
+
+      clutter_actor_queue_relayout (actor);
     }
       
 }
@@ -265,7 +329,12 @@ clutter_clone_texture_class_init (ClutterCloneTextureClass *klass)
   GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
 
-  actor_class->paint = clutter_clone_texture_paint;
+  actor_class->paint =
+    clutter_clone_texture_paint;
+  actor_class->get_preferred_width =
+    clutter_clone_texture_get_preferred_width;
+  actor_class->get_preferred_height =
+    clutter_clone_texture_get_preferred_height;
 
   gobject_class->finalize     = clutter_clone_texture_finalize;
   gobject_class->dispose      = clutter_clone_texture_dispose;
index b093d8b..e034d7e 100644 (file)
 #define clutter_texture_new_from_pixbuf              clutter_texture_new_from_pixbuf_DEPRECATED_BY_clutter_texture_new_from_file_OR_clutter_texture_new_AND_clutter_texture_set_from_rgb_data
 #define clutter_texture_set_pixbuf                   clutter_texture_set_pixbuf+DEPRECATED_BY_clutter_texture_set_from_rgb_data
 
+#define clutter_actor_query_coords                   clutter_actor_query_coords_REPLACED_BY_clutter_actor_get_width_request_AND_clutter_actor_get_height_request
+#define clutter_actor_request_coords                 clutter_actor_request_coords_REPLACED_BY_clutter_actor_allocate             
+
+#define clutter_actor_get_abs_position               clutter_actor_get_abs_position_REPLACED_BY_clutter_actor_get_transformed_position
+#define clutter_actor_get_abs_size                   clutter_actor_get_abs_size_REPLACED_BY_clutter_actor_get_transformed_size
+#define clutter_actor_get_abs_opacity                clutter_actor_get_abs_opacity_REPLACED_BY_clutter_actor_get_paint_opacity
+
 #endif /* CLUTTER_DEPRECATED_H */
index cb6fe7b..bb10b7f 100644 (file)
@@ -473,7 +473,7 @@ clutter_entry_paint (ClutterActor *self)
     }
 
   memcpy (&color, &priv->fgcol, sizeof (ClutterColor));
-  color.alpha = clutter_actor_get_abs_opacity (self);
+  color.alpha = clutter_actor_get_paint_opacity (self);
 
   pango_clutter_render_layout (priv->layout,
                                priv->text_x + priv->entry_padding, 0,
@@ -484,8 +484,9 @@ clutter_entry_paint (ClutterActor *self)
 }
 
 static void
-clutter_entry_request_coords (ClutterActor    *self,
-                             ClutterActorBox *box)
+clutter_entry_allocate (ClutterActor          *self,
+                        const ClutterActorBox *box,
+                        gboolean               absolute_origin_changed)
 {
   ClutterEntry *entry = CLUTTER_ENTRY (self);
   ClutterEntryPrivate *priv = entry->priv;
@@ -501,7 +502,7 @@ clutter_entry_request_coords (ClutterActor    *self,
       priv->width = width;
     }
 
-  CLUTTER_ACTOR_CLASS (clutter_entry_parent_class)->request_coords (self, box);
+  CLUTTER_ACTOR_CLASS (clutter_entry_parent_class)->allocate (self, box, absolute_origin_changed);
 }
 
 static inline void
@@ -633,13 +634,13 @@ clutter_entry_finalize (GObject *object)
 static void
 clutter_entry_class_init (ClutterEntryClass *klass)
 {
-  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
 
   klass->paint_cursor = clutter_entry_paint_cursor;
 
   actor_class->paint           = clutter_entry_paint;
-  actor_class->request_coords  = clutter_entry_request_coords;
+  actor_class->allocate        = clutter_entry_allocate;
   actor_class->key_press_event = clutter_entry_key_press;
 
   gobject_class->finalize     = clutter_entry_finalize;
index c215d2a..389f9fa 100644 (file)
@@ -33,7 +33,7 @@
  * rotating and clipping of the group will apply to the child actors.
  *
  * A #ClutterGroup's size is defined by the size and position of its children.
- * Resize requests via parent #ClutterActor API will be ignored.
+ * Resize requests via the #ClutterActor API will be ignored.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -83,14 +83,14 @@ struct _ClutterGroupPrivate
 static void
 clutter_group_paint (ClutterActor *actor)
 {
-  ClutterGroup *self = CLUTTER_GROUP(actor);
-  GList        *child_item;
+  ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
+  GList               *child_item;
 
   CLUTTER_NOTE (PAINT, "ClutterGroup paint enter");
 
-  cogl_push_matrix();
+  cogl_push_matrix ();
 
-  for (child_item = self->priv->children;
+  for (child_item = priv->children;
        child_item != NULL;
        child_item = child_item->next)
     {
@@ -102,7 +102,7 @@ clutter_group_paint (ClutterActor *actor)
        clutter_actor_paint (child);
     }
 
-  cogl_pop_matrix();
+  cogl_pop_matrix ();
 
   CLUTTER_NOTE (PAINT, "ClutterGroup paint leave");
 }
@@ -137,91 +137,286 @@ clutter_group_pick (ClutterActor       *actor,
     clutter_group_paint (actor);
 }
 
+static void
+clutter_fixed_layout_get_preferred_width (GList       *children,
+                                          ClutterUnit *min_width_p,
+                                          ClutterUnit *natural_width_p)
+{
+  GList *l;
+  ClutterUnit min_left, min_right;
+  ClutterUnit natural_left, natural_right;
+
+  min_left = 0;
+  min_right = 0;
+  natural_left = 0;
+  natural_right = 0;
+
+  for (l = children; l != NULL; l = l->next)
+    {
+      ClutterActor *child = l->data;
+      ClutterUnit child_x, child_min, child_natural;
+
+      child_x = clutter_actor_get_xu (child);
+
+      clutter_actor_get_preferred_size (child,
+                                        &child_min, NULL,
+                                        &child_natural, NULL);
+
+      if (l == children)
+        {
+          /* First child */
+          min_left = child_x;
+          natural_left = child_x;
+          min_right = min_left + child_min;
+          natural_right = natural_left + child_natural;
+        }
+      else
+        {
+          /* Union of extents with previous children */
+          if (child_x < min_left)
+            min_left = child_x;
+
+          if (child_x < natural_left)
+            natural_left = child_x;
+
+          if (child_x + child_min > min_right)
+            min_right = child_x + child_min;
+
+          if (child_x + child_natural > natural_right)
+            natural_right = child_x + child_natural;
+        }
+    }
+
+  /* The preferred size is defined as the width and height we want starting
+   * from our origin, since our allocation will set the origin; so we now
+   * need to remove any part of the request that is to the left of the origin.
+   */
+  if (min_left < 0)
+    min_left = 0;
+
+  if (natural_left < 0)
+    natural_left = 0;
+
+  if (min_right < 0)
+    min_right = 0;
+
+  if (natural_right < 0)
+    natural_right = 0;
+
+  g_assert (min_right >= min_left);
+  g_assert (natural_right >= natural_left);
+
+  if (min_width_p)
+    *min_width_p = min_right - min_left;
+
+  if (natural_width_p)
+    *natural_width_p = natural_right - min_left;
+}
 
 static void
-clutter_group_request_coords (ClutterActor    *self,
-                             ClutterActorBox *box)
+clutter_fixed_layout_get_preferred_height (GList       *children,
+                                           ClutterUnit *min_height_p,
+                                           ClutterUnit *natural_height_p)
 {
-  ClutterActorBox cbox;
+  GList *l;
+  ClutterUnit min_top, min_bottom;
+  ClutterUnit natural_top, natural_bottom;
+
+  min_top = 0;
+  min_bottom = 0;
+  natural_top = 0;
+  natural_bottom = 0;
 
-  clutter_actor_query_coords (self, &cbox);
+  for (l = children; l != NULL; l = l->next)
+    {
+      ClutterActor *child = l->data;
+      ClutterUnit child_y, child_min, child_natural;
+
+      child_y = clutter_actor_get_yu (child);
+
+      clutter_actor_get_preferred_size (child,
+                                        NULL, &child_min,
+                                        NULL, &child_natural);
+
+      if (l == children)
+        {
+          /* First child */
+          min_top = child_y;
+          natural_top = child_y;
+          min_bottom = min_top + child_min;
+          natural_bottom = natural_top + child_natural;
+        }
+      else
+        {
+          /* Union of extents with previous children */
+          if (child_y < min_top)
+            min_top = child_y;
+
+          if (child_y < natural_top)
+            natural_top = child_y;
+
+          if (child_y + child_min > min_bottom)
+            min_bottom = child_y + child_min;
+
+          if (child_y + child_natural > natural_bottom)
+            natural_bottom = child_y + child_natural;
+        }
+    }
+
+  /* The preferred size is defined as the width and height we want starting
+   * from our origin, since our allocation will set the origin; so we now
+   * need to remove any part of the request that is above the origin.
+   */
+  if (min_top < 0)
+    min_top = 0;
 
-  /* Only positioning works.
-   * Sizing requests fail, use scale() instead
-  */
-  box->x2 = box->x1 + (cbox.x2 - cbox.x1);
-  box->y2 = box->y1 + (cbox.y2 - cbox.y1);
+  if (natural_top < 0)
+    natural_top = 0;
 
-  CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->request_coords (self, box);
+  if (min_bottom < 0)
+    min_bottom = 0;
+
+  if (natural_bottom < 0)
+    natural_bottom = 0;
+
+  g_assert (min_bottom >= min_top);
+  g_assert (natural_bottom >= natural_top);
+
+  if (min_height_p)
+    *min_height_p = min_bottom - min_top;
+
+  if (natural_height_p)
+    *natural_height_p = natural_bottom - min_top;
 }
 
 static void
-clutter_group_query_coords (ClutterActor        *self,
-                           ClutterActorBox     *box)
+clutter_fixed_layout_allocate (GList    *children,
+                               gboolean  absolute_origin_changed)
 {
-  ClutterGroupPrivate *priv;
-  GList               *child_item;
+  GList *l;
+
+  for (l = children; l != NULL; l = l->next)
+    {
+      ClutterActor *child = l->data;
+      ClutterUnit child_x, child_y;
+      ClutterUnit natural_width, natural_height;
+      ClutterActorBox child_box;
+      
+      child_x = clutter_actor_get_xu (child);
+      child_y = clutter_actor_get_yu (child);
+
+      /* All children get their position and natural size (the
+       * container's allocation is flat-out ignored).
+       */
+      clutter_actor_get_preferred_size (child,
+                                        NULL, NULL,
+                                        &natural_width,
+                                        &natural_height);
+
+      child_box.x1 = child_x;
+      child_box.y1 = child_y;
+      child_box.x2 = child_box.x1 + natural_width;
+      child_box.y2 = child_box.y1 + natural_height;
+
+      clutter_actor_allocate (child, &child_box, absolute_origin_changed);
+    }
+}
+
+static void
+clutter_group_get_preferred_width (ClutterActor *self,
+                                   ClutterUnit   for_height,
+                                   ClutterUnit  *min_width_p,
+                                   ClutterUnit  *natural_width_p)
+{
+  ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
+
+  /* for_height is irrelevant to the fixed layout, so it's not used */
+  clutter_fixed_layout_get_preferred_width (priv->children,
+                                            min_width_p,
+                                            natural_width_p);
+}
+
+static void
+clutter_group_get_preferred_height (ClutterActor *self,
+                                    ClutterUnit   for_width,
+                                    ClutterUnit  *min_height_p,
+                                    ClutterUnit  *natural_height_p)
+{
+  ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
+
+  /* for_width is irrelevant to the fixed layout, so it's not used */
+  clutter_fixed_layout_get_preferred_height (priv->children,
+                                             min_height_p,
+                                             natural_height_p);
+}
+
+static void
+clutter_group_allocate (ClutterActor          *self,
+                        const ClutterActorBox *box,
+                        gboolean               origin_changed)
+{
+  ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
 
-  priv = CLUTTER_GROUP(self)->priv;
+  /* chain up to set actor->allocation */
+  CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->allocate (self, box,
+                                                              origin_changed);
 
-  child_item = priv->children;
+  /* Note that fixed-layout allocation of children does not care what
+   * allocation the container received, so "box" is not passed in
+   * here. We do not require that children's allocations are completely
+   * contained by our own.
+   */
+  clutter_fixed_layout_allocate (priv->children, origin_changed);
+}
 
-  /* FIXME: Cache these values */
-  box->x2 = box->x1;
-  box->y2 = box->y1;
+static void
+clutter_group_get_paint_area (ClutterActor    *self,
+                              ClutterActorBox *box)
+{
+  ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
 
-  if (child_item)
+  /* Our area is the union of all child boxes. */
+  if (!priv->children)
     {
-      do
-       {
-         ClutterActor    *child = CLUTTER_ACTOR(child_item->data);
-         ClutterActorBox  cbox;
-
-#if 0     /* XXX - Leave this post 0.6 ??? */
-         if (clutter_actor_is_scaled (child) ||
-             clutter_actor_is_rotated (child))
-           {
-             ClutterVertex vtx[4];
-
-             clutter_actor_get_relative_vertices (child, self, vtx);
-             clutter_actor_box_get_from_vertices (vtx, &cbox);
-           }
-         else
-#endif
-           {
-             gint            anchor_x;
-             gint            anchor_y;
-
-             clutter_actor_query_coords (child, &cbox);
-
-             /*
-              * Must adjust these by the anchor point, as we need the box
-              * to be relative to the top-left corner of the parent
-              */
-             clutter_actor_get_anchor_pointu (child, &anchor_x, &anchor_y);
-
-             cbox.x1 -= anchor_x;
-             cbox.x2 -= anchor_x;
-             cbox.y1 -= anchor_y;
-             cbox.y2 -= anchor_y;
-           }
-
-         /* FIXME: now that we go into the trouble of working out the
-          * projected sizes, we should do better than this (probably resize
-          * the box in all direction as required).
-          *
-          * Ignore any children with offscreen ( negaive )
-          * positions.
-          *
-          * Also x1 and x2 will be set by parent caller.
-          */
-         if (box->x2 - box->x1 < cbox.x2)
-           box->x2 = cbox.x2 + box->x1;
-
-         if (box->y2 - box->y1 < cbox.y2)
-           box->y2 = cbox.y2 + box->y1;
-       }
-      while ((child_item = g_list_next(child_item)) != NULL);
+      /* Only get our allocation if no children;
+       * if we do have children, we don't want this
+       * because the allocation is based on the children's
+       * untransformed layout, and we want the union of
+       * their transformed boxes (their paint boxes).
+       */
+      clutter_actor_get_allocation_box (self, box);
+    }
+  else
+    {
+      ClutterActorBox all_box = { 0, }; /* initialize to silence gcc */
+      GList *l;
+      
+      for (l = priv->children; l != NULL; l = l->next)
+        {
+          ClutterActor *child = l->data;
+          ClutterActorBox child_box = { 0, };
+
+          clutter_actor_get_paint_area (child, &child_box);
+
+          if (l == priv->children)
+            all_box = child_box;
+          else
+            {
+              if (child_box.x1 < all_box.x1)
+                all_box.x1 = child_box.x1;
+
+              if (child_box.y1 < all_box.y1)
+                all_box.y1 = child_box.y1;
+
+              if (child_box.x2 > all_box.x2)
+                all_box.x2 = child_box.x2;
+
+              if (child_box.y2 > all_box.y2)
+                all_box.y2 = child_box.y2;
+            }
+        }
+
+      *box = all_box;
     }
 }
 
@@ -234,6 +429,8 @@ clutter_group_dispose (GObject *object)
   if (priv->children)
     {
       g_list_foreach (priv->children, (GFunc) clutter_actor_destroy, NULL);
+      g_list_free (priv->children);
+
       priv->children = NULL;
     }
 
@@ -277,6 +474,11 @@ clutter_group_real_add (ClutterContainer *container,
   priv->children = g_list_append (priv->children, actor);
   clutter_actor_set_parent (actor, CLUTTER_ACTOR (group));
 
+  /* queue a relayout, to get the correct positioning inside
+   * the ::actor-added signal handlers
+   */
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (group));
+
   g_signal_emit_by_name (container, "actor-added", actor);
 
   clutter_group_sort_depth_order (group);
@@ -303,6 +505,11 @@ clutter_group_real_remove (ClutterContainer *container,
   priv->children = g_list_remove (priv->children, actor);
   clutter_actor_unparent (actor);
 
+  /* queue a relayout, to get the correct positioning inside
+   * the ::actor-removed signal handlers
+   */
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (group));
+
   /* at this point, the actor passed to the "actor-removed" signal
    * handlers is not parented anymore to the container but since we
    * are holding a reference on it, it's still valid
@@ -459,11 +666,14 @@ clutter_group_class_init (ClutterGroupClass *klass)
   actor_class->pick            = clutter_group_pick;
   actor_class->show_all        = clutter_group_real_show_all;
   actor_class->hide_all        = clutter_group_real_hide_all;
-  actor_class->request_coords  = clutter_group_request_coords;
-  actor_class->query_coords    = clutter_group_query_coords;
   actor_class->realize         = clutter_group_realize;
   actor_class->unrealize       = clutter_group_unrealize;
 
+  actor_class->get_preferred_width  = clutter_group_get_preferred_width;
+  actor_class->get_preferred_height = clutter_group_get_preferred_height;
+  actor_class->allocate             = clutter_group_allocate;
+  actor_class->get_paint_area       = clutter_group_get_paint_area;
+
   /**
    * ClutterGroup::add:
    * @group: the #ClutterGroup that received the signal
index 09e5595..5b3080d 100644 (file)
@@ -48,7 +48,7 @@
 G_DEFINE_TYPE (ClutterLabel, clutter_label, CLUTTER_TYPE_ACTOR)
 
 /* Probably move into main */
-static PangoContext         *_context  = NULL;
+static PangoContext *_context = NULL;
 
 enum
 {
@@ -75,8 +75,6 @@ struct _ClutterLabelPrivate
   
   ClutterColor          fgcol;
 
-  ClutterActorBox       allocation;
-  
   gchar                *text;
   gchar                *font_name;
   
@@ -95,194 +93,83 @@ struct _ClutterLabelPrivate
   PangoAttrList        *attrs;
   PangoAttrList        *effective_attrs;
   PangoLayout          *layout;
-  gint                  width_chars;
-  gint                  wrap_width;
 };
 
-static gint
-get_label_char_width (ClutterLabel *label)
+/*
+ * clutter_label_create_layout:
+ * @label: a #ClutterLabel
+ * @allocation_width: the width of the layout, or -1
+ *
+ * Creates a new #PangoLayout for the given @allocation_width, using
+ * the layout properties of the @label.
+ */
+static PangoLayout *
+clutter_label_create_layout (ClutterLabel *label,
+                             ClutterUnit   allocation_width)
 {
   ClutterLabelPrivate *priv = label->priv;
-  PangoContext *context;
-  PangoFontMetrics *metrics;
-  gint char_width, digit_width, char_pixels, w;
-        
-  context = pango_layout_get_context (priv->layout);
-  metrics = pango_context_get_metrics (context, priv->font_desc, 
-                                       pango_context_get_language (context));
-  char_width = pango_font_metrics_get_approximate_char_width (metrics);
-  digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
-  char_pixels = MAX (char_width, digit_width);
-  pango_font_metrics_unref (metrics);
-
-  if (priv->width_chars < 0)
-    {
-      PangoRectangle rect;
+  PangoLayout *layout;
 
-      pango_layout_set_width (priv->layout, -1);
-      pango_layout_get_extents (priv->layout, NULL, &rect);
+  layout = pango_layout_new (_context);
 
-      w = char_pixels * 5;
-      w = MIN (rect.width, w);
-    }
-  else
-    {
-      /* enforce minimum width for ellipsized labels at ~5 chars */
-      w = char_pixels * MAX (priv->width_chars, 5);
-    }
+  if (priv->effective_attrs)
+    pango_layout_set_attributes (layout, priv->effective_attrs);
 
-  return w;
-}
+  pango_layout_set_alignment (layout, priv->alignment);
+  pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode);
 
-static gint
-get_label_wrap_width (ClutterLabel *label)
-{
-  ClutterLabelPrivate *priv = label->priv;
+  pango_layout_set_font_description (layout, priv->font_desc);
+  pango_layout_set_justify (layout, priv->justify);
 
-  if (priv->wrap_width < 0)
+  if (priv->text)
     {
-      if (priv->width_chars > 0)
-        priv->wrap_width = get_label_char_width (label);
+      if (!priv->use_markup)
+        pango_layout_set_text (layout, priv->text, -1);
       else
-        {
-          PangoLayout *tmp;
-
-          tmp = pango_layout_new (_context);
-          pango_layout_set_font_description (tmp, priv->font_desc);
-          pango_layout_set_text (tmp, "This is a very long string, which "
-                                      "should be enough for a wrap width.",
-                                 -1);
-          pango_layout_get_size (tmp, &priv->wrap_width, NULL);
-          g_object_unref (tmp);
-        }
+        pango_layout_set_markup (layout, priv->text, -1);
     }
 
-  return priv->wrap_width;
-}
-
-static void
-clutter_label_ensure_layout (ClutterLabel *label)
-{
-  ClutterLabelPrivate *priv;
-  ClutterUnit raw_width;
-  gint width;
-
-  priv  = label->priv;
+  if (allocation_width > 0)
+    {
+      int layout_width, layout_height;
 
-  /* use the last size requested, if any */
-  raw_width = priv->allocation.x2 - priv->allocation.x1;
-  width = CLUTTER_UNITS_TO_DEVICE (raw_width);
+      pango_layout_get_size (layout, &layout_width, &layout_height);
 
-  if (!priv->layout)
-    {
-      priv->layout = pango_layout_new (_context);
+      /* No need to set ellipsize or wrap if we already have enough
+       * space, since we don't want to make the layout wider than it
+       * would be otherwise.
+       */
 
-      if (priv->effective_attrs)
-       pango_layout_set_attributes (priv->layout, priv->effective_attrs);
-  
-      pango_layout_set_alignment (priv->layout, priv->alignment);
-      pango_layout_set_ellipsize (priv->layout, priv->ellipsize);
-      pango_layout_set_single_paragraph_mode (priv->layout, 
-                                             priv->single_line_mode);
-      
-      pango_layout_set_font_description (priv->layout, priv->font_desc);
-      pango_layout_set_justify (priv->layout, priv->justify);
-     
-      if (priv->text)
-        { 
-          if (!priv->use_markup)
-            pango_layout_set_text (priv->layout, priv->text, -1);
-          else
-            pango_layout_set_markup (priv->layout, priv->text, -1);
-        }
-      
-      if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
-        pango_layout_set_width (priv->layout, raw_width > 0 ? CLUTTER_UNITS_TO_PANGO_UNIT (raw_width)
-                                                            : -1);
-      else if (priv->wrap)
+      if (CLUTTER_UNITS_FROM_PANGO_UNIT (layout_width) > allocation_width)
         {
-          pango_layout_set_wrap  (priv->layout, priv->wrap_mode);
-
-          if (width > 0)
-           pango_layout_set_width (priv->layout, CLUTTER_UNITS_TO_PANGO_UNIT (raw_width));
-          else
+          if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
             {
-              /* this was adapted from the GtkLabel code */
-              ClutterActor *stage = clutter_stage_get_default ();
-              gint stage_width = clutter_actor_get_width (stage);
-              gint longest_paragraph, height, wrap_width;
-              PangoRectangle logical_rect;
-
-              pango_layout_set_width (priv->layout, -1);
-              pango_layout_get_extents (priv->layout, NULL, &logical_rect);
-
-              width = logical_rect.width;
-
-              longest_paragraph = width;
-
-              wrap_width = get_label_wrap_width (label);
-              width = MAX (width, wrap_width);
-              width = MIN (width, PANGO_SCALE * (stage_width + 1) / 2);
-
-              pango_layout_set_width (priv->layout, width);
-              pango_layout_get_extents (priv->layout, NULL, &logical_rect);
-              width = logical_rect.width;
-              height = logical_rect.height;
-
-              if (longest_paragraph > 0)
-                {
-                  gint n_lines, perfect_width;
-
-                  n_lines = pango_layout_get_line_count (priv->layout);
-                  perfect_width = (longest_paragraph + n_lines - 1) / n_lines;
-
-                  if (perfect_width < width)
-                    {
-                      pango_layout_set_width (priv->layout, perfect_width);
-                      pango_layout_get_extents (priv->layout, NULL,
-                                                &logical_rect);
-
-                      if (logical_rect.height <= height)
-                        width = logical_rect.width = width;
-                      else
-                        {
-                          gint mid_width = (perfect_width + width) / 2;
-
-                          if (mid_width > perfect_width)
-                            {
-                              pango_layout_set_width (priv->layout, mid_width);
-                              pango_layout_get_extents (priv->layout, NULL,
-                                                        &logical_rect);
-
-                              if (logical_rect.height <= height);
-                                width = logical_rect.width;
-                            }
-                        }
-                    }
-                }
-
-              pango_layout_set_width (priv->layout, width);
+              gint width;
+
+              width = allocation_width > 0
+                ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
+                : -1;
+
+              pango_layout_set_ellipsize (layout, priv->ellipsize);
+              pango_layout_set_width (layout, width);
             }
-       }
-      else
-       pango_layout_set_width (priv->layout, raw_width > 0 ? CLUTTER_UNITS_TO_PANGO_UNIT (raw_width) 
-                                                            : -1);
+          else if (priv->wrap)
+            {
+              gint width;
+
+              width = allocation_width > 0
+                ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
+                : -1;
 
-      /* Prime the glyph cache */
-      pango_clutter_ensure_glyph_cache_for_layout (priv->layout);
+              pango_layout_set_wrap (layout, priv->wrap_mode);
+              pango_layout_set_width (layout, width);
+            }
+        }
     }
 
-  CLUTTER_NOTE (ACTOR, "Label width set to %d pixels", width);
-}
+  pango_clutter_ensure_glyph_cache_for_layout (layout);
 
-static void
-clutter_label_clear_layout (ClutterLabel *label)
-{
-  if (label->priv->layout)
-    {
-      g_object_unref (label->priv->layout);
-      label->priv->layout = NULL;
-    }
+  return layout;
 }
 
 static void
@@ -294,8 +181,7 @@ clutter_label_paint (ClutterActor *self)
 
   if (priv->font_desc == NULL || priv->text == NULL)
     {
-      CLUTTER_NOTE (ACTOR, "layout: %p, desc: %p, text %p",
-                   priv->layout,
+      CLUTTER_NOTE (ACTOR, "desc: %p, text %p",
                    priv->font_desc ? priv->font_desc : 0x0,
                    priv->text ? priv->text : 0x0);
       return;
@@ -303,85 +189,115 @@ clutter_label_paint (ClutterActor *self)
 
   CLUTTER_NOTE (PAINT, "painting label (text:`%s')", priv->text);
 
-  clutter_label_ensure_layout (label);
+  /* XXX - this should never happen, as the layout is always
+   * recreated when the label allocation changes
+   */
+  if (G_UNLIKELY (!priv->layout))
+    {
+      ClutterActorBox alloc = { 0, };
+
+      clutter_actor_get_allocation_box (self, &alloc);
+      priv->layout = clutter_label_create_layout (label, alloc.x2 - alloc.x1);
+    }
 
   memcpy (&color, &priv->fgcol, sizeof (ClutterColor));
-  color.alpha = clutter_actor_get_abs_opacity (self);
+  color.alpha = clutter_actor_get_paint_opacity (self);
 
   pango_clutter_render_layout (priv->layout, 0, 0, &color, 0);
 }
 
 static void
-clutter_label_query_coords (ClutterActor    *self,
-                           ClutterActorBox *box)
-{
-  ClutterLabel *label = CLUTTER_LABEL(self);
-  ClutterLabelPrivate *priv;
-  ClutterActorBox layout_box = { 0, };
-  PangoRectangle logical_rect;
+clutter_label_get_preferred_width (ClutterActor *self,
+                                   ClutterUnit   for_height,
+                                   ClutterUnit  *min_width_p,
+                                   ClutterUnit  *natural_width_p)
+{ 
+  ClutterLabel *label = CLUTTER_LABEL (self);
+  ClutterLabelPrivate *priv = label->priv;
+  PangoRectangle logical_rect = { 0, };
+  PangoLayout *layout;
 
-  priv = label->priv;
+  /* we create a layout to compute the width request; we ignore the
+   * passed height because ClutterLabel is a height-for-width actor
+   */
+  layout = clutter_label_create_layout (label, -1);
 
-  if (priv->wrap)
-    clutter_label_clear_layout (label);
+  pango_layout_get_extents (layout, NULL, &logical_rect);
 
-  clutter_label_ensure_layout (label);
+  if (min_width_p)
+    {
+      if (priv->wrap || priv->ellipsize)
+        *min_width_p = 1;
+      else
+        *min_width_p = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.width);
+    }
 
-  pango_layout_get_extents (priv->layout, NULL, &logical_rect);
+  if (natural_width_p)
+    *natural_width_p = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.width);
+
+  g_object_unref (layout);
+}
 
-  layout_box.x1 = box->x1;
-  layout_box.x2 = box->x1 + CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.width);
-  layout_box.y1 = box->y1;
-  layout_box.y2 = box->y1 + CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.height);
+static void
+clutter_label_get_preferred_height (ClutterActor *self,
+                                    ClutterUnit   for_width,
+                                    ClutterUnit  *min_height_p,
+                                    ClutterUnit  *natural_height_p)
+{
+  ClutterLabel *label = CLUTTER_LABEL (self);
 
-  if ((priv->allocation.x2 - priv->allocation.x1) > 0)
+  if (for_width == 0)
     {
-      ClutterUnit alloc_width, alloc_height;
+      if (min_height_p)
+        *min_height_p = 0;
 
-      alloc_width = priv->allocation.x2 - priv->allocation.x1;
-      alloc_height = priv->allocation.y2 - priv->allocation.y1;
+      if (natural_height_p)
+        *natural_height_p = 0;
+    }
+  else
+    {
+      PangoLayout *layout;
+      PangoRectangle logical_rect = { 0, };
+      ClutterUnit height;
 
-      if ((alloc_width >= (layout_box.x2 - layout_box.x1)) &&
-          (alloc_height >= (layout_box.y2 - layout_box.y1)))
-        *box = priv->allocation;
-      else
-        *box = layout_box;
+      /* we create a new layout to compute the height for the
+       * given width and then discard it
+       */
+      layout = clutter_label_create_layout (label, for_width);
 
-      return;
+      pango_layout_get_extents (layout, NULL, &logical_rect);
+      height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.height);
+
+      if (min_height_p)
+        *min_height_p = height;
+
+      if (natural_height_p)
+        *natural_height_p = height;
+
+      g_object_unref (layout);
     }
-  else
-    *box = layout_box;
 }
 
 static void
-clutter_label_request_coords (ClutterActor    *self,
-                             ClutterActorBox *box)
+clutter_label_allocate (ClutterActor          *self,
+                        const ClutterActorBox *box,
+                        gboolean               origin_changed)
 {
   ClutterLabel *label = CLUTTER_LABEL (self);
   ClutterLabelPrivate *priv = label->priv;
+  ClutterActorClass *parent_class;
 
-  if (priv->ellipsize)
+  /* the allocation was changed, so we must recreate the layout */
+  if (priv->layout)
     {
-      if (priv->layout)
-        {
-          gint width;
-          PangoRectangle logical;
-
-          width = CLUTTER_UNITS_TO_PANGO_UNIT (box->x2 - box->x1);
-
-          pango_layout_set_width (priv->layout, -1);
-          pango_layout_get_extents (priv->layout, NULL, &logical);
-
-          if (logical.width > width)
-            pango_layout_set_width (priv->layout, width);
-        }
+      g_object_unref (priv->layout);
+      priv->layout = NULL;
     }
-  else
-    clutter_label_clear_layout (label);
 
-  priv->allocation = *box;
+  priv->layout = clutter_label_create_layout (label, box->x2 - box->x1);
 
-  CLUTTER_ACTOR_CLASS (clutter_label_parent_class)->request_coords (self, box);
+  parent_class = CLUTTER_ACTOR_CLASS (clutter_label_parent_class);
+  parent_class->allocate (self, box, origin_changed);
 }
 
 static void 
@@ -532,9 +448,10 @@ clutter_label_class_init (ClutterLabelClass *klass)
   GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
 
-  actor_class->paint           = clutter_label_paint;
-  actor_class->request_coords  = clutter_label_request_coords;
-  actor_class->query_coords    = clutter_label_query_coords;
+  actor_class->paint                = clutter_label_paint;
+  actor_class->get_preferred_width  = clutter_label_get_preferred_width;
+  actor_class->get_preferred_height = clutter_label_get_preferred_height;
+  actor_class->allocate             = clutter_label_allocate;
 
   gobject_class->finalize     = clutter_label_finalize;
   gobject_class->dispose      = clutter_label_dispose;
@@ -667,9 +584,6 @@ clutter_label_init (ClutterLabel *self)
   priv->text          = NULL;
   priv->attrs         = NULL;
 
-  priv->width_chars   = -1;
-  priv->wrap_width    = -1;
-
   priv->fgcol.red     = 0;
   priv->fgcol.green   = 0;
   priv->fgcol.blue    = 0;
@@ -768,21 +682,12 @@ clutter_label_set_text (ClutterLabel *label,
 
   priv = label->priv;
 
-  g_object_ref (label);
-
   g_free (priv->text);
   priv->text = g_strdup (text);
 
-  clutter_label_clear_layout (label);   
-  /* Recreate the layout now so that the glyph cache will be primed
-     outside of the paint run */
-  clutter_label_ensure_layout (label);
-
-  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
-    clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
 
   g_object_notify (G_OBJECT (label), "text");
-  g_object_unref (label);
 }
 
 /**
@@ -841,8 +746,6 @@ clutter_label_set_font_name (ClutterLabel *label,
       return;
     }
 
-  g_object_ref (label);
-
   g_free (priv->font_name);
   priv->font_name = g_strdup (font_name);
   
@@ -850,21 +753,11 @@ clutter_label_set_font_name (ClutterLabel *label,
     pango_font_description_free (priv->font_desc);
 
   priv->font_desc = desc;
-  priv->wrap_width = -1;
 
   if (label->priv->text && label->priv->text[0] != '\0')
-    {
-      clutter_label_clear_layout (label);      
-      /* Recreate the layout now so that the glyph cache will be
-        primed outside of the paint run */
-      clutter_label_ensure_layout (label);
-      
-      if (CLUTTER_ACTOR_IS_VISIBLE (label))
-       clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
-    }
+    clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
   
   g_object_notify (G_OBJECT (label), "font-name");
-  g_object_unref (label);
 }
 
 
@@ -953,20 +846,11 @@ clutter_label_set_ellipsize (ClutterLabel          *label,
 
   if ((PangoEllipsizeMode) priv->ellipsize != mode)
     {
-      g_object_ref (label);
-
       priv->ellipsize = mode;
 
-      clutter_label_clear_layout (label);      
-      /* Recreate the layout now so that the glyph cache will be
-        primed outside of the paint run */
-      clutter_label_ensure_layout (label);
-      
-      if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
-       clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
 
       g_object_notify (G_OBJECT (label), "ellipsize");
-      g_object_unref (label);
     }
 }
 
@@ -1015,17 +899,11 @@ clutter_label_set_line_wrap (ClutterLabel *label,
   
   if (priv->wrap != wrap)
     {
-      g_object_ref (label);
-
       priv->wrap = wrap;
 
-      clutter_label_clear_layout (label);            
-
-      if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (label)))
-       clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
 
       g_object_notify (G_OBJECT (label), "wrap");
-      g_object_unref (label);
     }
 }
 
@@ -1071,17 +949,11 @@ clutter_label_set_line_wrap_mode (ClutterLabel *label,
   
   if (priv->wrap_mode != wrap_mode)
     {
-      g_object_ref (label);
-
       priv->wrap_mode = wrap_mode;
 
-      clutter_label_clear_layout (label);      
-
-      if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (label)))
-       clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
 
       g_object_notify (G_OBJECT (label), "wrap-mode");
-      g_object_unref (label);
     }
 }
 
@@ -1118,13 +990,11 @@ clutter_label_get_line_wrap_mode (ClutterLabel *label)
  *
  * Since: 0.2
  **/
-PangoLayout*
+PangoLayout *
 clutter_label_get_layout (ClutterLabel *label)
 {
   g_return_val_if_fail (CLUTTER_IS_LABEL (label), NULL);
 
-  clutter_label_ensure_layout (label);
-
   return label->priv->layout;
 }
 
@@ -1136,8 +1006,6 @@ clutter_label_set_attributes_internal (ClutterLabel  *label,
 
   priv = label->priv;
 
-  g_object_ref (label);
-
   if (attrs)
     pango_attr_list_ref (attrs);
   
@@ -1148,6 +1016,7 @@ clutter_label_set_attributes_internal (ClutterLabel  *label,
     {
       if (attrs)
        pango_attr_list_ref (attrs);
+
       if (priv->effective_attrs)
        pango_attr_list_unref (priv->effective_attrs);
       priv->effective_attrs = attrs;
@@ -1155,7 +1024,6 @@ clutter_label_set_attributes_internal (ClutterLabel  *label,
 
   label->priv->attrs = attrs;
   g_object_notify (G_OBJECT (label), "attributes");
-  g_object_unref (label);
 }
 
 /**
@@ -1178,10 +1046,7 @@ clutter_label_set_attributes (ClutterLabel     *label,
 
   clutter_label_set_attributes_internal (label, attrs);
 
-  clutter_label_clear_layout (label);  
-
-  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
-    clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
 }
 
 /**
@@ -1224,19 +1089,11 @@ clutter_label_set_use_markup (ClutterLabel *label,
 
   if (priv->use_markup != setting)
     {
-      g_object_ref (label);
-
       priv->use_markup = setting;
-      clutter_label_clear_layout (label);
-      /* Recreate the layout now so that the glyph cache will be
-        primed outside of the paint run */
-      clutter_label_ensure_layout (label);
 
-      if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (label)))
-       clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
 
       g_object_notify (G_OBJECT (label), "use-markup");
-      g_object_unref (label);
     }
 }
 
@@ -1277,16 +1134,11 @@ clutter_label_set_alignment (ClutterLabel   *label,
 
   if (priv->alignment != alignment)
     {
-      g_object_ref (label);
-
       priv->alignment = alignment;
-      clutter_label_clear_layout (label);
 
-      if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (label)))
-       clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
 
       g_object_notify (G_OBJECT (label), "alignment");
-      g_object_unref (label);
     }
 }
 
@@ -1333,10 +1185,7 @@ clutter_label_set_justify (ClutterLabel *label,
     {
       priv->justify = justify;
 
-      clutter_label_clear_layout (label);
-
-      if (CLUTTER_ACTOR_IS_VISIBLE (label))
-       clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
 
       g_object_notify (G_OBJECT (label), "justify");
     }
index 1e64f65..38dec0b 100644 (file)
@@ -106,8 +106,41 @@ clutter_get_show_fps (void)
   return clutter_show_fps;
 }
 
-static inline void
-clutter_maybe_setup_viewport (ClutterStage *stage)
+void
+_clutter_stage_maybe_relayout (ClutterActor *stage)
+{
+  ClutterUnit natural_width, natural_height;
+  ClutterActorBox box = { 0, };
+
+  /* avoid reentrancy */
+  if (!(CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_IN_RELAYOUT))
+    {
+      CLUTTER_NOTE (ACTOR, "Recomputing layout");
+
+      CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
+
+      natural_width = natural_height = 0;
+      clutter_actor_get_preferred_size (stage,
+                                        NULL, NULL,
+                                        &natural_width, &natural_height);
+
+      box.x1 = 0;
+      box.y1 = 0;
+      box.x2 = natural_width;
+      box.y2 = natural_height;
+
+      CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
+                    CLUTTER_UNITS_TO_DEVICE (natural_width),
+                    CLUTTER_UNITS_TO_DEVICE (natural_height));
+
+      clutter_actor_allocate (stage, &box, FALSE);
+
+      CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
+    }
+}
+
+void
+_clutter_stage_maybe_setup_viewport (ClutterStage *stage)
 {
   if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
     {
@@ -148,6 +181,9 @@ clutter_redraw (ClutterStage *stage)
   CLUTTER_NOTE (PAINT, " Redraw enter for stage:%p", stage);
   CLUTTER_NOTE (MULTISTAGE, "Redraw called for stage:%p", stage);
 
+  /* Before we can paint, we have to be sure we have the latest layout */
+  _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
+
   _clutter_backend_ensure_context (ctx->backend, stage);
 
   /* Setup FPS count - not currently across *all* stages rather than per */
@@ -160,7 +196,7 @@ clutter_redraw (ClutterStage *stage)
   /* The code below can't go in stage paint as base actor_paint
    * will get called before it (and break picking, etc)
    */
-  clutter_maybe_setup_viewport (stage);
+  _clutter_stage_maybe_setup_viewport (stage);
 
   /* Call through to the actual backend to do the painting down from
    * the stage. It will likely need to swap buffers, vblank sync etc
@@ -322,7 +358,7 @@ _clutter_do_pick (ClutterStage   *stage,
   _clutter_backend_ensure_context (context->backend, stage);
 
   /* needed for when a context switch happens */
-  clutter_maybe_setup_viewport (stage);
+  _clutter_stage_maybe_setup_viewport (stage);
 
   cogl_paint_init (&white);
 
@@ -2118,3 +2154,27 @@ clutter_set_use_mipmapped_text (gboolean value)
     pango_clutter_font_map_set_use_mipmapping (CLUTTER_CONTEXT ()->font_map,
                                               value);
 }
+
+/**
+ * clutter_get_use_mipmapped_text:
+ *
+ * Gets whether mipmapped textures are used in text operations.
+ * See clutter_set_use_mipmapped_text().
+ *
+ * Return value: %TRUE if text operations should use mipmapped
+ *   textures
+ *
+ * Since: 0.8
+ */
+gboolean
+clutter_get_use_mipmapped_text (void)
+{
+  PangoClutterFontMap *font_map = NULL;
+
+  font_map = CLUTTER_CONTEXT ()->font_map;
+
+  if (font_map)
+    return pango_clutter_font_map_get_use_mipmapping (font_map);
+
+  return FALSE;    
+}
index 535d6d9..1492363 100644 (file)
@@ -129,6 +129,7 @@ ClutterActor *   clutter_get_keyboard_grab           (void);
 
 void             clutter_clear_glyph_cache           (void);
 void             clutter_set_use_mipmapped_text      (gboolean      value);
+gboolean         clutter_get_use_mipmapped_text      (void);
 
 G_END_DECLS
 
index acf2be9..113bc86 100644 (file)
@@ -59,7 +59,8 @@ typedef enum {
                                          * viewport / perspective etc
                                          * needs (re)setting.
                                           */
-  CLUTTER_ACTOR_IN_PAINT       = 1 << 4  /* Used to avoid recursion */
+  CLUTTER_ACTOR_IN_PAINT       = 1 << 4, /* Used to avoid recursion */
+  CLUTTER_ACTOR_IN_RELAYOUT    = 1 << 5  /* Used to avoid recursion */
 } ClutterPrivateFlags;
 
 typedef enum {
@@ -142,10 +143,12 @@ void _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
 
 /* stage */
 
-void                _clutter_stage_set_window         (ClutterStage       *stage,
-                                                       ClutterStageWindow *stage_window);
-ClutterStageWindow *_clutter_stage_get_window         (ClutterStage       *stage);
-ClutterStageWindow *_clutter_stage_get_default_window (void);
+void                _clutter_stage_set_window           (ClutterStage       *stage,
+                                                         ClutterStageWindow *stage_window);
+ClutterStageWindow *_clutter_stage_get_window           (ClutterStage       *stage);
+ClutterStageWindow *_clutter_stage_get_default_window   (void);
+void                _clutter_stage_maybe_setup_viewport (ClutterStage       *stage);
+void                _clutter_stage_maybe_relayout       (ClutterActor       *stage);
 
 /* vfuncs implemented by backend */
 GType         _clutter_backend_impl_get_type  (void);
index 35890af..f7d14a9 100644 (file)
@@ -84,7 +84,7 @@ clutter_rectangle_paint (ClutterActor *self)
                                               : "unknown");
   cogl_push_matrix();
 
-  clutter_actor_get_geometry (self, &geom);
+  clutter_actor_get_allocation_geometry (self, &geom);
 
   /* parent paint call will have translated us into position so
    * paint from 0, 0
@@ -94,8 +94,9 @@ clutter_rectangle_paint (ClutterActor *self)
       tmp_col.red   = priv->border_color.red;
       tmp_col.green = priv->border_color.green;
       tmp_col.blue  = priv->border_color.blue;
-      tmp_col.alpha = (clutter_actor_get_abs_opacity (self) *
-                      priv->border_color.alpha) / 0xff;
+      tmp_col.alpha = clutter_actor_get_paint_opacity (self)
+                      * priv->border_color.alpha
+                      / 255;
 
       cogl_color (&tmp_col);
 
@@ -120,13 +121,13 @@ clutter_rectangle_paint (ClutterActor *self)
       tmp_col.red   = priv->color.red;
       tmp_col.green = priv->color.green;
       tmp_col.blue  = priv->color.blue;
-      tmp_col.alpha = (clutter_actor_get_abs_opacity (self) *
-                      priv->color.alpha) / 0xff;
+      tmp_col.alpha = clutter_actor_get_paint_opacity (self)
+                      * priv->color.alpha
+                      / 255;
 
       cogl_color (&tmp_col);
 
-      cogl_rectangle (priv->border_width,
-                      priv->border_width,
+      cogl_rectangle (priv->border_width, priv->border_width,
                       geom.width - priv->border_width * 2,
                       geom.height - priv->border_width * 2);
     }
@@ -135,8 +136,9 @@ clutter_rectangle_paint (ClutterActor *self)
       tmp_col.red   = priv->color.red;
       tmp_col.green = priv->color.green;
       tmp_col.blue  = priv->color.blue;
-      tmp_col.alpha = (clutter_actor_get_abs_opacity (self) *
-                      priv->color.alpha) / 0xff;
+      tmp_col.alpha = clutter_actor_get_paint_opacity (self)
+                      * priv->color.alpha
+                      / 255;
 
       cogl_color (&tmp_col);
 
index 1113709..781c0be 100644 (file)
@@ -121,25 +121,52 @@ enum
 static guint stage_signals[LAST_SIGNAL] = { 0, };
 
 static void
-clutter_stage_request_coords (ClutterActor    *self,
-                              ClutterActorBox *box)
+clutter_stage_get_preferred_width (ClutterActor *self,
+                                   ClutterUnit   for_height,
+                                   ClutterUnit  *min_width_p,
+                                   ClutterUnit  *natural_width_p)
 {
   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
 
   g_assert (priv->impl != NULL);
-  CLUTTER_ACTOR_GET_CLASS (priv->impl)->request_coords (priv->impl, box);
 
-  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->request_coords (self, box);
+  CLUTTER_ACTOR_GET_CLASS (priv->impl)->get_preferred_width (priv->impl,
+                                                             for_height,
+                                                             min_width_p,
+                                                             natural_width_p);
 }
 
 static void
-clutter_stage_query_coords (ClutterActor    *self,
-                            ClutterActorBox *box)
+clutter_stage_get_preferred_height (ClutterActor *self,
+                                    ClutterUnit   for_width,
+                                    ClutterUnit  *min_height_p,
+                                    ClutterUnit  *natural_height_p)
 {
   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
 
   g_assert (priv->impl != NULL);
-  CLUTTER_ACTOR_GET_CLASS (priv->impl)->query_coords (priv->impl, box);
+
+  CLUTTER_ACTOR_GET_CLASS (priv->impl)->get_preferred_height (priv->impl,
+                                                              for_width,
+                                                              min_height_p,
+                                                              natural_height_p);
+}
+static void
+clutter_stage_allocate (ClutterActor              *self,
+                        const ClutterActorBox     *box,
+                        gboolean                   origin_changed)
+{
+  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
+
+  g_assert (priv->impl != NULL);
+
+  CLUTTER_ACTOR_GET_CLASS (priv->impl)->allocate (priv->impl,
+                                                  box,
+                                                  origin_changed);
+
+  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->allocate (self, 
+                                                              box,
+                                                              origin_changed);
 }
 
 static void
@@ -243,6 +270,32 @@ clutter_stage_hide (ClutterActor *self)
 }
 
 static void
+clutter_stage_real_fullscreen (ClutterStage *stage)
+{
+  ClutterStagePrivate *priv = stage->priv;
+  ClutterUnit natural_width, natural_height;
+  ClutterActorBox box;
+
+  /* we need to force an allocation here because the size
+   * of the stage might have been changed by the backend
+   *
+   * this is a really bad solution to the issues caused by
+   * the fact that fullscreening the stage on the X11 backends
+   * is really an asynchronous operation
+   */
+  clutter_actor_get_preferred_size (CLUTTER_ACTOR (priv->impl),
+                                    NULL, NULL,
+                                    &natural_width, &natural_height);
+
+  box.x1 = 0;
+  box.y1 = 0;
+  box.x2 = natural_width;
+  box.y2 = natural_height;
+
+  clutter_actor_allocate (CLUTTER_ACTOR (stage), &box, FALSE);
+}
+
+static void
 clutter_stage_set_property (GObject      *object,
                            guint         prop_id,
                            const GValue *value,
@@ -404,8 +457,9 @@ clutter_stage_class_init (ClutterStageClass *klass)
   gobject_class->dispose = clutter_stage_dispose;
   gobject_class->finalize = clutter_stage_finalize;
 
-  actor_class->request_coords = clutter_stage_request_coords;
-  actor_class->query_coords = clutter_stage_query_coords;
+  actor_class->allocate = clutter_stage_allocate;
+  actor_class->get_preferred_width = clutter_stage_get_preferred_width;
+  actor_class->get_preferred_height = clutter_stage_get_preferred_height;
   actor_class->paint = clutter_stage_paint;
   actor_class->pick = clutter_stage_pick;
   actor_class->realize = clutter_stage_realize;
@@ -518,7 +572,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
   stage_signals[FULLSCREEN] =
     g_signal_new ("fullscreen",
                  G_TYPE_FROM_CLASS (gobject_class),
-                 G_SIGNAL_RUN_LAST,
+                 G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (ClutterStageClass, fullscreen),
                  NULL, NULL,
                  clutter_marshal_VOID__VOID,
@@ -575,6 +629,8 @@ clutter_stage_class_init (ClutterStageClass *klass)
                  clutter_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
 
+  klass->fullscreen = clutter_stage_real_fullscreen;
+
   g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate));
 }
 
index f4127ff..73bd63d 100644 (file)
  * This process allows basic management of commonly limited available texture
  * memory.
  *
- * Note: a ClutterTexture will scale its contents to fit the bounding box
- * requested using clutter_actor_request_coords() and its wrappers. To
- * display an area of a texture without scaling, you should set the clip
- * area using clutter_actor_set_clip().
+ * Note: a ClutterTexture will scale its contents to fit the bounding
+ * box requested using clutter_actor_set_size(). To display an area of
+ * a texture without scaling, you should set the clip area using
+ * clutter_actor_set_clip().
  */
 
 #ifdef HAVE_CONFIG_H
@@ -319,6 +319,64 @@ clutter_texture_realize (ClutterActor *actor)
 }
 
 static void
+clutter_texture_get_preferred_width (ClutterActor *self,
+                                     ClutterUnit   for_height,
+                                     ClutterUnit  *min_width_p,
+                                     ClutterUnit  *natural_width_p)
+{
+  ClutterTexture *texture = CLUTTER_TEXTURE (self);
+  ClutterTexturePrivate *priv = texture->priv;
+
+  /* FIXME If we wanted to be clever here, we could set the natural
+   * width to preserve aspect ratio considering for_height
+   */
+
+  /* Min request is always 0 since we can scale down or clip */
+  if (min_width_p)
+    *min_width_p = 0;
+
+  if (priv->sync_actor_size)
+    {
+      if (natural_width_p)
+        *natural_width_p = CLUTTER_UNITS_FROM_DEVICE (priv->width);
+    }
+  else
+    {
+      if (natural_width_p)
+        *natural_width_p = 0;
+    }
+}
+
+static void
+clutter_texture_get_preferred_height (ClutterActor *self,
+                                      ClutterUnit   for_width,
+                                      ClutterUnit  *min_height_p,
+                                      ClutterUnit  *natural_height_p)
+{
+  ClutterTexture *texture = CLUTTER_TEXTURE (self);
+  ClutterTexturePrivate *priv = texture->priv;
+
+  /* FIXME If we wanted to be clever here, we could set the natural
+   * height to preserve aspect ratio considering for_width
+   */
+
+  /* Min request is always 0 since we can scale down or clip */
+  if (min_height_p)
+    *min_height_p = 0;
+
+  if (priv->sync_actor_size)
+    {
+      if (natural_height_p)
+        *natural_height_p = CLUTTER_UNITS_FROM_DEVICE (priv->height);
+    }
+  else
+    {
+      if (natural_height_p)
+        *natural_height_p = 0;
+    }
+}
+
+static void
 clutter_texture_paint (ClutterActor *self)
 {
   ClutterTexture *texture = CLUTTER_TEXTURE (self);
@@ -370,10 +428,10 @@ clutter_texture_paint (ClutterActor *self)
                                               : "unknown");
   cogl_push_matrix ();
 
-  col.alpha = clutter_actor_get_abs_opacity (self);
+  col.alpha = clutter_actor_get_paint_opacity (self);
   cogl_color (&col);
 
-  clutter_actor_get_coords (self, &x_1, &y_1, &x_2, &y_2);
+  clutter_actor_get_allocation_coords (self, &x_1, &y_1, &x_2, &y_2);
 
   CLUTTER_NOTE (PAINT, "paint to x1: %i, y1: %i x2: %i, y2: %i "
                       "opacity: %i",
@@ -401,23 +459,6 @@ clutter_texture_paint (ClutterActor *self)
 }
 
 static void
-clutter_texture_request_coords (ClutterActor    *self,
-                                ClutterActorBox *box)
-{
-  ClutterTexture *texture = CLUTTER_TEXTURE (self);
-  ClutterActorBox old_request;
-
-  clutter_actor_query_coords (self, &old_request);
-
-  if (((box->x2 - box->x1) != (old_request.x2 - old_request.x1)) ||
-      ((box->y2 - box->y1) != (old_request.y2 - old_request.y1)))
-    texture->priv->sync_actor_size = FALSE;
-
-  CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)
-    ->request_coords (self, box);
-}
-
-static void
 clutter_texture_dispose (GObject *object)
 {
   ClutterTexture *texture = CLUTTER_TEXTURE (object);
@@ -457,6 +498,7 @@ clutter_texture_set_property (GObject      *object,
       break;
     case PROP_SYNC_SIZE:
       priv->sync_actor_size = g_value_get_boolean (value);
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (texture));
       break;
     case PROP_REPEAT_X:
       if (priv->repeat_x != g_value_get_boolean (value))
@@ -557,7 +599,9 @@ clutter_texture_class_init (ClutterTextureClass *klass)
   actor_class->paint          = clutter_texture_paint;
   actor_class->realize        = clutter_texture_realize;
   actor_class->unrealize      = clutter_texture_unrealize;
-  actor_class->request_coords = clutter_texture_request_coords;
+
+  actor_class->get_preferred_width = clutter_texture_get_preferred_width;
+  actor_class->get_preferred_height = clutter_texture_get_preferred_height;
 
   gobject_class->dispose      = clutter_texture_dispose;
   gobject_class->set_property = clutter_texture_set_property;
@@ -920,18 +964,11 @@ clutter_texture_set_cogl_texture (ClutterTexture  *texture,
 
   if (size_change)
     {
-      g_signal_emit (texture, texture_signals[SIZE_CHANGE],
-                    0, priv->width, priv->height);
+      g_signal_emit (texture, texture_signals[SIZE_CHANGE], 0,
+                     priv->width,
+                     priv->height);
 
-      if (priv->sync_actor_size)
-       {
-         clutter_actor_set_size (CLUTTER_ACTOR(texture),
-                                 priv->width,
-                                 priv->height);
-         /* The above call will clear sync_actor_size because the
-            size has changed so we need to put it back */
-         priv->sync_actor_size = TRUE;
-       }
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (texture));
     }
 
   /* rename signal */
@@ -1493,7 +1530,7 @@ on_fbo_source_size_change (GObject          *object,
   ClutterTexturePrivate *priv = texture->priv;
   guint                  w, h;
 
-  clutter_actor_get_abs_size (priv->fbo_source, &w, &h);
+  clutter_actor_get_transformed_size (priv->fbo_source, &w, &h);
 
   if (w != priv->width || h != priv->height)
     {
@@ -1616,7 +1653,7 @@ clutter_texture_new_from_actor (ClutterActor *actor)
        return NULL;
     }
 
-  clutter_actor_get_abs_size (actor, &w, &h);
+  clutter_actor_get_transformed_size (actor, &w, &h);
 
   if (w == 0 || h == 0)
     return NULL;
index 389ef03..0100639 100644 (file)
@@ -94,16 +94,26 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11)
   if (stage_x11->xwin != None && stage_x11->is_foreign_xwin == FALSE)
     {
       XSizeHints *size_hints;
+      ClutterUnit min_width, min_height;
 
       size_hints = XAllocSizeHints();
 
+      clutter_actor_get_preferred_width (CLUTTER_ACTOR (stage_x11),
+                                         -1,
+                                         &min_width, NULL);
+      clutter_actor_get_preferred_height (CLUTTER_ACTOR (stage_x11),
+                                          min_width,
+                                          &min_height, NULL);
+
+      size_hints->min_width = CLUTTER_UNITS_TO_DEVICE (min_width);
+      size_hints->min_height = CLUTTER_UNITS_TO_DEVICE (min_height);
+      size_hints->flags = PMinSize;
+
       if (!resize)
         {
-          size_hints->max_width = size_hints->min_width =
-            stage_x11->xwin_width;
-          size_hints->max_height = size_hints->min_height =
-            stage_x11->xwin_height;
-          size_hints->flags = PMinSize|PMaxSize;
+          size_hints->max_width = size_hints->min_width;
+          size_hints->max_height = size_hints->min_height;
+          size_hints->flags |= PMaxSize;
         }
 
       XSetWMNormalHints (stage_x11->xdpy, stage_x11->xwin, size_hints);
@@ -117,18 +127,18 @@ clutter_stage_x11_show (ClutterActor *actor)
 {
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
 
+  CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->show (actor);
+
   if (stage_x11->xwin)
     {
       /* Fire off a redraw to avoid flicker on first map.
        * Appears not to work perfectly on intel drivers at least.
-      */
+       */
       clutter_redraw (stage_x11->wrapper);
 
       XSync (stage_x11->xdpy, FALSE);
       XMapWindow (stage_x11->xdpy, stage_x11->xwin);
     }
-
-  CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_MAPPED);
 }
 
 static void
@@ -136,8 +146,6 @@ clutter_stage_x11_hide (ClutterActor *actor)
 {
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
 
-  CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_MAPPED);
-
   if (stage_x11->xwin)
     XUnmapWindow (stage_x11->xdpy, stage_x11->xwin);
 }
@@ -156,41 +164,108 @@ clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11)
 }
 
 static void
-clutter_stage_x11_query_coords (ClutterActor    *self,
-                                ClutterActorBox *box)
+clutter_stage_x11_get_preferred_width (ClutterActor *self,
+                                       ClutterUnit   for_height,
+                                       ClutterUnit  *min_width_p,
+                                       ClutterUnit  *natural_width_p)
 {
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
+  gboolean resize;
+
+  if (stage_x11->fullscreen_on_map)
+    {
+      int width;
+
+      width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
+
+      if (min_width_p)
+        *min_width_p = CLUTTER_UNITS_FROM_DEVICE (width);
+
+      if (natural_width_p)
+        *natural_width_p = CLUTTER_UNITS_FROM_DEVICE (width);
+
+      return;
+    }
 
-  box->x1 = box->y1 = 0;
-  box->x2 = box->x1 + CLUTTER_UNITS_FROM_INT (stage_x11->xwin_width);
-  box->y2 = box->y1 + CLUTTER_UNITS_FROM_INT (stage_x11->xwin_height);
+  resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
+
+  if (min_width_p)
+    {
+      /* FIXME need API to set this */
+      if (resize)
+        *min_width_p = CLUTTER_UNITS_FROM_DEVICE (1);
+      else
+        *min_width_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_width);
+    }
+
+  if (natural_width_p)
+    *natural_width_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_width);
 }
 
 static void
-clutter_stage_x11_request_coords (ClutterActor    *self,
-                                  ClutterActorBox *box)
+clutter_stage_x11_get_preferred_height (ClutterActor *self,
+                                        ClutterUnit   for_width,
+                                        ClutterUnit  *min_height_p,
+                                        ClutterUnit  *natural_height_p)
 {
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
-  gint new_width, new_height;
+  gboolean resize;
 
-  new_width  = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1));
-  new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1)); 
+  if (stage_x11->fullscreen_on_map)
+    {
+      int height;
+
+      height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
+
+      if (min_height_p)
+        *min_height_p = CLUTTER_UNITS_FROM_DEVICE (height);
+
+      if (natural_height_p)
+        *natural_height_p = CLUTTER_UNITS_FROM_DEVICE (height);
+
+      return;
+    }
 
-  /* X cant resize to 0 dimentions */
-  if (new_height == 0)
+  resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
+
+  if (min_height_p)
     {
-      box->y2 = box->y1 + 1;
-      new_height = 1;
+      if (resize)
+        *min_height_p = CLUTTER_UNITS_FROM_DEVICE (1); /* FIXME need API
+                                                        * to set this
+                                                        */
+      else
+        *min_height_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_height);
     }
 
-  if (new_width == 0)
+  if (natural_height_p)
+    *natural_height_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_height);
+}
+
+static void
+clutter_stage_x11_allocate (ClutterActor          *self,
+                            const ClutterActorBox *box,
+                            gboolean               origin_changed)
+{
+  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
+  ClutterActorClass *parent_class;
+  gint new_width, new_height;
+
+  new_width  = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1));
+  new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1));
+
+  if (new_width == 0 || new_height == 0)
     {
-      box->x2 = box->x1 + 1;
+      /* Should not happen, if this turns up we need to debug it and
+       * determine the cleanest way to fix.
+       */
+      g_warning ("X11 stage not allowed to have 0 width or height");
       new_width = 1;
+      new_height = 1;
     }
 
-  if (new_width != stage_x11->xwin_width
-      || new_height != stage_x11->xwin_height)
+  if (new_width != stage_x11->xwin_width ||
+      new_height != stage_x11->xwin_height)
     {
       stage_x11->xwin_width  = new_width;
       stage_x11->xwin_height = new_height;
@@ -210,13 +285,13 @@ clutter_stage_x11_request_coords (ClutterActor    *self,
       if (stage_x11->xwin != None
          && !stage_x11->is_foreign_xwin
          && !stage_x11->handling_configure)
-        XResizeWindow (stage_x11->xdpy, 
+        XResizeWindow (stage_x11->xdpy,
                        stage_x11->xwin,
                        stage_x11->xwin_width,
                        stage_x11->xwin_height);
 
       clutter_stage_x11_fix_window_size (stage_x11);
-      
+
       if (stage_x11->xpixmap != None)
         {
           /* Need to recreate to resize */
@@ -228,16 +303,9 @@ clutter_stage_x11_request_coords (ClutterActor    *self,
                                  CLUTTER_ACTOR_SYNC_MATRICES);
     }
 
-  if (stage_x11->xwin != None
-      && !stage_x11->is_foreign_xwin
-      && !stage_x11->handling_configure) /* Do we want to bother ? */
-    XMoveWindow (stage_x11->xdpy,
-                 stage_x11->xwin,
-                 CLUTTER_UNITS_TO_INT (box->x1),
-                 CLUTTER_UNITS_TO_INT (box->y1));
-
-  CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->request_coords (self,
-                                                                        box);
+  /* chain up to fill in actor->priv->allocation */
+  parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class);
+  parent_class->allocate (self, box, origin_changed);
 }
 
 static inline void
@@ -331,8 +399,26 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
 
   if (is_fullscreen)
     {
+      int width, height;
+
+      width  = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
+      height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
+
+      /* we force the stage to the screen size here, in order to
+       * get the fullscreen stage size right after the call to
+       * clutter_stage_fullscreen(). XXX this might break in case
+       * the stage is not fullscreened, but if that does not happen
+       * we are massively screwed anyway
+       */
+      stage_x11->xwin_width = width;
+      stage_x11->xwin_height = height;
+
+      clutter_actor_set_size (CLUTTER_ACTOR (stage), width, height);
+
       if (stage_x11->xwin != None)
         {
+          stage_x11->fullscreen_on_map = TRUE;
+
           /* if the actor is not mapped we resize the stage window to match
            * the size of the screen; this is useful for e.g. EGLX to avoid
            * a resize when calling clutter_stage_fullscreen() before showing
@@ -340,14 +426,6 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
            */
           if (!CLUTTER_ACTOR_IS_MAPPED (stage_x11))
             {
-              gint width, height;
-
-              width  = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
-              height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
-
-              clutter_actor_set_size (CLUTTER_ACTOR (stage_x11),
-                                      width, height);
-
               /* FIXME: This wont work if we support more states */
               XChangeProperty (stage_x11->xdpy,
                                stage_x11->xwin,
@@ -365,12 +443,10 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
               else
                  clutter_stage_set_user_resizable (stage, TRUE);
 
-              send_wmspec_change_state(backend_x11, stage_x11->xwin,
-                                       backend_x11->atom_NET_WM_STATE_FULLSCREEN,
-                                       TRUE);
+              send_wmspec_change_state (backend_x11, stage_x11->xwin,
+                                        backend_x11->atom_NET_WM_STATE_FULLSCREEN,
+                                        TRUE);
             }
-
-          stage_x11->fullscreen_on_map = TRUE;
         }
     }
   else
@@ -388,10 +464,10 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
             {
               clutter_stage_set_user_resizable (stage, TRUE);
 
-              send_wmspec_change_state(backend_x11,
-                                       stage_x11->xwin,
-                                       backend_x11->atom_NET_WM_STATE_FULLSCREEN,
-                                       FALSE);
+              send_wmspec_change_state (backend_x11,
+                                        stage_x11->xwin,
+                                        backend_x11->atom_NET_WM_STATE_FULLSCREEN,
+                                        FALSE);
 
               /* reset the windows state - this isn't fun - see above */
               if (!was_resizeable)
@@ -414,7 +490,6 @@ clutter_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window,
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
 
   stage_x11->is_cursor_visible = (cursor_visible == TRUE);
-
   set_cursor_visible (stage_x11);
 }
 
@@ -426,7 +501,6 @@ clutter_stage_x11_set_title (ClutterStageWindow *stage_window,
 
   g_free (stage_x11->title);
   stage_x11->title = g_strdup (title);
-
   set_wm_title (stage_x11);
 }
 
@@ -478,8 +552,10 @@ clutter_stage_x11_class_init (ClutterStageX11Class *klass)
   actor_class->realize = clutter_stage_x11_realize;
   actor_class->show = clutter_stage_x11_show;
   actor_class->hide = clutter_stage_x11_hide;
-  actor_class->request_coords = clutter_stage_x11_request_coords;
-  actor_class->query_coords = clutter_stage_x11_query_coords;
+
+  actor_class->get_preferred_width = clutter_stage_x11_get_preferred_width;
+  actor_class->get_preferred_height = clutter_stage_x11_get_preferred_height;
+  actor_class->allocate = clutter_stage_x11_allocate;
 }
 
 static void
@@ -681,7 +757,7 @@ clutter_stage_x11_map (ClutterStageX11 *stage_x11)
   else
     clutter_stage_unfullscreen (CLUTTER_STAGE (stage_x11->wrapper));
 
-  clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_x11->wrapper));
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_x11->wrapper));
 }
 
 void
index 363e70b..38132a6 100644 (file)
@@ -13,7 +13,7 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
                  test-cogl-tex-getset test-cogl-offscreen \
                  test-cogl-tex-polygon test-stage-read-pixels \
                  test-random-text test-clip test-paint-wrapper \
-                 test-texture-quality test-entry-auto
+                 test-texture-quality test-entry-auto test-layout
 
 if X11_TESTS
 noinst_PROGRAMS += test-pixmap
@@ -24,22 +24,22 @@ LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR
 AM_CFLAGS = $(CLUTTER_CFLAGS)
 AM_LDFLAGS = $(CLUTTER_LIBS)
 
-test_textures_SOURCES             = test-textures.c
-test_events_SOURCES               = test-events.c
-test_offscreen_SOURCES            = test-offscreen.c
-test_scale_SOURCES                = test-scale.c
-test_actors_SOURCES               = test-actors.c
-test_grab_SOURCES                 = test-grab.c
-test_behave_SOURCES               = test-behave.c
-test_text_SOURCES                 = test-text.c
-test_entry_SOURCES                = test-entry.c
-test_project_SOURCES              = test-project.c
-test_unproject_SOURCES            = test-unproject.c
-test_perspective_SOURCES          = test-perspective.c
-test_rotate_SOURCES               = test-rotate.c
-test_depth_SOURCES                = test-depth.c
-test_threads_SOURCES              = test-threads.c
-test_timeline_SOURCES             = test-timeline.c
+test_textures_SOURCES    = test-textures.c
+test_events_SOURCES      = test-events.c
+test_offscreen_SOURCES   = test-offscreen.c
+test_scale_SOURCES       = test-scale.c
+test_actors_SOURCES      = test-actors.c
+test_grab_SOURCES        = test-grab.c
+test_behave_SOURCES      = test-behave.c
+test_text_SOURCES        = test-text.c
+test_entry_SOURCES       = test-entry.c
+test_project_SOURCES     = test-project.c
+test_unproject_SOURCES   = test-unproject.c
+test_perspective_SOURCES = test-perspective.c
+test_rotate_SOURCES      = test-rotate.c
+test_depth_SOURCES       = test-depth.c
+test_threads_SOURCES     = test-threads.c
+test_timeline_SOURCES    = test-timeline.c
 test_timeline_dup_frames_SOURCES  = test-timeline-dup-frames.c
 test_timeline_interpolate_SOURCES = test-timeline-interpolate.c
 test_timeline_rewind_SOURCES      = test-timeline-rewind.c
@@ -67,5 +67,6 @@ test_random_text_SOURCES          = test-random-text.c
 test_paint_wrapper_SOURCES        = test-paint-wrapper.c
 test_texture_quality_SOURCES      = test-texture-quality.c
 test_entry_auto_SOURCES                  = test-entry-auto.c
+test_layout_SOURCES               = test-layout.c
 
 EXTRA_DIST = redhand.png test-script.json
diff --git a/tests/test-layout.c b/tests/test-layout.c
new file mode 100644 (file)
index 0000000..26d53c8
--- /dev/null
@@ -0,0 +1,785 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cogl/cogl.h>
+#include <clutter/clutter.h>
+
+/* layout actor, by Lucas Rocha */
+
+#define MY_TYPE_THING                (my_thing_get_type ())
+#define MY_THING(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_THING, MyThing))
+#define MY_IS_THING(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_THING))
+#define MY_THING_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass),  MY_TYPE_THING, MyThingClass))
+#define MY_IS_THING_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass),  MY_TYPE_THING))
+#define MY_THING_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj),  MY_TYPE_THING, MyThingClass))
+
+typedef struct _MyThing             MyThing;
+typedef struct _MyThingPrivate      MyThingPrivate;
+typedef struct _MyThingClass        MyThingClass;
+
+struct _MyThing
+{
+  ClutterActor parent_instance;
+
+  MyThingPrivate *priv;
+};
+
+struct _MyThingClass
+{
+  ClutterActorClass parent_class;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_SPACING,
+  PROP_PADDING,
+  PROP_USE_TRANSFORMED_BOX
+};
+
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MyThing,
+                         my_thing,
+                         CLUTTER_TYPE_ACTOR,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+                                                clutter_container_iface_init));
+
+#define MY_THING_GET_PRIVATE(obj)    \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MY_TYPE_THING, MyThingPrivate))
+
+struct _MyThingPrivate
+{
+  GList       *children;
+  
+  ClutterUnit  spacing;
+  ClutterUnit  padding;
+
+  guint        use_transformed_box : 1;
+};
+
+/* Add, remove, foreach, copied from ClutterGroup code. */
+
+static void
+my_thing_real_add (ClutterContainer *container,
+                   ClutterActor     *actor)
+{
+  MyThing *group = MY_THING (container);
+  MyThingPrivate *priv = group->priv;
+
+  g_object_ref (actor);
+
+  priv->children = g_list_append (priv->children, actor);
+  clutter_actor_set_parent (actor, CLUTTER_ACTOR (group));
+
+  g_signal_emit_by_name (container, "actor-added", actor);
+
+  /* queue relayout to allocate new item */
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (group));
+
+  g_object_unref (actor);
+}
+
+static void
+my_thing_real_remove (ClutterContainer *container,
+                      ClutterActor     *actor)
+{
+  MyThing *group = MY_THING (container);
+  MyThingPrivate *priv = group->priv;
+
+  g_object_ref (actor);
+
+  priv->children = g_list_remove (priv->children, actor);
+  clutter_actor_unparent (actor);
+
+  /* At this point, the actor passed to the "actor-removed" signal
+   * handlers is not parented anymore to the container but since we
+   * are holding a reference on it, it's still valid
+   */
+  g_signal_emit_by_name (container, "actor-removed", actor);
+
+  /* queue relayout to re-allocate children without the
+     removed item */
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (group));
+
+  g_object_unref (actor);
+}
+
+static void
+my_thing_real_foreach (ClutterContainer *container,
+                       ClutterCallback   callback,
+                       gpointer          user_data)
+{
+  MyThingPrivate *priv = MY_THING (container)->priv;
+  GList *l;
+
+  for (l = priv->children; l; l = l->next)
+    (* callback) (CLUTTER_ACTOR (l->data), user_data);
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+  iface->add = my_thing_real_add;
+  iface->remove = my_thing_real_remove;
+  iface->foreach = my_thing_real_foreach;
+}
+
+static void
+my_thing_set_property (GObject      *gobject,
+                       guint         prop_id,
+                       const GValue *value,
+                       GParamSpec   *pspec)
+{
+  MyThingPrivate *priv = MY_THING (gobject)->priv;
+  gboolean needs_relayout = TRUE;
+
+  switch (prop_id)
+    {
+    case PROP_SPACING:
+      priv->spacing = clutter_value_get_unit (value);
+      break;
+
+    case PROP_PADDING:
+      priv->padding = clutter_value_get_unit (value);
+      break;
+
+    case PROP_USE_TRANSFORMED_BOX:
+      priv->use_transformed_box = g_value_get_boolean (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      needs_relayout = FALSE;
+      break;
+    }
+
+  /* setting spacing or padding queues a relayout 
+     because they are supposed to change the internal
+     allocation of children */
+  if (needs_relayout)
+    clutter_actor_queue_relayout (CLUTTER_ACTOR (gobject));
+}
+
+static void
+my_thing_get_property (GObject    *gobject,
+                       guint       prop_id,
+                       GValue     *value,
+                       GParamSpec *pspec)
+{
+  MyThingPrivate *priv = MY_THING (gobject)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_SPACING:
+      clutter_value_set_unit (value, priv->spacing);
+      break;
+
+    case PROP_PADDING:
+      clutter_value_set_unit (value, priv->padding);
+      break;
+
+    case PROP_USE_TRANSFORMED_BOX:
+      g_value_set_boolean (value, priv->use_transformed_box);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+my_thing_finalize (GObject *gobject)
+{
+  G_OBJECT_CLASS (my_thing_parent_class)->finalize (gobject);
+}
+
+static void
+my_thing_dispose (GObject *gobject)
+{
+  MyThing *self = MY_THING (gobject);
+  MyThingPrivate *priv = self->priv;
+
+  if (priv->children)
+    {
+      g_list_foreach (priv->children, (GFunc) clutter_actor_destroy, NULL);
+      priv->children = NULL;
+    }
+
+  G_OBJECT_CLASS (my_thing_parent_class)->dispose (gobject);
+}
+
+static void
+my_thing_get_preferred_width (ClutterActor *self,
+                              ClutterUnit   for_height,
+                              ClutterUnit  *min_width_p,
+                              ClutterUnit  *natural_width_p)
+{
+  MyThingPrivate *priv;
+  GList *l;
+  ClutterUnit min_left, min_right;
+  ClutterUnit natural_left, natural_right;
+
+  priv = MY_THING (self)->priv;
+
+  min_left = 0;
+  min_right = 0;
+  natural_left = 0;
+  natural_right = 0;
+
+  for (l = priv->children; l != NULL; l = l->next)
+    {
+      ClutterActor *child;
+      ClutterUnit child_x, child_min, child_natural;
+
+      child = l->data;
+
+      child_x = clutter_actor_get_xu (child);
+
+      clutter_actor_get_preferred_size (child,
+                                        &child_min, NULL,
+                                        &child_natural, NULL);
+
+      if (l == priv->children)
+        {
+          /* First child */
+          min_left = child_x;
+          natural_left = child_x;
+          min_right = min_left + child_min;
+          natural_right = natural_left + child_natural;
+        }
+      else
+        {
+          /* Union of extents with previous children */
+          if (child_x < min_left)
+            min_left = child_x;
+
+          if (child_x < natural_left)
+            natural_left = child_x;
+
+          if (child_x + child_min > min_right)
+            min_right = child_x + child_min;
+
+          if (child_x + child_natural > natural_right)
+            natural_right = child_x + child_natural;
+        }
+    }
+
+  if (min_left < 0)
+    min_left = 0;
+
+  if (natural_left < 0)
+    natural_left = 0;
+
+  if (min_right < 0)
+    min_right = 0;
+
+  if (natural_right < 0)
+    natural_right = 0;
+
+  g_assert (min_right >= min_left);
+  g_assert (natural_right >= natural_left);
+
+  if (min_width_p)
+    *min_width_p = min_right - min_left;
+
+  if (natural_width_p)
+    *natural_width_p = natural_right - min_left;
+}
+
+static void
+my_thing_get_preferred_height (ClutterActor *self,
+                               ClutterUnit   for_width,
+                               ClutterUnit  *min_height_p,
+                               ClutterUnit  *natural_height_p)
+{
+  MyThingPrivate *priv;
+  GList *l;
+  ClutterUnit min_top, min_bottom;
+  ClutterUnit natural_top, natural_bottom;
+
+  priv = MY_THING (self)->priv;
+
+  min_top = 0;
+  min_bottom = 0;
+  natural_top = 0;
+  natural_bottom = 0;
+
+  for (l = priv->children; l != NULL; l = l->next)
+    {
+      ClutterActor *child;
+      ClutterUnit child_y, child_min, child_natural;
+
+      child = l->data;
+
+      child_y = clutter_actor_get_yu (child);
+
+      clutter_actor_get_preferred_size (child,
+                                        NULL, &child_min,
+                                        NULL, &child_natural);
+
+      if (l == priv->children)
+        {
+          /* First child */
+          min_top = child_y;
+          natural_top = child_y;
+          min_bottom = min_top + child_min;
+          natural_bottom = natural_top + child_natural;
+        }
+      else
+        {
+          /* Union of extents with previous children */
+          if (child_y < min_top)
+            min_top = child_y;
+
+          if (child_y < natural_top)
+            natural_top = child_y;
+
+          if (child_y + child_min > min_bottom)
+            min_bottom = child_y + child_min;
+
+          if (child_y + child_natural > natural_bottom)
+            natural_bottom = child_y + child_natural;
+        }
+    }
+
+  if (min_top < 0)
+    min_top = 0;
+
+  if (natural_top < 0)
+    natural_top = 0;
+
+  if (min_bottom < 0)
+    min_bottom = 0;
+
+  if (natural_bottom < 0)
+    natural_bottom = 0;
+
+  g_assert (min_bottom >= min_top);
+  g_assert (natural_bottom >= natural_top);
+
+  if (min_height_p)
+    *min_height_p = min_bottom - min_top;
+
+  if (natural_height_p)
+    *natural_height_p = natural_bottom - min_top;
+}
+
+static void
+my_thing_allocate (ClutterActor          *self,
+                   const ClutterActorBox *box,
+                   gboolean               absolute_origin_changed)
+{
+  MyThingPrivate *priv;
+  ClutterUnit current_x, current_y, max_row_height;
+  GList *l;
+
+  /* chain up to set actor->allocation */
+  CLUTTER_ACTOR_CLASS (my_thing_parent_class)->allocate (self, box,
+                                                         absolute_origin_changed);
+
+  priv = MY_THING (self)->priv;
+
+  current_x = priv->padding;
+  current_y = priv->padding;
+  max_row_height = 0;
+
+  /* The allocation logic here is to horizontally place children 
+   * side-by-side and reflow into a new row when we run out of 
+   * space 
+   */
+  for (l = priv->children; l != NULL; l = l->next)
+    {
+      ClutterActor *child;
+      ClutterUnit natural_width, natural_height;
+      ClutterActorBox child_box;
+      child = l->data;
+
+      clutter_actor_get_preferred_size (child,
+                                        NULL, NULL,
+                                        &natural_width, &natural_height);
+
+      /* if it fits in the current row, keep it there; otherwise
+       * reflow into another row
+       */
+      if (current_x + natural_width > box->x2 - box->x1 - priv->padding)
+        {
+          current_x = priv->padding;
+          current_y += max_row_height + priv->spacing;
+          max_row_height = 0;
+        }
+
+      child_box.x1 = current_x;
+      child_box.y1 = current_y;
+      child_box.x2 = child_box.x1 + natural_width;
+      child_box.y2 = child_box.y1 + natural_height;
+
+      clutter_actor_allocate (child, &child_box, absolute_origin_changed);
+
+      /* if we take into account the transformation of the children
+       * then we first check if it's transformed; then we get the
+       * onscreen coordinates of the two points of the bounding box
+       * of the actor (origin(x, y) and (origin + size)(x,y)) and
+       * we update the coordinates and area given to the next child
+       */
+      if (priv->use_transformed_box)
+        {
+          if (clutter_actor_is_scaled (child) ||
+              clutter_actor_is_rotated (child))
+            {
+              ClutterVertex v1 = { 0, }, v2 = { 0, };
+              ClutterActorBox box = { 0, };
+
+              /* origin */
+              v1.x = 0;
+              v1.y = 0;
+              clutter_actor_apply_transform_to_point (child, &v1, &v2);
+              box.x1 = v2.x;
+              box.y1 = v2.y;
+
+              /* size */
+              v1.x = natural_width;
+              v1.y = natural_height;
+              clutter_actor_apply_transform_to_point (child, &v1, &v2);
+              box.x2 = v2.x;
+              box.y2 = v2.y;
+
+              natural_width = box.x2 - box.x1;
+              natural_height = box.y2 - box.y1;
+            }
+        }
+
+      /* Record the maximum child height on current row to know
+       * what's the increment that should be used for the next  
+       * row 
+       */
+      if (natural_height > max_row_height)
+        max_row_height = natural_height;
+
+      current_x += natural_width + priv->spacing;
+    }
+}
+
+static void
+my_thing_paint (ClutterActor *actor)
+{
+  MyThing *self = MY_THING (actor);
+  GList *c;
+
+  cogl_push_matrix();
+
+  /* paint all visible children */
+  for (c = self->priv->children;
+       c != NULL;
+       c = c->next)
+    {
+      ClutterActor *child = c->data;
+
+      g_assert (child != NULL);
+
+      if (CLUTTER_ACTOR_IS_VISIBLE (child))
+       clutter_actor_paint (child);
+    }
+
+  cogl_pop_matrix();
+}
+
+#define MIN_SIZE 24
+#define MAX_SIZE 64
+
+static void
+my_thing_class_init (MyThingClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  gobject_class->set_property = my_thing_set_property;
+  gobject_class->get_property = my_thing_get_property;
+  gobject_class->dispose      = my_thing_dispose;
+  gobject_class->finalize     = my_thing_finalize;
+
+  actor_class->get_preferred_width  = my_thing_get_preferred_width;
+  actor_class->get_preferred_height = my_thing_get_preferred_height;
+  actor_class->allocate             = my_thing_allocate;
+  actor_class->paint                = my_thing_paint;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_SPACING,
+                                   clutter_param_spec_unit ("spacing",
+                                                            "Spacing",
+                                                            "Spacing of the thing",
+                                                            0, CLUTTER_MAXUNIT,
+                                                            0,
+                                                            G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_PADDING,
+                                   clutter_param_spec_unit ("padding",
+                                                            "Padding",
+                                                            "Padding around the thing",
+                                                            0, CLUTTER_MAXUNIT,
+                                                            0,
+                                                            G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_USE_TRANSFORMED_BOX,
+                                   g_param_spec_boolean ("use-transformed-box",
+                                                         "Use Transformed Box",
+                                                         "Use transformed box when allocating",
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
+
+  g_type_class_add_private (klass, sizeof (MyThingPrivate));
+}
+
+static void
+my_thing_init (MyThing *thing)
+{
+  thing->priv = MY_THING_GET_PRIVATE (thing);
+}
+
+ClutterActor *
+my_thing_new (gint padding,
+              gint spacing)
+{
+  return g_object_new (MY_TYPE_THING,
+                       "padding", CLUTTER_UNITS_FROM_DEVICE (padding),
+                       "spacing", CLUTTER_UNITS_FROM_DEVICE (spacing),
+                       NULL);
+
+}
+
+/* test code */
+
+static ClutterActor *stage         = NULL;
+static ClutterActor *box           = NULL;
+static ClutterActor *icon          = NULL;
+static ClutterTimeline *timeline   = NULL;
+static ClutterBehaviour *behaviour = NULL;
+
+static ClutterColor bg_color;
+
+static void
+toggle_property_value (ClutterActor *actor,
+                       const gchar  *property_name)
+{
+  gboolean value;
+
+  g_object_get (G_OBJECT (actor),
+                property_name, &value,
+                NULL);
+
+  value = !value;
+
+  g_object_set (G_OBJECT (box),
+                property_name, value,
+                NULL);
+}
+
+static void
+increase_property_value (ClutterActor *actor, 
+                         const char   *property_name)
+{
+  ClutterUnit value;
+
+  g_object_get (G_OBJECT (actor),
+                property_name, &value,
+                NULL);
+
+  value = value + CLUTTER_UNITS_FROM_DEVICE (10);
+
+  g_object_set (G_OBJECT (box),
+                property_name, value,
+                NULL);
+}
+
+static void
+decrease_property_value (ClutterActor *actor, 
+                         const char   *property_name)
+{
+  ClutterUnit value;
+
+  g_object_get (G_OBJECT (actor),
+                property_name, &value,
+                NULL);
+
+  value = MAX (0, value - CLUTTER_UNITS_FROM_DEVICE (10));
+
+  g_object_set (G_OBJECT (box),
+                property_name, value,
+                NULL);
+}
+
+static ClutterActor *
+create_item()
+{
+  ClutterActor *clone = 
+    clutter_clone_texture_new (CLUTTER_TEXTURE (icon));
+  
+  gint32 size = g_random_int_range (MIN_SIZE, MAX_SIZE);
+  
+  clutter_actor_set_size (clone, size, size);
+
+  clutter_behaviour_apply (behaviour, clone);
+
+  return clone;
+}
+
+static gboolean
+keypress_cb (ClutterStage    *stage,
+            ClutterKeyEvent *event,
+            gpointer         data)
+{
+  switch (clutter_key_event_symbol (event))
+    {
+    case CLUTTER_q:
+      {
+        clutter_main_quit ();
+      }
+
+    case CLUTTER_a:
+      {
+        if (icon != NULL)
+          {
+            ClutterActor *clone = create_item (); 
+
+            /* Add one item to container */
+            clutter_container_add_actor (CLUTTER_CONTAINER (box), clone);
+          }
+        break;
+      }
+
+    case CLUTTER_d:
+      {
+        GList *children = 
+          clutter_container_get_children (CLUTTER_CONTAINER (box));
+
+        if (children)
+          {
+            GList *last = g_list_last (children);
+
+            /* Remove last item on container */
+            clutter_container_remove_actor (CLUTTER_CONTAINER (box), 
+                                            CLUTTER_ACTOR (last->data));
+          }
+        break;
+      }
+
+    case CLUTTER_w:
+      {
+        decrease_property_value (box, "padding");
+        break;
+      }
+
+    case CLUTTER_e:
+      {
+        increase_property_value (box, "padding");
+        break;
+      }
+
+    case CLUTTER_r:
+      {
+        decrease_property_value (box, "spacing");
+        break;
+      }
+
+    case CLUTTER_s:
+      {
+        toggle_property_value (box, "use-transformed-box");
+        break;
+      }
+
+    case CLUTTER_t:
+      {
+        increase_property_value (box, "spacing");
+        break;
+      }
+
+    case CLUTTER_z:
+      {
+        if (clutter_timeline_is_playing (timeline))
+          clutter_timeline_pause (timeline);
+        else
+          clutter_timeline_start (timeline);
+
+        break;
+      }
+
+    default:
+    break;
+    } 
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  ClutterActor *instructions;
+  gint i;
+  GError *error = NULL;
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+  clutter_actor_set_size (stage, 800, 600);
+
+  clutter_color_parse ("Red", &bg_color);
+
+  timeline = clutter_timeline_new_for_duration (2000);
+  clutter_timeline_set_loop (timeline, TRUE);
+
+  behaviour = clutter_behaviour_scale_new (clutter_alpha_new_full (timeline,
+                                                                   CLUTTER_ALPHA_SINE,
+                                                                   NULL, NULL),
+                                           1.0, 1.0, 2.0, 2.0);
+
+  box = my_thing_new (10, 10);
+
+  clutter_actor_set_position (box, 20, 20);
+  clutter_actor_set_size (box, 400, -1);
+
+  icon = clutter_texture_new_from_file ("redhand.png", &error);
+  if (error)
+    g_error ("Unable to load 'redhand.png': %s", error->message);
+
+  for (i = 0; i < 33; i++)
+    {
+      ClutterActor *clone = create_item (); 
+
+      clutter_container_add_actor (CLUTTER_CONTAINER (box), clone);
+    }
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
+
+  instructions = clutter_label_new_with_text ("Sans 14", 
+                                              "<b>Instructions:</b>\n"
+                                              "a - add a new item\n"
+                                              "d - remove last item\n"
+                                              "z - start/pause behaviour\n"
+                                              "w - decrease padding\n"
+                                              "e - increase padding\n"
+                                              "r - decrease spacing\n"
+                                              "t - increase spacing\n"
+                                              "s - use transformed box\n"
+                                              "q - quit");
+
+  clutter_label_set_use_markup (CLUTTER_LABEL (instructions), TRUE);
+  clutter_actor_set_position (instructions, 450, 10);
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), instructions);
+
+  g_signal_connect (stage, "key-release-event",
+                   G_CALLBACK (keypress_cb),
+                   NULL);
+
+  clutter_actor_show (stage);
+
+  clutter_main ();
+
+  g_object_unref (timeline);
+  g_object_unref (behaviour);
+
+  return EXIT_SUCCESS;
+}
index 6fac2ff..bff5ba4 100644 (file)
@@ -31,9 +31,9 @@ main (int argc, char *argv[])
   clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
   g_assert (color_check.alpha == label_color.alpha);
 
-  g_print ("label 50%%.get_abs_opacity() = %d\n",
-           clutter_actor_get_abs_opacity (label));
-  g_assert (clutter_actor_get_abs_opacity (label) == 128);
+  g_print ("label 50%%.get_paint_opacity() = %d\n",
+           clutter_actor_get_paint_opacity (label));
+  g_assert (clutter_actor_get_paint_opacity (label) == 128);
 
   clutter_actor_show (label);
 
@@ -57,9 +57,9 @@ main (int argc, char *argv[])
   clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
   g_assert (color_check.alpha == label_color.alpha);
 
-  g_print ("label 50%% + group 50%%.get_abs_opacity() = %d\n",
-           clutter_actor_get_abs_opacity (label));
-  g_assert (clutter_actor_get_abs_opacity (label) == 64);
+  g_print ("label 50%% + group 50%%.get_paint_opacity() = %d\n",
+           clutter_actor_get_paint_opacity (label));
+  g_assert (clutter_actor_get_paint_opacity (label) == 64);
 
   clutter_actor_show (label);
 
@@ -81,9 +81,9 @@ main (int argc, char *argv[])
   clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
   g_assert (color_check.alpha == rect_color.alpha);
 
-  g_print ("rect 100%%.get_abs_opacity() = %d\n",
-           clutter_actor_get_abs_opacity (rect));
-  g_assert (clutter_actor_get_abs_opacity (rect) == 128);
+  g_print ("rect 100%%.get_paint_opacity() = %d\n",
+           clutter_actor_get_paint_opacity (rect));
+  g_assert (clutter_actor_get_paint_opacity (rect) == 128);
 
   clutter_actor_show (rect);
 
@@ -101,9 +101,9 @@ main (int argc, char *argv[])
   clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
   g_assert (color_check.alpha == rect_color.alpha);
 
-  g_print ("rect 100%%.get_abs_opacity() = %d\n",
-           clutter_actor_get_abs_opacity (rect));
-  g_assert (clutter_actor_get_abs_opacity (rect) == 255);
+  g_print ("rect 100%%.get_paint_opacity() = %d\n",
+           clutter_actor_get_paint_opacity (rect));
+  g_assert (clutter_actor_get_paint_opacity (rect) == 255);
 
   clutter_actor_show (rect);
 
index 2604158..1ad01e8 100644 (file)
@@ -12,7 +12,7 @@ init_handles ()
   ClutterVertex    v1, v2;
   ClutterColor blue = { 0, 0, 0xff, 0xff };
 
-  clutter_actor_get_vertices (rect, v);
+  clutter_actor_get_abs_allocation_vertices (rect, v);
   for (i = 0; i < 4; ++i)
     {
       p[i] = clutter_rectangle_new_with_color (&blue);
@@ -58,7 +58,7 @@ place_handles ()
   ClutterVertex    v[4];
   ClutterVertex    v1, v2;
 
-  clutter_actor_get_vertices (rect, v);
+  clutter_actor_get_abs_allocation_vertices (rect, v);
   for (i = 0; i < 4; ++i)
     {
       clutter_actor_set_position (p[i],
@@ -136,8 +136,8 @@ on_event (ClutterStage *stage,
            
            clutter_event_get_coords (event, &x, &y);
            
-           clutter_actor_query_coords (dragging, &box1);
-           clutter_actor_query_coords (rect, &box2);
+           clutter_actor_get_allocation_box (dragging, &box1);
+           clutter_actor_get_allocation_box (rect, &box2);
 
            xp = CLUTTER_INT_TO_FIXED (x-3) - box1.x1;
            yp = CLUTTER_INT_TO_FIXED (y-3) - box1.y1;
@@ -178,7 +178,10 @@ on_event (ClutterStage *stage,
                    break;
                  }
 
-               clutter_actor_request_coords (rect, &box2);
+                /* FIXME this is just plain wrong, to allocate directly
+                 * like this
+                 */
+               clutter_actor_allocate (rect, &box2, TRUE);
              }
            
            place_handles ();