Add dependencies
[clutter-gtk] / clutter-gtk / gtk-clutter-viewport.c
index d050ea5..c2f6a15 100644 (file)
@@ -14,7 +14,7 @@
  * The #GtkClutterViewport can be used inside any #ClutterContainer
  * implementation.
  *
- * #GtkClutterViewport is available since Clutter-GTK 1.0
+ * #GtkClutterViewport is available since Clutter-GTK 0.10
  */
 
 #ifdef HAVE_CONFIG_H
 
 #include <cogl/cogl.h>
 
+#include "gtk-clutter-viewport.h"
+
 #include "gtk-clutter-scrollable.h"
 #include "gtk-clutter-util.h"
-#include "gtk-clutter-viewport.h"
+#include "gtk-clutter-zoomable.h"
 
 /* XXX - GtkAdjustment accessors have been added with GTK+ 2.14,
  * but I want Clutter-GTK to be future-proof, so let's do this
 #define gtk_adjustment_set_step_increment(a,v)  ((a)->step_increment = (v))
 #define gtk_adjustment_set_lower(a,v)           ((a)->lower = (v))
 
+#define gtk_adjustment_get_lower(a)             ((a)->lower)
 #define gtk_adjustment_get_upper(a)             ((a)->upper)
 #define gtk_adjustment_get_page_size(a)         ((a)->page_size)
 #endif
 
-#define GET_PRIVATE(obj)        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CLUTTER_VIEWPORT, GtkClutterViewportPrivate))
+#define GET_PRIVATE(obj)        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_CLUTTER_TYPE_VIEWPORT, GtkClutterViewportPrivate))
 
 #define I_(str) (g_intern_static_string ((str)))
 
+typedef enum {
+  VIEWPORT_X_AXIS,
+  VIEWPORT_Y_AXIS,
+  VIEWPORT_Z_AXIS
+} ViewportAxis;
+
 static void clutter_container_iface_init      (gpointer g_iface);
 static void gtk_clutter_scrollable_iface_init (gpointer g_iface);
+static void gtk_clutter_zoomable_iface_init   (gpointer g_iface);
 
 G_DEFINE_TYPE_WITH_CODE (GtkClutterViewport,
                          gtk_clutter_viewport,
                          CLUTTER_TYPE_ACTOR,
                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
                                                 clutter_container_iface_init)
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_CLUTTER_SCROLLABLE,
-                                                gtk_clutter_scrollable_iface_init));
+                         G_IMPLEMENT_INTERFACE (GTK_CLUTTER_TYPE_SCROLLABLE,
+                                                gtk_clutter_scrollable_iface_init)
+                         G_IMPLEMENT_INTERFACE (GTK_CLUTTER_TYPE_ZOOMABLE,
+                                                gtk_clutter_zoomable_iface_init));
 
 struct _GtkClutterViewportPrivate
 {
@@ -63,8 +75,9 @@ struct _GtkClutterViewportPrivate
 
   ClutterActor *child;
 
-  GtkAdjustment *h_adjustment;
-  GtkAdjustment *v_adjustment;
+  GtkAdjustment *x_adjustment;
+  GtkAdjustment *y_adjustment;
+  GtkAdjustment *z_adjustment;
 };
 
 enum
@@ -73,8 +86,10 @@ enum
 
   PROP_CHILD,
   PROP_ORIGIN,
+
   PROP_H_ADJUSTMENT,
-  PROP_V_ADJUSTMENT
+  PROP_V_ADJUSTMENT,
+  PROP_Z_ADJUSTMENT
 };
 
 static void
@@ -145,20 +160,27 @@ viewport_adjustment_value_changed (GtkAdjustment      *adjustment,
 
   if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
     {
-      GtkAdjustment *h_adjust = priv->h_adjustment;
-      GtkAdjustment *v_adjust = priv->v_adjustment;
-      ClutterUnit new_x, new_y;
+      GtkAdjustment *x_adjust = priv->x_adjustment;
+      GtkAdjustment *y_adjust = priv->y_adjustment;
+      GtkAdjustment *z_adjust = priv->z_adjustment;
+      gfloat new_x, new_y, new_z;
 
-      new_x = CLUTTER_UNITS_FROM_FLOAT (gtk_adjustment_get_value (h_adjust));
-      new_y = CLUTTER_UNITS_FROM_FLOAT (gtk_adjustment_get_value (v_adjust));
+      new_x = gtk_adjustment_get_value (x_adjust);
+      new_y = gtk_adjustment_get_value (y_adjust);
+      new_z = gtk_adjustment_get_value (z_adjust);
 
       /* change the origin and queue a relayout */
-      if (new_x != priv->origin.x || new_y != priv->origin.y)
+      if (new_x != priv->origin.x ||
+          new_y != priv->origin.y ||
+          new_z != priv->origin.z)
         {
           priv->origin.x = new_x;
           priv->origin.y = new_y;
+          priv->origin.z = new_z;
 
           clutter_actor_queue_relayout (CLUTTER_ACTOR (viewport));
+
+          g_object_notify (G_OBJECT (viewport), "origin");
         }
     }
 }
@@ -184,10 +206,15 @@ viewport_reclamp_adjustment (GtkAdjustment *adjustment)
 
 static gboolean
 viewport_set_hadjustment_values (GtkClutterViewport *viewport,
-                                 guint               width)
+                                 gfloat              width)
 {
   GtkClutterViewportPrivate *priv = viewport->priv;
-  GtkAdjustment *h_adjust = priv->h_adjustment;
+  GtkAdjustment *h_adjust = priv->x_adjustment;
+
+  if (width < 0)
+    clutter_actor_get_preferred_width (CLUTTER_ACTOR (viewport), -1,
+                                       NULL,
+                                       &width);
 
   gtk_adjustment_set_page_size (h_adjust, width);
   gtk_adjustment_set_step_increment (h_adjust, width * 0.1);
@@ -196,15 +223,13 @@ viewport_set_hadjustment_values (GtkClutterViewport *viewport,
 
   if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
     {
-      ClutterUnit natural_width;
+      gfloat natural_width;
 
       clutter_actor_get_preferred_size (priv->child,
                                         NULL, NULL,
                                         &natural_width, NULL);
 
-      gtk_adjustment_set_upper (h_adjust,
-                                MAX (CLUTTER_UNITS_TO_DEVICE (natural_width),
-                                     width));
+      gtk_adjustment_set_upper (h_adjust, MAX (natural_width, width));
     }
   else
     gtk_adjustment_set_upper (h_adjust, width);
@@ -214,12 +239,15 @@ viewport_set_hadjustment_values (GtkClutterViewport *viewport,
 
 static gboolean
 viewport_set_vadjustment_values (GtkClutterViewport *viewport,
-                                 guint               height)
+                                 gfloat              height)
 {
   GtkClutterViewportPrivate *priv = viewport->priv;
-  GtkAdjustment *v_adjust = priv->v_adjustment;
+  GtkAdjustment *v_adjust = priv->y_adjustment;
 
-  height = clutter_actor_get_height (CLUTTER_ACTOR (viewport));
+  if (height < 0)
+    clutter_actor_get_preferred_height (CLUTTER_ACTOR (viewport), -1,
+                                        NULL,
+                                        &height);
 
   gtk_adjustment_set_page_size (v_adjust, height);
   gtk_adjustment_set_step_increment (v_adjust, height * 0.1);
@@ -228,15 +256,13 @@ viewport_set_vadjustment_values (GtkClutterViewport *viewport,
 
   if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
     {
-      ClutterUnit natural_height;
+      gfloat natural_height;
 
       clutter_actor_get_preferred_size (priv->child,
                                         NULL, NULL,
                                         NULL, &natural_height);
 
-      gtk_adjustment_set_upper (v_adjust,
-                                MAX (CLUTTER_UNITS_TO_DEVICE (natural_height),
-                                     height));
+      gtk_adjustment_set_upper (v_adjust, MAX (natural_height, height));
     }
   else
     gtk_adjustment_set_upper (v_adjust, height);
@@ -244,17 +270,71 @@ viewport_set_vadjustment_values (GtkClutterViewport *viewport,
   return viewport_reclamp_adjustment (v_adjust);
 }
 
+static gboolean
+viewport_set_zadjustment_values (GtkClutterViewport *viewport,
+                                 gfloat              width,
+                                 gfloat              height)
+{
+  GtkClutterViewportPrivate *priv = viewport->priv;
+  GtkAdjustment *z_adjust = priv->z_adjustment;
+  gfloat depth;
+
+  if (width < 0)
+    clutter_actor_get_preferred_width (CLUTTER_ACTOR (viewport), -1,
+                                       NULL,
+                                       &width);
+
+  if (height < 0)
+    clutter_actor_get_preferred_height (CLUTTER_ACTOR (viewport), -1,
+                                        NULL,
+                                        &height);
+
+  depth = clutter_actor_get_depth (CLUTTER_ACTOR (viewport));
+
+  gtk_adjustment_set_page_size (z_adjust, 0.0);
+  gtk_adjustment_set_step_increment (z_adjust, MIN (width, height) * 0.1);
+  gtk_adjustment_set_page_increment (z_adjust, MIN (width, height) * 0.9);
+  gtk_adjustment_set_lower (z_adjust, 0.0);
+  gtk_adjustment_set_upper (z_adjust, MAX (width, height));
+
+#if 0
+  g_debug ("%s: zadjustment: { %.2f lower, %.2f page, %.2f upper }",
+           G_STRLOC,
+           gtk_adjustment_get_lower (z_adjust),
+           gtk_adjustment_get_page_size (z_adjust),
+           gtk_adjustment_get_upper (z_adjust));
+#endif
+
+  return viewport_reclamp_adjustment (z_adjust);
+}
+
 static inline void
 disconnect_adjustment (GtkClutterViewport *viewport,
-                       GtkOrientation      orientation)
+                       ViewportAxis        axis)
 {
   GtkClutterViewportPrivate *priv = viewport->priv;
-  GtkAdjustment **adj_p;
+  GtkAdjustment **adj_p = NULL;
+
+  switch (axis)
+    {
+    case VIEWPORT_X_AXIS:
+      adj_p = &priv->x_adjustment;
+      break;
+
+    case VIEWPORT_Y_AXIS:
+      adj_p = &priv->y_adjustment;
+      break;
 
-  adj_p = (orientation == GTK_ORIENTATION_HORIZONTAL) ? &priv->h_adjustment
-                                                      : &priv->v_adjustment;
+    case VIEWPORT_Z_AXIS:
+      adj_p = &priv->z_adjustment;
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
 
-  if (*adj_p)
+  if (*adj_p != NULL)
     {
       g_signal_handlers_disconnect_by_func (*adj_p,
                                             viewport_adjustment_value_changed,
@@ -266,16 +346,32 @@ disconnect_adjustment (GtkClutterViewport *viewport,
 
 static inline void
 connect_adjustment (GtkClutterViewport *viewport,
-                    GtkOrientation      orientation,
+                    ViewportAxis        axis,
                     GtkAdjustment      *adjustment)
 {
   GtkClutterViewportPrivate *priv = viewport->priv;
-  GtkAdjustment **adj_p;
+  GtkAdjustment **adj_p = NULL;
   gboolean value_changed = FALSE;
-  guint width, height;
+  gfloat width, height;
+
+  switch (axis)
+    {
+    case VIEWPORT_X_AXIS:
+      adj_p = &priv->x_adjustment;
+      break;
 
-  adj_p = (orientation == GTK_ORIENTATION_HORIZONTAL) ? &priv->h_adjustment
-                                                      : &priv->v_adjustment;
+    case VIEWPORT_Y_AXIS:
+      adj_p = &priv->y_adjustment;
+      break;
+
+    case VIEWPORT_Z_AXIS:
+      adj_p = &priv->z_adjustment;
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
 
   if (adjustment && adjustment == *adj_p)
     return;
@@ -283,15 +379,31 @@ connect_adjustment (GtkClutterViewport *viewport,
   if (!adjustment)
     adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 0, 0, 0, 0));
 
-  disconnect_adjustment (viewport, orientation);
+  disconnect_adjustment (viewport, axis);
   *adj_p = g_object_ref_sink (adjustment);
 
   clutter_actor_get_size (CLUTTER_ACTOR (viewport), &width, &height);
 
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    value_changed = viewport_set_hadjustment_values (viewport, width);
-  else
-    value_changed = viewport_set_vadjustment_values (viewport, height);
+  switch (axis)
+    {
+    case VIEWPORT_X_AXIS:
+      value_changed = viewport_set_hadjustment_values (viewport, width);
+      break;
+
+    case VIEWPORT_Y_AXIS:
+      value_changed = viewport_set_vadjustment_values (viewport, height);
+      break;
+
+    case VIEWPORT_Z_AXIS:
+      value_changed = viewport_set_zadjustment_values (viewport,
+                                                       width,
+                                                       height);
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
 
   g_signal_connect (adjustment, "value-changed",
                     G_CALLBACK (viewport_adjustment_value_changed),
@@ -304,41 +416,55 @@ connect_adjustment (GtkClutterViewport *viewport,
   else
     viewport_adjustment_value_changed (adjustment, viewport);
 
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    g_object_notify (G_OBJECT (viewport), "hadjustment");
-  else
-    g_object_notify (G_OBJECT (viewport), "vadjustment");
+  switch (axis)
+    {
+    case VIEWPORT_X_AXIS:
+      g_object_notify (G_OBJECT (viewport), "hadjustment");
+      break;
+
+    case VIEWPORT_Y_AXIS:
+      g_object_notify (G_OBJECT (viewport), "vadjustment");
+      break;
+
+    case VIEWPORT_Z_AXIS:
+      g_object_notify (G_OBJECT (viewport), "zadjustment");
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
 }
 
 static void
-gtk_clutter_viewport_set_adjustments (GtkClutterScrollable *scrollable,
-                                      GtkAdjustment        *h_adjust,
-                                      GtkAdjustment        *v_adjust)
+scrollable_set_adjustments (GtkClutterScrollable *scrollable,
+                            GtkAdjustment        *h_adjust,
+                            GtkAdjustment        *v_adjust)
 {
   g_object_freeze_notify (G_OBJECT (scrollable));
 
   connect_adjustment (GTK_CLUTTER_VIEWPORT (scrollable),
-                      GTK_ORIENTATION_HORIZONTAL,
+                      VIEWPORT_X_AXIS,
                       h_adjust);
   connect_adjustment (GTK_CLUTTER_VIEWPORT (scrollable),
-                      GTK_ORIENTATION_VERTICAL,
+                      VIEWPORT_Y_AXIS,
                       v_adjust);
 
   g_object_thaw_notify (G_OBJECT (scrollable));
 }
 
 static void
-gtk_clutter_viewport_get_adjustments (GtkClutterScrollable  *scrollable,
-                                      GtkAdjustment        **h_adjust,
-                                      GtkAdjustment        **v_adjust)
+scrollable_get_adjustments (GtkClutterScrollable  *scrollable,
+                            GtkAdjustment        **h_adjust,
+                            GtkAdjustment        **v_adjust)
 {
   GtkClutterViewportPrivate *priv = GTK_CLUTTER_VIEWPORT (scrollable)->priv;
 
   if (h_adjust)
-    *h_adjust = priv->h_adjustment;
+    *h_adjust = priv->x_adjustment;
 
   if (v_adjust)
-    *v_adjust = priv->v_adjustment;
+    *v_adjust = priv->y_adjustment;
 }
 
 static void
@@ -346,8 +472,38 @@ gtk_clutter_scrollable_iface_init (gpointer g_iface)
 {
   GtkClutterScrollableIface *iface = g_iface;
 
-  iface->set_adjustments = gtk_clutter_viewport_set_adjustments;
-  iface->get_adjustments = gtk_clutter_viewport_get_adjustments;
+  iface->set_adjustments = scrollable_set_adjustments;
+  iface->get_adjustments = scrollable_get_adjustments;
+}
+
+static void
+zoomable_set_adjustment (GtkClutterZoomable *zoomable,
+                         GtkAdjustment      *adjust)
+{
+  g_object_freeze_notify (G_OBJECT (zoomable));
+
+  connect_adjustment (GTK_CLUTTER_VIEWPORT (zoomable),
+                      VIEWPORT_Z_AXIS,
+                      adjust);
+
+  g_object_thaw_notify (G_OBJECT (zoomable));
+}
+
+static GtkAdjustment *
+zoomable_get_adjustment (GtkClutterZoomable *zoomable)
+{
+  GtkClutterViewportPrivate *priv = GTK_CLUTTER_VIEWPORT (zoomable)->priv;
+
+  return priv->z_adjustment;
+}
+
+static void
+gtk_clutter_zoomable_iface_init (gpointer g_iface)
+{
+  GtkClutterZoomableIface *iface = g_iface;
+
+  iface->set_adjustment = zoomable_set_adjustment;
+  iface->get_adjustment = zoomable_get_adjustment;
 }
 
 static void
@@ -378,13 +534,19 @@ gtk_clutter_viewport_set_property (GObject      *gobject,
 
     case PROP_H_ADJUSTMENT:
       connect_adjustment (GTK_CLUTTER_VIEWPORT (gobject),
-                          GTK_ORIENTATION_HORIZONTAL,
+                          VIEWPORT_X_AXIS,
                           g_value_get_object (value));
       break;
 
     case PROP_V_ADJUSTMENT:
       connect_adjustment (GTK_CLUTTER_VIEWPORT (gobject),
-                          GTK_ORIENTATION_VERTICAL,
+                          VIEWPORT_Y_AXIS,
+                          g_value_get_object (value));
+      break;
+
+    case PROP_Z_ADJUSTMENT:
+      connect_adjustment (GTK_CLUTTER_VIEWPORT (gobject),
+                          VIEWPORT_Z_AXIS,
                           g_value_get_object (value));
       break;
 
@@ -413,11 +575,15 @@ gtk_clutter_viewport_get_property (GObject    *gobject,
       break;
 
     case PROP_H_ADJUSTMENT:
-      g_value_set_object (value, priv->h_adjustment);
+      g_value_set_object (value, priv->x_adjustment);
       break;
 
     case PROP_V_ADJUSTMENT:
-      g_value_set_object (value, priv->v_adjustment);
+      g_value_set_object (value, priv->y_adjustment);
+      break;
+
+    case PROP_Z_ADJUSTMENT:
+      g_value_set_object (value, priv->z_adjustment);
       break;
 
     default:
@@ -438,18 +604,20 @@ gtk_clutter_viewport_dispose (GObject *gobject)
     }
 
   disconnect_adjustment (GTK_CLUTTER_VIEWPORT (gobject),
-                         GTK_ORIENTATION_HORIZONTAL);
+                         VIEWPORT_X_AXIS);
+  disconnect_adjustment (GTK_CLUTTER_VIEWPORT (gobject),
+                         VIEWPORT_Y_AXIS);
   disconnect_adjustment (GTK_CLUTTER_VIEWPORT (gobject),
-                         GTK_ORIENTATION_VERTICAL);
+                         VIEWPORT_Z_AXIS);
 
   G_OBJECT_CLASS (gtk_clutter_viewport_parent_class)->dispose (gobject);
 }
 
 static void
 gtk_clutter_viewport_get_preferred_width (ClutterActor *actor,
-                                          ClutterUnit   for_height,
-                                          ClutterUnit  *min_width_p,
-                                          ClutterUnit  *natural_width_p)
+                                          gfloat        for_height,
+                                          gfloat       *min_width_p,
+                                          gfloat       *natural_width_p)
 {
   GtkClutterViewportPrivate *priv = GTK_CLUTTER_VIEWPORT (actor)->priv;
 
@@ -473,9 +641,9 @@ gtk_clutter_viewport_get_preferred_width (ClutterActor *actor,
 
 static void
 gtk_clutter_viewport_get_preferred_height (ClutterActor *actor,
-                                           ClutterUnit   for_width,
-                                           ClutterUnit  *min_height_p,
-                                           ClutterUnit  *natural_height_p)
+                                           gfloat        for_width,
+                                           gfloat       *min_height_p,
+                                           gfloat       *natural_height_p)
 {
   GtkClutterViewportPrivate *priv = GTK_CLUTTER_VIEWPORT (actor)->priv;
 
@@ -498,31 +666,35 @@ gtk_clutter_viewport_get_preferred_height (ClutterActor *actor,
 }
 
 static void
-gtk_clutter_viewport_allocate (ClutterActor          *actor,
-                               const ClutterActorBox *box,
-                               gboolean               origin_changed)
+gtk_clutter_viewport_allocate (ClutterActor           *actor,
+                               const ClutterActorBox  *box,
+                               ClutterAllocationFlags  flags)
 {
   GtkClutterViewport *viewport = GTK_CLUTTER_VIEWPORT (actor);
   GtkClutterViewportPrivate *priv = viewport->priv;
   ClutterActorClass *parent_class;
-  gboolean h_adjustment_value_changed, v_adjustment_value_changed;
-  guint width, height;
+  gboolean x_adjustment_value_changed;
+  gboolean y_adjustment_value_changed;
+  gboolean z_adjustment_value_changed;
+  gfloat width, height;
 
   parent_class = CLUTTER_ACTOR_CLASS (gtk_clutter_viewport_parent_class);
-  parent_class->allocate (actor, box, origin_changed);
+  parent_class->allocate (actor, box, flags);
 
-  width  = CLUTTER_UNITS_TO_DEVICE (box->x2 - box->x1);
-  height = CLUTTER_UNITS_TO_DEVICE (box->y2 - box->y1);
+  width  = box->x2 - box->x1;
+  height = box->y2 - box->y1;
 
-  h_adjustment_value_changed =
+  x_adjustment_value_changed =
     viewport_set_hadjustment_values (viewport, width);
-  v_adjustment_value_changed =
+  y_adjustment_value_changed =
     viewport_set_vadjustment_values (viewport, height);
+  z_adjustment_value_changed =
+    viewport_set_zadjustment_values (viewport, width, height);
 
   if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
     {
       ClutterActorBox child_allocation = { 0, };
-      ClutterUnit alloc_width, alloc_height;
+      gfloat alloc_width, alloc_height;
 
       /* a viewport is a boundless actor which can contain a child
        * without constraints; hence, we give any child exactly the
@@ -531,56 +703,68 @@ gtk_clutter_viewport_allocate (ClutterActor          *actor,
        */
       clutter_actor_get_preferred_size (priv->child,
                                         NULL, NULL,
-                                        &alloc_width, &alloc_height);
+                                        &alloc_width,
+                                        &alloc_height);
 
-      child_allocation.x1 = clutter_actor_get_xu (priv->child);
-      child_allocation.y1 = clutter_actor_get_yu (priv->child);
+      child_allocation.x1 = 0;
+      child_allocation.y1 = 0;
       child_allocation.x2 = child_allocation.x1 + alloc_width;
       child_allocation.y2 = child_allocation.y1 + alloc_height;
 
-      clutter_actor_allocate (priv->child, &child_allocation, origin_changed);
+      clutter_actor_allocate (priv->child, &child_allocation, flags);
     }
 
-  gtk_adjustment_changed (priv->h_adjustment);
-  gtk_adjustment_changed (priv->v_adjustment);
+  gtk_adjustment_changed (priv->x_adjustment);
+  gtk_adjustment_changed (priv->y_adjustment);
+  gtk_adjustment_changed (priv->z_adjustment);
 
-  if (h_adjustment_value_changed)
-    gtk_adjustment_value_changed (priv->h_adjustment);
+  if (x_adjustment_value_changed)
+    gtk_adjustment_value_changed (priv->x_adjustment);
 
-  if (v_adjustment_value_changed)
-    gtk_adjustment_value_changed (priv->v_adjustment);
+  if (y_adjustment_value_changed)
+    gtk_adjustment_value_changed (priv->y_adjustment);
+
+  if (z_adjustment_value_changed)
+    gtk_adjustment_value_changed (priv->z_adjustment);
 }
 
 static void
-gtk_clutter_viewport_paint (ClutterActor *actor)
+gtk_clutter_viewport_apply_transform (ClutterActor *actor,
+                                      CoglMatrix   *matrix)
 {
   GtkClutterViewportPrivate *priv = GTK_CLUTTER_VIEWPORT (actor)->priv;
+  ClutterActorClass *parent_class;
 
-  cogl_push_matrix ();
+  parent_class = CLUTTER_ACTOR_CLASS (gtk_clutter_viewport_parent_class);
+  parent_class->apply_transform (actor, matrix);
 
-  /* translate the paint environment by the same amount
-   * defined by the origin value
-   */
-  cogl_translatex (CLUTTER_UNITS_TO_FIXED (priv->origin.x) * -1,
-                   CLUTTER_UNITS_TO_FIXED (priv->origin.y) * -1,
-                   CLUTTER_UNITS_TO_FIXED (priv->origin.z) * -1);
+  cogl_matrix_translate (matrix,
+                         priv->origin.x * -1,
+                         priv->origin.y * -1,
+                         priv->origin.z * -1);
+}
 
-  /* the child will be painted in the new frame of reference */
-  if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
-    clutter_actor_paint (priv->child);
+static void
+gtk_clutter_viewport_paint (ClutterActor *actor)
+{
+  GtkClutterViewportPrivate *priv = GTK_CLUTTER_VIEWPORT (actor)->priv;
 
-  cogl_pop_matrix ();
+  if (priv->child)
+    clutter_actor_paint (priv->child);
 }
 
 static void
 gtk_clutter_viewport_pick (ClutterActor       *actor,
                            const ClutterColor *pick_color)
 {
-  /* chain up to get the default pick */
-  CLUTTER_ACTOR_CLASS (gtk_clutter_viewport_parent_class)->pick (actor, pick_color);
+  GtkClutterViewportPrivate *priv = GTK_CLUTTER_VIEWPORT (actor)->priv;
+  ClutterActorClass *parent_class;
+
+  parent_class = CLUTTER_ACTOR_CLASS (gtk_clutter_viewport_parent_class);
+  parent_class->pick (actor, pick_color);
 
-  /* this will cause the child (if any) to be painted in pick mode */
-  gtk_clutter_viewport_paint (actor);
+  if (priv->child)
+    clutter_actor_paint (priv->child);
 }
 
 static void
@@ -599,6 +783,7 @@ gtk_clutter_viewport_class_init (GtkClutterViewportClass *klass)
   actor_class->get_preferred_width = gtk_clutter_viewport_get_preferred_width;
   actor_class->get_preferred_height = gtk_clutter_viewport_get_preferred_height;
   actor_class->allocate = gtk_clutter_viewport_allocate;
+  actor_class->apply_transform = gtk_clutter_viewport_apply_transform;
   actor_class->paint = gtk_clutter_viewport_paint;
   actor_class->pick = gtk_clutter_viewport_pick;
 
@@ -607,7 +792,7 @@ gtk_clutter_viewport_class_init (GtkClutterViewportClass *klass)
    *
    * The #ClutterActor inside the viewport.
    *
-   * Since: 1.0
+   * Since: 0.10
    */
   pspec = g_param_spec_object ("child",
                                "Child",
@@ -619,9 +804,11 @@ gtk_clutter_viewport_class_init (GtkClutterViewportClass *klass)
   /**
    * GtkClutterViewport:origin:
    *
-   * The current origin of the viewport.
+   * The current origin of the viewport. You should use the
+   * vertex to convert event coordinates for the child of the
+   * viewport.
    *
-   * Since: 1.0
+   * Since: 0.10
    */
   pspec = g_param_spec_boxed ("origin",
                               "Origin",
@@ -631,8 +818,17 @@ gtk_clutter_viewport_class_init (GtkClutterViewportClass *klass)
   g_object_class_install_property (gobject_class, PROP_ORIGIN, pspec);
 
   /* GtkClutterScrollable properties */
-  g_object_class_override_property (gobject_class, PROP_H_ADJUSTMENT, "hadjustment");
-  g_object_class_override_property (gobject_class, PROP_V_ADJUSTMENT, "vadjustment");
+  g_object_class_override_property (gobject_class,
+                                    PROP_H_ADJUSTMENT,
+                                    "hadjustment");
+  g_object_class_override_property (gobject_class,
+                                    PROP_V_ADJUSTMENT,
+                                    "vadjustment");
+
+  /* GtkClutterZoomable properties */
+  g_object_class_override_property (gobject_class,
+                                    PROP_Z_ADJUSTMENT,
+                                    "zadjustment");
 }
 
 static void
@@ -647,20 +843,23 @@ gtk_clutter_viewport_init (GtkClutterViewport *viewport)
  * gtk_clutter_viewport_new:
  * @h_adjust: horizontal adjustment, or %NULL
  * @v_adjust: vertical adjustment, or %NULL
+ * @z_adjust: zoom adjustment, or %NULL
  *
  * Creates a new #GtkClutterViewport with the given adjustments.
  *
  * Return value: the newly created viewport actor
  *
- * Since: 1.0
+ * Since: 0.10
  */
 ClutterActor *
 gtk_clutter_viewport_new (GtkAdjustment *h_adjust,
-                          GtkAdjustment *v_adjust)
+                          GtkAdjustment *v_adjust,
+                          GtkAdjustment *z_adjust)
 {
-  return g_object_new (GTK_TYPE_CLUTTER_VIEWPORT,
+  return g_object_new (GTK_CLUTTER_TYPE_VIEWPORT,
                        "hadjustment", h_adjust,
                        "vadjustment", v_adjust,
+                       "zadjustment", z_adjust,
                        NULL);
 }
 
@@ -674,48 +873,26 @@ gtk_clutter_viewport_new (GtkAdjustment *h_adjust,
  * Retrieves the current translation factor ("origin") used when
  * displaying the child of @viewport.
  *
- * Since: 1.0.
+ * Since: 0.10
  */
 void
 gtk_clutter_viewport_get_origin (GtkClutterViewport *viewport,
-                                 gint               *x,
-                                 gint               *y,
-                                 gint               *z)
+                                 gfloat             *x,
+                                 gfloat             *y,
+                                 gfloat             *z)
 {
   GtkClutterViewportPrivate *priv;
 
-  g_return_if_fail (GTK_IS_CLUTTER_VIEWPORT (viewport));
+  g_return_if_fail (GTK_CLUTTER_IS_VIEWPORT (viewport));
 
   priv = viewport->priv;
 
   if (x)
-    *x = CLUTTER_UNITS_TO_DEVICE (priv->origin.x);
+    *x = priv->origin.x;
 
   if (y)
-    *y = CLUTTER_UNITS_TO_DEVICE (priv->origin.y);
+    *y = priv->origin.y;
 
   if (z)
-    *z = CLUTTER_UNITS_TO_DEVICE (priv->origin.z);
-}
-
-/**
- * gtk_clutter_viewport_get_originu:
- * @viewport: a #GtkClutterViewport
- * @origin: a #ClutterVertex
- *
- * Retrieves the current translation factor ("origin") used
- * when displaying the child of @viewport.
- *
- * This function is the units-based version of
- * gtk_clutter_viewport_get_origin().
- *
- * Since: 1.0
- */
-void
-gtk_clutter_viewport_get_originu (GtkClutterViewport *viewport,
-                                  ClutterVertex      *origin)
-{
-  g_return_if_fail (GTK_IS_CLUTTER_VIEWPORT (viewport));
-
-  *origin = viewport->priv->origin;
+    *z = priv->origin.z;
 }