[libchamplain] Replace tidy with mx



commit dcd152746c36e1be8141cb30231d406b280bae63
Author: JiÅ?í Techet <techet gmail com>
Date:   Sun Jan 23 11:01:12 2011 +0100

    Replace tidy with mx
    
    Replace the outdated tidy library with its successor - mx. This will
    help us to use fixes and updates from the mainline.

 .gitignore                                         |   12 +-
 Makefile.am                                        |    2 +-
 champlain/Makefile.am                              |    6 +-
 champlain/champlain-layer.c                        |    2 +-
 champlain/champlain-view.c                         |   61 +-
 configure.ac                                       |    2 +-
 mx/Makefile.am                                     |   66 ++
 mx/mx-adjustment.c                                 | 1233 ++++++++++++++++++++
 mx/mx-adjustment.h                                 |  149 +++
 mx/mx-bin.c                                        |  715 ++++++++++++
 mx/mx-bin.h                                        |   99 ++
 mx/mx-draggable.c                                  |  706 +++++++++++
 mx/mx-draggable.h                                  |  132 +++
 tidy/tidy-enum-types.c.in => mx/mx-enum-types.c.in |    2 +-
 tidy/tidy-enum-types.h.in => mx/mx-enum-types.h.in |    8 +-
 mx/mx-kinetic-scroll-view.c                        | 1195 +++++++++++++++++++
 mx/mx-kinetic-scroll-view.h                        |   92 ++
 mx/mx-marshal.list                                 |    8 +
 tidy/tidy-private.h => mx/mx-private.h             |   14 +-
 mx/mx-scrollable.c                                 |   99 ++
 mx/mx-scrollable.h                                 |   71 ++
 mx/mx-types.h                                      |   80 ++
 mx/mx-viewport.c                                   |  678 +++++++++++
 mx/mx-viewport.h                                   |   91 ++
 tidy/Makefile.am                                   |   63 -
 tidy/tidy-adjustment.c                             |  643 ----------
 tidy/tidy-adjustment.h                             |  119 --
 tidy/tidy-debug.h                                  |    4 -
 tidy/tidy-finger-scroll.c                          |  695 -----------
 tidy/tidy-finger-scroll.h                          |   75 --
 tidy/tidy-marshal.list                             |    6 -
 tidy/tidy-scroll-view.c                            |  339 ------
 tidy/tidy-scroll-view.h                            |   65 -
 tidy/tidy-scrollable.c                             |   87 --
 tidy/tidy-scrollable.h                             |   63 -
 tidy/tidy-viewport.c                               |  596 ----------
 tidy/tidy-viewport.h                               |   72 --
 37 files changed, 5472 insertions(+), 2878 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index f292cda..ac7cd39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,12 +86,12 @@ libtool
 ltmain.sh
 missing
 stamp-h1
-tidy/tidy-enum-types.c
-tidy/tidy-enum-types.h
-tidy/stamp-enum-types
-tidy/tidy-marshal.c
-tidy/tidy-marshal.h
-tidy/stamp-marshal
+mx/mx-enum-types.c
+mx/mx-enum-types.h
+mx/stamp-enum-types
+mx/mx-marshal.c
+mx/mx-marshal.h
+mx/stamp-marshal
 bindings/python/update-binding.sh
 bindings/python/champlain-gtk/pychamplaingtk.c
 bindings/python/champlain/pychamplain.c
diff --git a/Makefile.am b/Makefile.am
index 6b9c72f..bd3492e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = build tidy champlain
+SUBDIRS = build mx champlain
 
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 
diff --git a/champlain/Makefile.am b/champlain/Makefile.am
index 442bbd2..e82c64a 100644
--- a/champlain/Makefile.am
+++ b/champlain/Makefile.am
@@ -111,7 +111,7 @@ nodist_libchamplain_ CHAMPLAIN_API_VERSION@_la_SOURCES = \
 	$(libchamplain_headers_built)	\
 	$(libchamplain_sources_built)
 
-libchamplain_ CHAMPLAIN_API_VERSION@_la_LIBADD = $(DEPS_LIBS) $(SOUP_LIBS) $(MEMPHIS_LIBS) $(top_builddir)/tidy/libtidy-1.0.la
+libchamplain_ CHAMPLAIN_API_VERSION@_la_LIBADD = $(DEPS_LIBS) $(SOUP_LIBS) $(MEMPHIS_LIBS) $(top_builddir)/mx/libchamplainmx-1.0.la
 
 libchamplain_ CHAMPLAIN_API_VERSION@_la_LDFLAGS = \
 	-version-info $(LIBRARY_VERSION)\
@@ -123,7 +123,7 @@ AM_CPPFLAGS = 				\
 	$(SOUP_CFLAGS)			\
 	$(MEMPHIS_CFLAGS)		\
 	-DDATADIR=\""$(datadir)"\"	\
-	-I$(top_srcdir)/tidy		\
+	-I$(top_srcdir)/mx		\
 	-I$(top_srcdir)			\
 	-DCHAMPLAIN_COMPILATION 	\
 	$(WARN_CFLAGS)
@@ -160,7 +160,7 @@ Champlain_ CHAMPLAIN_API_VERSION_NORM@_gir_FILES = $(introspection_sources)
 Champlain_ CHAMPLAIN_API_VERSION_NORM@_gir_INCLUDES = Clutter-1.0 Gtk-3.0 $(memphis_gir_include)
 Champlain_ CHAMPLAIN_API_VERSION_NORM@_gir_CFLAGS = \
 	$(DEPS_CFLAGS) $(SOUP_CFLAGS) $(MEMPHIS_CFLAGS) \
-	-I$(top_srcdir)/tidy -I$(top_srcdir) -I$(top_builddir) \
+	-I$(top_srcdir)/mx -I$(top_srcdir) -I$(top_builddir) \
 	-DCHAMPLAIN_COMPILATION
 
 INTROSPECTION_GIRS += Champlain- CHAMPLAIN_API_VERSION@.gir
diff --git a/champlain/champlain-layer.c b/champlain/champlain-layer.c
index 3e3e3a0..c966136 100644
--- a/champlain/champlain-layer.c
+++ b/champlain/champlain-layer.c
@@ -657,7 +657,7 @@ button_release_cb (G_GNUC_UNUSED ClutterActor *actor,
     ChamplainLayer *layer)
 {
   gboolean found = FALSE;
-printf("FOOOOOO\n");
+  
   if (clutter_event_get_button (event) != 1)
     return FALSE;
 
diff --git a/champlain/champlain-view.c b/champlain/champlain-view.c
index 6979e8e..275af73 100644
--- a/champlain/champlain-view.c
+++ b/champlain/champlain-view.c
@@ -67,10 +67,10 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <math.h>
-#include <tidy-adjustment.h>
-#include <tidy-finger-scroll.h>
-#include <tidy-scrollable.h>
-#include <tidy-viewport.h>
+#include <mx-kinetic-scroll-view.h>
+#include <mx-viewport.h>
+#include <mx-adjustment.h>
+#include <mx-scrollable.h>
 
 //#define VIEW_LOG 
 #ifdef VIEW_LOG
@@ -176,6 +176,7 @@ struct _ChamplainViewPrivate
   ClutterActor *viewport;  /* Contains the map_layer, license and markers */
   ClutterActor *map_layer; /* Contains tiles actors (grouped by zoom level) */
   ChamplainRectangle viewport_size;
+  ClutterActor *viewport_container;
 
   ClutterActor *user_layers; /* Contains the markers */
 
@@ -280,7 +281,7 @@ update_viewport (ChamplainView *view,
   if (relocate || force)
     {
       g_signal_handlers_block_by_func (priv->viewport, G_CALLBACK (viewport_pos_changed_cb), view);
-      tidy_viewport_set_origin (TIDY_VIEWPORT (priv->viewport),
+      mx_viewport_set_origin (MX_VIEWPORT (priv->viewport),
           priv->viewport_size.x,
           priv->viewport_size.y,
           0);
@@ -305,7 +306,7 @@ update_viewport (ChamplainView *view,
 
 
 static void
-panning_completed (G_GNUC_UNUSED TidyFingerScroll *scroll,
+panning_completed (G_GNUC_UNUSED MxKineticScrollView *scroll,
     ChamplainView *view)
 {
   DEBUG_LOG ()
@@ -314,7 +315,7 @@ panning_completed (G_GNUC_UNUSED TidyFingerScroll *scroll,
   ChamplainFloatPoint absolute;
   gfloat x, y;
 
-  tidy_viewport_get_origin (TIDY_VIEWPORT (priv->viewport), &x, &y, NULL);
+  mx_viewport_get_origin (MX_VIEWPORT (priv->viewport), &x, &y, NULL);
 
   absolute.x = x + priv->anchor.x + priv->viewport_size.width / 2.0;
   absolute.y = y + priv->anchor.y + priv->viewport_size.height / 2.0;
@@ -393,11 +394,11 @@ resize_viewport (ChamplainView *view)
   gdouble lower_y = 0;
   gdouble upper_x = G_MAXINT16;
   gdouble upper_y = G_MAXINT16;
-  TidyAdjustment *hadjust, *vadjust;
+  MxAdjustment *hadjust, *vadjust;
 
   ChamplainViewPrivate *priv = view->priv;
 
-  tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (priv->viewport), &hadjust,
+  mx_scrollable_get_adjustments (MX_SCROLLABLE (priv->viewport), &hadjust,
       &vadjust);
 
   if (priv->zoom_level < 8)
@@ -414,7 +415,7 @@ resize_viewport (ChamplainView *view)
 
   /*
    * block emmision of signal by priv->viewport with viewport_pos_changed_cb()
-   * callback - the signal can be emitted by updating TidyAdjustment, but
+   * callback - the signal can be emitted by updating MxAdjustment, but
    * calling the callback now would be a disaster since we don't have updated
    * anchor yet
    */
@@ -488,7 +489,7 @@ champlain_view_get_property (GObject *object,
     case PROP_DECEL_RATE:
       {
         gdouble decel = 0.0;
-        g_object_get (priv->finger_scroll, "decel-rate", &decel, NULL);
+        g_object_get (priv->finger_scroll, "deceleration", &decel, NULL);
         g_value_set_double (value, decel);
         break;
       }
@@ -640,14 +641,14 @@ champlain_view_dispose (GObject *object)
 
   if (priv->finger_scroll != NULL)
     {
-      tidy_finger_scroll_stop (TIDY_FINGER_SCROLL (priv->finger_scroll));
+      mx_kinetic_scroll_view_stop (MX_KINETIC_SCROLL_VIEW (priv->finger_scroll));
       g_object_unref (priv->finger_scroll);
       priv->finger_scroll = NULL;
     }
 
   if (priv->viewport != NULL)
     {
-      tidy_viewport_stop (TIDY_VIEWPORT (priv->viewport));
+//      mx_viewport_stop (MX_VIEWPORT (priv->viewport));
       g_object_unref (priv->viewport);
       priv->viewport = NULL;
     }
@@ -1385,8 +1386,21 @@ champlain_view_init (ChamplainView *view)
   priv->user_layers = g_object_ref (clutter_group_new ());
   clutter_actor_show (priv->user_layers);
 
+  priv->viewport_container = g_object_ref (clutter_group_new ());
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->viewport_container),
+      priv->map_layer);
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->viewport_container),
+      priv->polygon_layer);
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->viewport_container),
+      priv->user_layers);
+
+  clutter_actor_show (priv->viewport_container);
+
   /* Setup viewport */
-  priv->viewport = g_object_ref (tidy_viewport_new ());
+  priv->viewport = g_object_ref (mx_viewport_new ());
+  mx_bin_set_child (MX_BIN (priv->viewport), priv->viewport_container);
+  
   g_object_set (G_OBJECT (priv->viewport), "sync-adjustments", FALSE, NULL);
 
   g_signal_connect (priv->viewport, "notify::x-origin",
@@ -1394,18 +1408,11 @@ champlain_view_init (ChamplainView *view)
   g_signal_connect (priv->viewport, "notify::y-origin",
       G_CALLBACK (viewport_pos_changed_cb), view);
 
-  clutter_container_add_actor (CLUTTER_CONTAINER (priv->viewport),
-      priv->map_layer);
-  clutter_container_add_actor (CLUTTER_CONTAINER (priv->viewport),
-      priv->polygon_layer);
-  clutter_container_add_actor (CLUTTER_CONTAINER (priv->viewport),
-      priv->user_layers);
-
   clutter_actor_raise (priv->polygon_layer, priv->map_layer);
   clutter_actor_raise (priv->user_layers, priv->map_layer);
 
   /* Setup finger scroll */
-  priv->finger_scroll = g_object_ref (tidy_finger_scroll_new (priv->scroll_mode));
+  priv->finger_scroll = g_object_ref (mx_kinetic_scroll_view_new ());
 
   g_signal_connect (priv->finger_scroll, "scroll-event",
       G_CALLBACK (scroll_event), view);
@@ -1455,7 +1462,7 @@ viewport_pos_changed_cb (G_GNUC_UNUSED GObject *gobject,
   ChamplainViewPrivate *priv = view->priv;
   gfloat x, y;
 
-  tidy_viewport_get_origin (TIDY_VIEWPORT (priv->viewport), &x, &y, NULL);
+  mx_viewport_get_origin (MX_VIEWPORT (priv->viewport), &x, &y, NULL);
 
   if (fabs (x - priv->viewport_size.x) > 100 ||
       fabs (y - priv->viewport_size.y) > 100 ||
@@ -2624,7 +2631,7 @@ champlain_view_set_decel_rate (ChamplainView *view,
   g_return_if_fail (CHAMPLAIN_IS_VIEW (view) &&
       rate < 2.0 && rate > 1.0001);
 
-  g_object_set (view->priv->finger_scroll, "decel-rate", rate, NULL);
+  g_object_set (view->priv->finger_scroll, "deceleration", rate, NULL);
 }
 
 
@@ -2649,8 +2656,8 @@ champlain_view_set_scroll_mode (ChamplainView *view,
 
   priv->scroll_mode = mode;
 
-  g_object_set (G_OBJECT (priv->finger_scroll), "mode",
-      priv->scroll_mode, NULL);
+//  g_object_set (G_OBJECT (priv->finger_scroll), "mode",
+//      priv->scroll_mode, NULL);
 }
 
 
@@ -3062,7 +3069,7 @@ champlain_view_get_decel_rate (ChamplainView *view)
   g_return_val_if_fail (CHAMPLAIN_IS_VIEW (view), 0.0);
 
   gdouble decel = 0.0;
-  g_object_get (view->priv->finger_scroll, "decel-rate", &decel, NULL);
+  g_object_get (view->priv->finger_scroll, "deceleration", &decel, NULL);
   return decel;
 }
 
diff --git a/configure.ac b/configure.ac
index ca1ea75..d4331c6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -214,7 +214,7 @@ AC_CONFIG_FILES([build/Makefile
                  champlain/Makefile
                  champlain/champlain-version.h
                  demos/Makefile
-                 tidy/Makefile
+                 mx/Makefile
                  docs/Makefile
                  docs/reference/Makefile
                  docs/reference/version.xml
diff --git a/mx/Makefile.am b/mx/Makefile.am
new file mode 100644
index 0000000..1e02d40
--- /dev/null
+++ b/mx/Makefile.am
@@ -0,0 +1,66 @@
+BUILT_SOURCES =
+CLEANFILES =
+DISTCLEANFILES =
+EXTRA_DIST =
+
+
+mx_headers_public = \
+	$(srcdir)/mx-draggable.h		\
+	$(srcdir)/mx-viewport.h		\
+	$(srcdir)/mx-kinetic-scroll-view.h		\
+	$(srcdir)/mx-types.h		\
+	$(srcdir)/mx-adjustment.h		\
+	$(srcdir)/mx-bin.h		\
+	$(srcdir)/mx-scrollable.h		\
+	$(srcdir)/mx-private.h
+
+mx_sources = \
+	$(srcdir)/mx-draggable.c		\
+	$(srcdir)/mx-viewport.c		\
+	$(srcdir)/mx-kinetic-scroll-view.c		\
+	$(srcdir)/mx-adjustment.c		\
+	$(srcdir)/mx-bin.c		\
+	$(srcdir)/mx-scrollable.c
+
+
+# glib-genmarshal rules
+glib_marshal_list = mx-marshal.list
+glib_marshal_prefix = _mx_marshal
+include $(top_srcdir)/build/Makefile.am.marshal
+
+# glib-mkenums rules
+glib_enum_h = mx-enum-types.h
+glib_enum_c = mx-enum-types.c
+glib_enum_headers = $(mx_headers_public)
+include $(top_srcdir)/build/Makefile.am.enums
+
+mx_headers_built = 	\
+	mx-enum-types.h	\
+	mx-marshal.h
+
+mx_sources_built = 	\
+	mx-enum-types.c	\
+	mx-marshal.c
+
+
+libchamplainmx_1_0_la_SOURCES = \
+	$(mx_headers_public)	\
+	$(mx_sources)
+
+nodist_libchamplainmx_1_0_la_SOURCES = \
+	$(mx_headers_built)	\
+	$(mx_sources_built)
+
+libchamplainmx_1_0_la_LIBADD = $(DEPS_LIBS)
+
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	-DPREFIX=\""$(prefix)"\" 	\
+	-DLIBDIR=\""$(libdir)"\" 	\
+	-DG_DISABLE_DEPRECATED 		\
+	-DG_LOG_DOMAIN=\"Mx\" 	\
+	$(DEPS_CFLAGS) 			\
+	$(MX_DEBUG_CFLAGS)	\
+	$(WARN_CFLAGS)
+
+noinst_LTLIBRARIES = libchamplainmx-1.0.la
diff --git a/mx/mx-adjustment.c b/mx/mx-adjustment.c
new file mode 100644
index 0000000..2718d60
--- /dev/null
+++ b/mx/mx-adjustment.c
@@ -0,0 +1,1233 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-adjustment.c: Adjustment object
+ *
+ * Copyright (C) 2008 OpenedHand
+ * Copyright (c) 2009, 2010 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Chris Lord <chris openedhand com>, inspired by GtkAdjustment
+ * Port to Mx by: Robert Staudinger <robsta openedhand com>
+ *
+ */
+
+/**
+ * SECTION:mx-adjustment
+ * @short_description: A GObject representing an adjustable bounded value
+ *
+ * The #MxAdjustment object represents a range of values bounded between a
+ * minimum and maximum, together with step and page increments and a page size.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+#include "mx-adjustment.h"
+#include "mx-marshal.h"
+#include "mx-private.h"
+
+G_DEFINE_TYPE (MxAdjustment, mx_adjustment, G_TYPE_OBJECT)
+
+#define ADJUSTMENT_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MX_TYPE_ADJUSTMENT, MxAdjustmentPrivate))
+
+struct _MxAdjustmentPrivate
+{
+  /* Do not sanity-check values while constructing,
+   * not all properties may be set yet. */
+  guint is_constructing : 1;
+  guint clamp_value     : 1;
+  guint elastic         : 1;
+
+  gdouble  lower;
+  gdouble  upper;
+  gdouble  value;
+  gdouble  step_increment;
+  gdouble  page_increment;
+  gdouble  page_size;
+
+  /* For signal emission/notification */
+  guint lower_source;
+  guint upper_source;
+  guint value_source;
+  guint step_inc_source;
+  guint page_inc_source;
+  guint page_size_source;
+  guint changed_source;
+
+  /* For interpolation */
+  ClutterTimeline *interpolation;
+  gdouble          old_position;
+  gdouble          new_position;
+  ClutterAlpha    *interpolate_alpha;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_LOWER,
+  PROP_UPPER,
+  PROP_VALUE,
+  PROP_STEP_INC,
+  PROP_PAGE_INC,
+  PROP_PAGE_SIZE,
+
+  PROP_ELASTIC,
+  PROP_CLAMP_VALUE,
+};
+
+enum
+{
+  CHANGED,
+
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static gboolean _mx_adjustment_set_lower          (MxAdjustment *adjustment,
+                                                   gdouble       lower);
+static gboolean _mx_adjustment_set_upper          (MxAdjustment *adjustment,
+                                                   gdouble       upper);
+static gboolean _mx_adjustment_set_step_increment (MxAdjustment *adjustment,
+                                                   gdouble       step);
+static gboolean _mx_adjustment_set_page_increment (MxAdjustment *adjustment,
+                                                   gdouble       page);
+static gboolean _mx_adjustment_set_page_size      (MxAdjustment *adjustment,
+                                                   gdouble       size);
+static void mx_adjustment_clamp_page (MxAdjustment *adjustment,
+                                      gdouble       lower,
+                                      gdouble       upper);
+
+static void
+mx_adjustment_constructed (GObject *object)
+{
+  GObjectClass *g_class;
+  MxAdjustment *self = MX_ADJUSTMENT (object);
+
+  g_class = G_OBJECT_CLASS (mx_adjustment_parent_class);
+  /* The docs say we're suppose to chain up, but would crash without
+   * some extra care. */
+  if (g_class && g_class->constructed &&
+      g_class->constructed != mx_adjustment_constructed)
+    {
+      g_class->constructed (object);
+    }
+
+  MX_ADJUSTMENT (self)->priv->is_constructing = FALSE;
+  mx_adjustment_clamp_page (self, self->priv->lower, self->priv->upper);
+}
+
+static void
+mx_adjustment_get_property (GObject    *gobject,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  MxAdjustmentPrivate *priv = MX_ADJUSTMENT (gobject)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_LOWER:
+      g_value_set_double (value, priv->lower);
+      break;
+
+    case PROP_UPPER:
+      g_value_set_double (value, priv->upper);
+      break;
+
+    case PROP_VALUE:
+      g_value_set_double (value, priv->value);
+      break;
+
+    case PROP_STEP_INC:
+      g_value_set_double (value, priv->step_increment);
+      break;
+
+    case PROP_PAGE_INC:
+      g_value_set_double (value, priv->page_increment);
+      break;
+
+    case PROP_PAGE_SIZE:
+      g_value_set_double (value, priv->page_size);
+      break;
+
+    case PROP_ELASTIC:
+      g_value_set_boolean (value, priv->elastic);
+      break;
+
+    case PROP_CLAMP_VALUE:
+      g_value_set_boolean (value, priv->clamp_value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+mx_adjustment_set_property (GObject      *gobject,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  MxAdjustment *adj = MX_ADJUSTMENT (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_LOWER:
+      mx_adjustment_set_lower (adj, g_value_get_double (value));
+      break;
+
+    case PROP_UPPER:
+      mx_adjustment_set_upper (adj, g_value_get_double (value));
+      break;
+
+    case PROP_VALUE:
+      mx_adjustment_set_value (adj, g_value_get_double (value));
+      break;
+
+    case PROP_STEP_INC:
+      mx_adjustment_set_step_increment (adj, g_value_get_double (value));
+      break;
+
+    case PROP_PAGE_INC:
+      mx_adjustment_set_page_increment (adj, g_value_get_double (value));
+      break;
+
+    case PROP_PAGE_SIZE:
+      mx_adjustment_set_page_size (adj, g_value_get_double (value));
+      break;
+
+    case PROP_ELASTIC:
+      mx_adjustment_set_elastic (adj, g_value_get_boolean (value));
+      break;
+
+    case PROP_CLAMP_VALUE:
+      mx_adjustment_set_clamp_value (adj, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+stop_interpolation (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->interpolation)
+    {
+      clutter_timeline_stop (priv->interpolation);
+      g_object_unref (priv->interpolation);
+      priv->interpolation = NULL;
+    }
+}
+
+static void
+mx_adjustment_remove_idle (guint *source)
+{
+  if (*source)
+    {
+      g_source_remove (*source);
+      *source = 0;
+    }
+}
+
+static void
+mx_adjustment_dispose (GObject *object)
+{
+  MxAdjustmentPrivate *priv = MX_ADJUSTMENT (object)->priv;
+
+  stop_interpolation (MX_ADJUSTMENT (object));
+
+  /* Remove idle handlers */
+  mx_adjustment_remove_idle (&priv->value_source);
+  mx_adjustment_remove_idle (&priv->lower_source);
+  mx_adjustment_remove_idle (&priv->upper_source);
+  mx_adjustment_remove_idle (&priv->page_inc_source);
+  mx_adjustment_remove_idle (&priv->step_inc_source);
+  mx_adjustment_remove_idle (&priv->page_size_source);
+  mx_adjustment_remove_idle (&priv->changed_source);
+
+  if (priv->interpolate_alpha)
+    {
+      g_object_unref (priv->interpolate_alpha);
+      priv->interpolate_alpha = NULL;
+    }
+
+  G_OBJECT_CLASS (mx_adjustment_parent_class)->dispose (object);
+}
+
+static void
+mx_adjustment_class_init (MxAdjustmentClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (MxAdjustmentPrivate));
+
+  object_class->constructed = mx_adjustment_constructed;
+  object_class->get_property = mx_adjustment_get_property;
+  object_class->set_property = mx_adjustment_set_property;
+  object_class->dispose = mx_adjustment_dispose;
+
+  g_object_class_install_property (object_class,
+                                   PROP_LOWER,
+                                   g_param_spec_double ("lower",
+                                                        "Lower",
+                                                        "Lower bound",
+                                                        -G_MAXDOUBLE,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        MX_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+  g_object_class_install_property (object_class,
+                                   PROP_UPPER,
+                                   g_param_spec_double ("upper",
+                                                        "Upper",
+                                                        "Upper bound",
+                                                        -G_MAXDOUBLE,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        MX_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+  g_object_class_install_property (object_class,
+                                   PROP_VALUE,
+                                   g_param_spec_double ("value",
+                                                        "Value",
+                                                        "Current value",
+                                                        -G_MAXDOUBLE,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        MX_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+  g_object_class_install_property (object_class,
+                                   PROP_STEP_INC,
+                                   g_param_spec_double ("step-increment",
+                                                        "Step Increment",
+                                                        "Step increment",
+                                                        0.0,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        MX_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+  g_object_class_install_property (object_class,
+                                   PROP_PAGE_INC,
+                                   g_param_spec_double ("page-increment",
+                                                        "Page Increment",
+                                                        "Page increment",
+                                                        0.0,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        MX_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+  g_object_class_install_property (object_class,
+                                   PROP_PAGE_SIZE,
+                                   g_param_spec_double ("page-size",
+                                                        "Page Size",
+                                                        "Page size",
+                                                        0.0,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        MX_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+  g_object_class_install_property (object_class,
+                                   PROP_ELASTIC,
+                                   g_param_spec_boolean ("elastic",
+                                                         "Elastic",
+                                                         "Make interpolation "
+                                                         "behave in an "
+                                                         "'elastic' way and "
+                                                         "stop clamping value.",
+                                                         FALSE,
+                                                         MX_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_CLAMP_VALUE,
+                                   g_param_spec_boolean ("clamp-value",
+                                                         "Clamp value",
+                                                         "Clamp the adjustment "
+                                                         "value between the "
+                                                         "lower and upper "
+                                                         "values, respecting "
+                                                         "the page-size.",
+                                                         TRUE,
+                                                         MX_PARAM_READWRITE));
+
+  /**
+   * MxAdjustment::changed:
+   *
+   * Emitted when any of the adjustment values have changed
+   */
+  signals[CHANGED] =
+    g_signal_new ("changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (MxAdjustmentClass, changed),
+                  NULL, NULL,
+                  _mx_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+static void
+mx_adjustment_init (MxAdjustment *self)
+{
+  self->priv = ADJUSTMENT_PRIVATE (self);
+
+  self->priv->is_constructing = TRUE;
+  self->priv->clamp_value = TRUE;
+}
+
+/**
+ * mx_adjustment_new:
+ *
+ * Create a new MxAdjustment
+ *
+ * Returns: a newly allocated MxAdjustment
+ */
+MxAdjustment *
+mx_adjustment_new (void)
+{
+  return g_object_new (MX_TYPE_ADJUSTMENT, NULL);
+}
+
+/**
+ * mx_adjustment_new_with_values:
+ * @value: A #gdouble
+ * @lower: A #gdouble
+ * @upper: A #gdouble
+ * @step_increment: A #gdouble
+ * @page_increment: A #gdouble
+ * @page_size: A #gdouble
+ *
+ * Create a new MxAdjustment with the properties set to the values specified.
+ *
+ * Returns: a newly allocated MxAdjustment
+ */
+MxAdjustment *
+mx_adjustment_new_with_values (gdouble value,
+                               gdouble lower,
+                               gdouble upper,
+                               gdouble step_increment,
+                               gdouble page_increment,
+                               gdouble page_size)
+{
+  return g_object_new (MX_TYPE_ADJUSTMENT,
+                       "value", value,
+                       "lower", lower,
+                       "upper", upper,
+                       "step-increment", step_increment,
+                       "page-increment", page_increment,
+                       "page-size", page_size,
+                       NULL);
+}
+
+/**
+ * mx_adjustment_get_value:
+ * @adjustment: An #MxAdjustment
+ *
+ * Get the current value of the #MxAdjustment:value property
+ *
+ * Returns: the current value of the "value" property
+ */
+gdouble
+mx_adjustment_get_value (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv;
+
+  g_return_val_if_fail (MX_IS_ADJUSTMENT (adjustment), 0);
+
+  priv = adjustment->priv;
+
+  return priv->value;
+}
+
+static gboolean
+mx_adjustment_value_notify_cb (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->value_source = 0;
+
+  g_object_notify (G_OBJECT (adjustment), "value");
+
+  return FALSE;
+}
+
+static gboolean
+mx_adjustment_lower_notify_cb (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->lower_source = 0;
+  g_object_notify (G_OBJECT (adjustment), "lower");
+
+  return FALSE;
+}
+
+static gboolean
+mx_adjustment_upper_notify_cb (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->upper_source = 0;
+  g_object_notify (G_OBJECT (adjustment), "upper");
+
+  return FALSE;
+}
+
+static gboolean
+mx_adjustment_step_inc_notify_cb (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->step_inc_source = 0;
+  g_object_notify (G_OBJECT (adjustment), "step-increment");
+
+  return FALSE;
+}
+
+static gboolean
+mx_adjustment_page_inc_notify_cb (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->page_inc_source = 0;
+  g_object_notify (G_OBJECT (adjustment), "page-increment");
+
+  return FALSE;
+}
+
+static gboolean
+mx_adjustment_page_size_notify_cb (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->page_size_source = 0;
+  g_object_notify (G_OBJECT (adjustment), "page-size");
+
+  return FALSE;
+}
+
+static gboolean
+mx_adjustment_emit_changed_cb (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->changed_source = 0;
+  g_signal_emit (adjustment, signals[CHANGED], 0);
+
+  return FALSE;
+}
+
+/**
+ * mx_adjustment_set_value:
+ * @adjustment: An #MxAdjustment
+ * @value: A #gdouble
+ *
+ * Set the value of the #MxAdjustment:value property.
+ *
+ */
+void
+mx_adjustment_set_value (MxAdjustment *adjustment,
+                         gdouble       value)
+{
+  MxAdjustmentPrivate *priv;
+
+  g_return_if_fail (MX_IS_ADJUSTMENT (adjustment));
+
+  priv = adjustment->priv;
+
+  /* Defer clamp until after construction. */
+  if (!priv->is_constructing)
+    {
+      if (!priv->elastic && priv->clamp_value)
+        value = CLAMP (value,
+                       priv->lower,
+                       MAX (priv->lower, priv->upper - priv->page_size));
+    }
+
+  if (priv->value != value)
+    {
+      stop_interpolation (adjustment);
+
+      priv->value = value;
+
+      g_object_notify (G_OBJECT (adjustment), "value");
+    }
+}
+
+static void
+mx_adjustment_clamp_page (MxAdjustment *adjustment,
+                          gdouble       lower,
+                          gdouble       upper)
+{
+  MxAdjustmentPrivate *priv;
+  gboolean changed;
+
+  g_return_if_fail (MX_IS_ADJUSTMENT (adjustment));
+
+  priv = adjustment->priv;
+
+  lower = CLAMP (lower, priv->lower, priv->upper - priv->page_size);
+  upper = CLAMP (upper, priv->lower + priv->page_size, priv->upper);
+
+  changed = FALSE;
+
+  if (priv->value + priv->page_size > upper)
+    {
+      priv->value = upper - priv->page_size;
+      changed = TRUE;
+    }
+
+  if (priv->value < lower)
+    {
+      priv->value = lower;
+      changed = TRUE;
+    }
+
+  if (changed && !priv->value_source)
+    priv->value_source =
+      g_idle_add_full (CLUTTER_PRIORITY_REDRAW,
+                       (GSourceFunc)mx_adjustment_value_notify_cb,
+                       adjustment,
+                       NULL);
+}
+
+static void
+mx_adjustment_emit_changed (MxAdjustment *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (!priv->changed_source)
+    priv->changed_source =
+      g_idle_add_full (CLUTTER_PRIORITY_REDRAW,
+                       (GSourceFunc)mx_adjustment_emit_changed_cb,
+                       adjustment,
+                       NULL);
+}
+
+static gboolean
+_mx_adjustment_set_lower (MxAdjustment *adjustment,
+                          gdouble       lower)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->lower != lower)
+    {
+      priv->lower = lower;
+
+      mx_adjustment_emit_changed (adjustment);
+
+      if (!priv->lower_source)
+        priv->lower_source =
+          g_idle_add_full (CLUTTER_PRIORITY_REDRAW,
+                           (GSourceFunc)mx_adjustment_lower_notify_cb,
+                           adjustment,
+                           NULL);
+
+      /* Defer clamp until after construction. */
+      if (!priv->is_constructing && priv->clamp_value)
+        mx_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * mx_adjustment_set_lower:
+ * @adjustment: A #MxAdjustment
+ * @lower: A #gdouble
+ *
+ * Set the value of the #MxAdjustment:lower property.
+ *
+ */
+void
+mx_adjustment_set_lower (MxAdjustment *adjustment,
+                         gdouble       lower)
+{
+  _mx_adjustment_set_lower (adjustment, lower);
+}
+
+/**
+ * mx_adjustment_get_lower:
+ * @adjustment: A #MxAdjustment
+ *
+ * Get the value of the #MxAdjustment:lower property.
+ *
+ * Returns: the current value of the "lower" property.
+ */
+gdouble
+mx_adjustment_get_lower (MxAdjustment *adjustment)
+{
+  g_return_val_if_fail (MX_IS_ADJUSTMENT (adjustment), 0.0);
+  return adjustment->priv->lower;
+}
+
+static gboolean
+_mx_adjustment_set_upper (MxAdjustment *adjustment,
+                          gdouble       upper)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->upper != upper)
+    {
+      priv->upper = upper;
+
+      mx_adjustment_emit_changed (adjustment);
+
+      if (!priv->upper_source)
+        priv->upper_source =
+          g_idle_add_full (CLUTTER_PRIORITY_REDRAW,
+                           (GSourceFunc)mx_adjustment_upper_notify_cb,
+                           adjustment,
+                           NULL);
+
+      /* Defer clamp until after construction. */
+      if (!priv->is_constructing && priv->clamp_value)
+        mx_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * mx_adjustment_set_upper:
+ * @adjustment: A #MxAdjustment
+ * @upper: A #gdouble
+ *
+ * Set the value of the #MxAdjustment:upper property.
+ *
+ */
+void
+mx_adjustment_set_upper (MxAdjustment *adjustment,
+                         gdouble       upper)
+{
+  _mx_adjustment_set_upper (adjustment, upper);
+}
+
+/**
+ * mx_adjustment_get_upper:
+ * @adjustment: A #MxAdjustment
+ *
+ * Get the value of the #MxAdjustment:upper property.
+ *
+ * Returns: the current value of the "upper" property.
+ */
+gdouble
+mx_adjustment_get_upper (MxAdjustment *adjustment)
+{
+  g_return_val_if_fail (MX_IS_ADJUSTMENT (adjustment), 0.0);
+  return adjustment->priv->upper;
+}
+
+static gboolean
+_mx_adjustment_set_step_increment (MxAdjustment *adjustment,
+                                   gdouble       step)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->step_increment != step)
+    {
+      priv->step_increment = step;
+
+      mx_adjustment_emit_changed (adjustment);
+
+      if (!priv->step_inc_source)
+        priv->step_inc_source =
+          g_idle_add_full (CLUTTER_PRIORITY_REDRAW,
+                           (GSourceFunc)mx_adjustment_step_inc_notify_cb,
+                           adjustment,
+                           NULL);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * mx_adjustment_set_step_increment:
+ * @adjustment: A #MxAdjustment
+ * @increment: A #gdouble
+ *
+ * Set the value of the #MxAdjustment:step-increment property.
+ *
+ */
+void
+mx_adjustment_set_step_increment (MxAdjustment *adjustment,
+                                  gdouble       increment)
+{
+  _mx_adjustment_set_step_increment (adjustment, increment);
+}
+
+/**
+ * mx_adjustment_get_step_increment:
+ * @adjustment: A #MxAdjustment
+ *
+ * Get the value of the MxAdjustment:step-increment property.
+ *
+ * Returns: the current value of the "step-increment" property.
+ */
+gdouble
+mx_adjustment_get_step_increment (MxAdjustment *adjustment)
+{
+  g_return_val_if_fail (MX_IS_ADJUSTMENT (adjustment), 0.0);
+  return adjustment->priv->step_increment;
+}
+
+static gboolean
+_mx_adjustment_set_page_increment (MxAdjustment *adjustment,
+                                   gdouble       page)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->page_increment != page)
+    {
+      priv->page_increment = page;
+
+      mx_adjustment_emit_changed (adjustment);
+
+      if (!priv->page_inc_source)
+        priv->page_inc_source =
+          g_idle_add_full (CLUTTER_PRIORITY_REDRAW,
+                           (GSourceFunc)mx_adjustment_page_inc_notify_cb,
+                           adjustment,
+                           NULL);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * mx_adjustment_set_page_increment:
+ * @adjustment: A #MxAdjustment
+ * @increment: A #gdouble
+ *
+ * Set the value of the #MxAdjustment:page-increment property.
+ *
+ */
+void
+mx_adjustment_set_page_increment (MxAdjustment *adjustment,
+                                  gdouble       increment)
+{
+  _mx_adjustment_set_page_increment (adjustment, increment);
+}
+
+/**
+ * mx_adjustment_get_page_increment:
+ * @adjustment: A #MxAdjustment
+ *
+ * Get the value of the MxAdjustment:page-increment property.
+ *
+ * Returns: the current value of the "page-increment" property.
+ */
+gdouble
+mx_adjustment_get_page_increment (MxAdjustment *adjustment)
+{
+  g_return_val_if_fail (MX_IS_ADJUSTMENT (adjustment), 0.0);
+  return adjustment->priv->page_increment;
+}
+
+static gboolean
+_mx_adjustment_set_page_size (MxAdjustment *adjustment,
+                              gdouble       size)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->page_size != size)
+    {
+      priv->page_size = size;
+
+      mx_adjustment_emit_changed (adjustment);
+
+      if (!priv->page_size_source)
+        priv->page_size_source =
+          g_idle_add_full (CLUTTER_PRIORITY_REDRAW,
+                           (GSourceFunc)mx_adjustment_page_size_notify_cb,
+                           adjustment,
+                           NULL);
+
+      /* Well explicitely clamp after construction. */
+      if (!priv->is_constructing && priv->clamp_value)
+        mx_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * mx_adjustment_set_page_size:
+ * @adjustment: A #MxAdjustment
+ * @page_size: A #gdouble
+ *
+ * Set the #MxAdjustment:page-size property.
+ *
+ */
+void
+mx_adjustment_set_page_size (MxAdjustment *adjustment,
+                             gdouble       page_size)
+{
+  _mx_adjustment_set_page_size (adjustment, page_size);
+}
+
+/**
+ * mx_adjustment_get_page_size:
+ * @adjustment: A #MxAdjustment
+ *
+ * Get the value of the #MxAdjustment:page-size property.
+ *
+ * Returns: the current value of the "page-size" property.
+ */
+gdouble
+mx_adjustment_get_page_size (MxAdjustment *adjustment)
+{
+  g_return_val_if_fail (MX_IS_ADJUSTMENT (adjustment), 0.0);
+  return adjustment->priv->page_size;
+}
+
+/**
+ * mx_adjustment_set_values:
+ * @adjustment: A #MxAdjustment
+ * @value: A #gdouble
+ * @lower: A #gdouble
+ * @upper: A #gdouble
+ * @step_increment: A #gdouble
+ * @page_increment: A #gdouble
+ * @page_size: A #gdouble
+ *
+ * Set the various properties of MxAdjustment.
+ *
+ */
+void
+mx_adjustment_set_values (MxAdjustment *adjustment,
+                          gdouble       value,
+                          gdouble       lower,
+                          gdouble       upper,
+                          gdouble       step_increment,
+                          gdouble       page_increment,
+                          gdouble       page_size)
+{
+  MxAdjustmentPrivate *priv;
+  gboolean emit_changed = FALSE;
+
+  g_return_if_fail (MX_IS_ADJUSTMENT (adjustment));
+  g_return_if_fail (page_size >= 0 && page_size <= G_MAXDOUBLE);
+  g_return_if_fail (step_increment >= 0 && step_increment <= G_MAXDOUBLE);
+  g_return_if_fail (page_increment >= 0 && page_increment <= G_MAXDOUBLE);
+
+  priv = adjustment->priv;
+
+  emit_changed = FALSE;
+
+  g_object_freeze_notify (G_OBJECT (adjustment));
+
+  emit_changed |= _mx_adjustment_set_lower (adjustment, lower);
+  emit_changed |= _mx_adjustment_set_upper (adjustment, upper);
+  emit_changed |= _mx_adjustment_set_step_increment (adjustment,
+                                                     step_increment);
+  emit_changed |= _mx_adjustment_set_page_increment (adjustment,
+                                                     page_increment);
+  emit_changed |= _mx_adjustment_set_page_size (adjustment, page_size);
+
+  if (value != priv->value)
+    {
+      mx_adjustment_set_value (adjustment, value);
+      emit_changed = TRUE;
+    }
+
+  if (emit_changed)
+    mx_adjustment_emit_changed (adjustment);
+
+  g_object_thaw_notify (G_OBJECT (adjustment));
+}
+
+/**
+ * mx_adjustment_get_values:
+ * @adjustment: A #MxAdjustment
+ * @value: A #gdouble
+ * @lower: A #gdouble
+ * @upper: A #gdouble
+ * @step_increment: A #gdouble
+ * @page_increment: A #gdouble
+ * @page_size: A #gdouble
+ *
+ * Get the various properties of MxAdjustment.
+ *
+ */
+void
+mx_adjustment_get_values (MxAdjustment *adjustment,
+                          gdouble      *value,
+                          gdouble      *lower,
+                          gdouble      *upper,
+                          gdouble      *step_increment,
+                          gdouble      *page_increment,
+                          gdouble      *page_size)
+{
+  MxAdjustmentPrivate *priv;
+
+  g_return_if_fail (MX_IS_ADJUSTMENT (adjustment));
+
+  priv = adjustment->priv;
+
+  if (lower)
+    *lower = priv->lower;
+
+  if (upper)
+    *upper = priv->upper;
+
+  if (value)
+    *value = mx_adjustment_get_value (adjustment);
+
+  if (step_increment)
+    *step_increment = priv->step_increment;
+
+  if (page_increment)
+    *page_increment = priv->page_increment;
+
+  if (page_size)
+    *page_size = priv->page_size;
+}
+
+static void
+interpolation_new_frame_cb (ClutterTimeline *timeline,
+                            guint            msecs,
+                            MxAdjustment    *adjustment)
+{
+  gdouble new_value;
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->interpolation = NULL;
+
+  new_value = priv->old_position +
+              (priv->new_position - priv->old_position) *
+              clutter_alpha_get_alpha (priv->interpolate_alpha);
+
+  mx_adjustment_set_value (adjustment, new_value);
+  priv->interpolation = timeline;
+
+  /* Stop the interpolation if we've reached the end of the adjustment */
+  if (!priv->elastic && priv->clamp_value &&
+      ((new_value < priv->lower) ||
+       (new_value >= (priv->upper - priv->page_size))))
+    stop_interpolation (adjustment);
+}
+
+static void
+interpolation_completed_cb (ClutterTimeline *timeline,
+                            MxAdjustment    *adjustment)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->elastic && priv->clamp_value)
+    {
+      if (clutter_timeline_get_direction (priv->interpolation) ==
+            CLUTTER_TIMELINE_FORWARD)
+        {
+          clutter_timeline_set_direction (priv->interpolation,
+                                          CLUTTER_TIMELINE_BACKWARD);
+          clutter_timeline_set_duration (priv->interpolation, 250);
+          clutter_timeline_rewind (priv->interpolation);
+
+          if (priv->new_position < priv->lower)
+            {
+              priv->old_position = priv->lower;
+              clutter_timeline_start (priv->interpolation);
+            }
+          else if (priv->new_position > (priv->upper - priv->page_size))
+            {
+              priv->old_position = priv->upper - priv->page_size;
+              clutter_timeline_start (priv->interpolation);
+            }
+        }
+      else
+        {
+          stop_interpolation (adjustment);
+          mx_adjustment_set_value (adjustment, priv->old_position);
+        }
+    }
+  else
+    {
+      stop_interpolation (adjustment);
+      mx_adjustment_set_value (adjustment, priv->new_position);
+    }
+}
+
+/**
+ * mx_adjustment_interpolate:
+ * @adjustment: A #MxAdjustment
+ * @value: A #gdouble
+ * @duration: duration in milliseconds
+ * @mode: A #ClutterAnimationMode
+ *
+ * Interpolate #MxAdjustment:value to the new value specified by @value, using
+ * the mode and duration given.
+ */
+void
+mx_adjustment_interpolate (MxAdjustment *adjustment,
+                           gdouble       value,
+                           guint         duration,
+                           gulong        mode)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  g_return_if_fail (isfinite (value));
+
+  if (duration <= 1)
+    {
+      stop_interpolation (adjustment);
+      mx_adjustment_set_value (adjustment, value);
+      return;
+    }
+
+  priv->old_position = priv->value;
+  priv->new_position = value;
+
+  if (!priv->interpolation)
+    {
+      priv->interpolation = clutter_timeline_new (duration);
+
+      g_signal_connect (priv->interpolation,
+                        "new-frame",
+                        G_CALLBACK (interpolation_new_frame_cb),
+                        adjustment);
+      g_signal_connect (priv->interpolation,
+                        "completed",
+                        G_CALLBACK (interpolation_completed_cb),
+                        adjustment);
+    }
+  else
+    {
+      /* Extend the animation if it gets interrupted, otherwise frequent calls
+       * to this function will end up with no advancements until the calls
+       * finish (as the animation never gets a chance to start).
+       */
+      clutter_timeline_set_direction (priv->interpolation,
+                                      CLUTTER_TIMELINE_FORWARD);
+      clutter_timeline_rewind (priv->interpolation);
+      clutter_timeline_set_duration (priv->interpolation, duration);
+    }
+
+  if (priv->interpolate_alpha)
+    g_object_unref (priv->interpolate_alpha);
+
+  priv->interpolate_alpha = clutter_alpha_new_full (priv->interpolation,
+                                                    mode);
+
+  clutter_timeline_start (priv->interpolation);
+}
+
+/**
+ * mx_adjustment_interpolate_relative:
+ * @adjustment: A #MxAdjustment
+ * @offset: A #gdouble
+ * @duration: duration in milliseconds
+ * @mode: A #ClutterAnimationMode
+ *
+ * Interpolate the value of #MxAdjustment:value to a new value calculated from
+ * @offset.
+ *
+ */
+void
+mx_adjustment_interpolate_relative (MxAdjustment *adjustment,
+                                    gdouble       offset,
+                                    guint         duration,
+                                    gulong        mode)
+{
+  MxAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->interpolation)
+    offset += priv->new_position;
+  else
+    offset += priv->value;
+
+  mx_adjustment_interpolate (adjustment,
+                             offset,
+                             duration,
+                             mode);
+}
+
+/**
+ * mx_adjustment_get_elastic:
+ * @adjustment: A #MxAdjustment
+ *
+ * Get the value of the #MxAdjustment:elastic property.
+ *
+ * Returns: the current value of the "elastic" property.
+ */
+gboolean
+mx_adjustment_get_elastic (MxAdjustment *adjustment)
+{
+  return adjustment->priv->elastic;
+}
+
+/**
+ * mx_adjustment_set_elastic:
+ * @adjustment: A #MxAdjustment
+ * @elastic: A #gboolean
+ *
+ * Set the value of the #MxAdjustment:elastic property.
+ *
+ */
+void
+mx_adjustment_set_elastic (MxAdjustment *adjustment,
+                           gboolean      elastic)
+{
+  adjustment->priv->elastic = elastic;
+}
+
+/**
+ * mx_adjustment_get_clamp_value:
+ * @adjustment: A #MxAdjustment
+ *
+ * Get the value of the #MxAdjustment:clamp-value property.
+ *
+ * Returns: the current value of the "clamp-value" property.
+ */
+gboolean
+mx_adjustment_get_clamp_value (MxAdjustment *adjustment)
+{
+  return adjustment->priv->clamp_value;
+}
+
+/**
+ * mx_adjustment_set_clamp_value:
+ * @adjustment: A #MxAdjustment
+ * @clamp: a #gboolean
+ *
+ * Set the value of the #MxAdjustment:clamp-value property.
+ */
+void
+mx_adjustment_set_clamp_value (MxAdjustment *adjustment,
+                               gboolean      clamp)
+{
+  adjustment->priv->clamp_value = clamp;
+}
+
diff --git a/mx/mx-adjustment.h b/mx/mx-adjustment.h
new file mode 100644
index 0000000..0ae7153
--- /dev/null
+++ b/mx/mx-adjustment.h
@@ -0,0 +1,149 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-adjustment.h: Adjustment object
+ *
+ * Copyright 2008 OpenedHand
+ * Copyright 2009, 2010 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Chris Lord <chris openedhand com>, inspired by GtkAdjustment
+ * Port to Mx by: Robert Staudinger <robsta openedhand com>
+ *
+ */
+
+#ifndef __MX_ADJUSTMENT_H__
+#define __MX_ADJUSTMENT_H__
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define MX_TYPE_ADJUSTMENT            (mx_adjustment_get_type())
+#define MX_ADJUSTMENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MX_TYPE_ADJUSTMENT, MxAdjustment))
+#define MX_IS_ADJUSTMENT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MX_TYPE_ADJUSTMENT))
+#define MX_ADJUSTMENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MX_TYPE_ADJUSTMENT, MxAdjustmentClass))
+#define MX_IS_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MX_TYPE_ADJUSTMENT))
+#define MX_ADJUSTMENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MX_TYPE_ADJUSTMENT, MxAdjustmentClass))
+
+typedef struct _MxAdjustment          MxAdjustment;
+typedef struct _MxAdjustmentPrivate   MxAdjustmentPrivate;
+typedef struct _MxAdjustmentClass     MxAdjustmentClass;
+
+/**
+ * MxAdjustment:
+ *
+ * Class for handling an interval between to values. The contents of
+ * the #MxAdjustment are private and should be accessed using the
+ * public API.
+ */
+struct _MxAdjustment
+{
+  /*< private >*/
+  GObject parent_instance;
+
+  MxAdjustmentPrivate *priv;
+};
+
+/**
+ * MxAdjustmentClass
+ * @changed: Class handler for the ::changed signal.
+ *
+ * Base class for #MxAdjustment.
+ */
+struct _MxAdjustmentClass
+{
+  /*< private >*/
+  GObjectClass parent_class;
+
+  /*< public >*/
+  void (* changed) (MxAdjustment *adjustment);
+
+  /* padding for future expansion */
+  void (*_padding_0) (void);
+  void (*_padding_1) (void);
+  void (*_padding_2) (void);
+  void (*_padding_3) (void);
+  void (*_padding_4) (void);
+};
+
+GType mx_adjustment_get_type (void) G_GNUC_CONST;
+
+MxAdjustment *mx_adjustment_new                (void);
+MxAdjustment *mx_adjustment_new_with_values    (gdouble       value,
+                                                gdouble       lower,
+                                                gdouble       upper,
+                                                gdouble       step_increment,
+                                                gdouble       page_increment,
+                                                gdouble       page_size);
+gdouble       mx_adjustment_get_value          (MxAdjustment *adjustment);
+void          mx_adjustment_set_value          (MxAdjustment *adjustment,
+                                                gdouble       value);
+
+gdouble       mx_adjustment_get_lower          (MxAdjustment *adjustment);
+void          mx_adjustment_set_lower          (MxAdjustment *adjustment,
+                                                gdouble       lower);
+
+gdouble       mx_adjustment_get_upper          (MxAdjustment *adjustment);
+void          mx_adjustment_set_upper          (MxAdjustment *adjustment,
+                                                gdouble       upper);
+
+gdouble       mx_adjustment_get_step_increment (MxAdjustment *adjustment);
+void          mx_adjustment_set_step_increment (MxAdjustment *adjustment,
+                                                gdouble       increment);
+
+gdouble       mx_adjustment_get_page_increment (MxAdjustment *adjustment);
+void          mx_adjustment_set_page_increment (MxAdjustment *adjustment,
+                                                gdouble       increment);
+
+gdouble       mx_adjustment_get_page_size      (MxAdjustment *adjustment);
+void          mx_adjustment_set_page_size      (MxAdjustment *adjustment,
+                                                gdouble       page_size);
+
+void          mx_adjustment_set_values         (MxAdjustment *adjustment,
+                                                gdouble       value,
+                                                gdouble       lower,
+                                                gdouble       upper,
+                                                gdouble       step_increment,
+                                                gdouble       page_increment,
+                                                gdouble       page_size);
+void          mx_adjustment_get_values         (MxAdjustment *adjustment,
+                                                gdouble      *value,
+                                                gdouble      *lower,
+                                                gdouble      *upper,
+                                                gdouble      *step_increment,
+                                                gdouble      *page_increment,
+                                                gdouble      *page_size);
+
+void          mx_adjustment_interpolate          (MxAdjustment *adjustment,
+                                                  gdouble       value,
+                                                  guint         duration,
+                                                  gulong        mode);
+void          mx_adjustment_interpolate_relative (MxAdjustment *adjustment,
+                                                  gdouble       offset,
+                                                  guint         duration,
+                                                  gulong        mode);
+
+gboolean      mx_adjustment_get_elastic (MxAdjustment *adjustment);
+void          mx_adjustment_set_elastic (MxAdjustment *adjustment,
+                                         gboolean      elastic);
+
+gboolean      mx_adjustment_get_clamp_value (MxAdjustment *adjustment);
+void          mx_adjustment_set_clamp_value (MxAdjustment *adjustment,
+                                             gboolean      clamp);
+
+G_END_DECLS
+
+#endif /* __MX_ADJUSTMENT_H__ */
diff --git a/mx/mx-bin.c b/mx/mx-bin.c
new file mode 100644
index 0000000..3d16631
--- /dev/null
+++ b/mx/mx-bin.c
@@ -0,0 +1,715 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-bin.c: Basic container actor
+ *
+ * Copyright (c) 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi linux intel com>
+ *
+ */
+
+/**
+ * SECTION:mx-bin
+ * @short_description: a simple container with one actor.
+ *
+ * #MxBin is a simple abstract container capable of having only one
+ * #ClutterActor as a child. #MxBin does not allocate the child itself,
+ * therefore any subclasses are required to implement the
+ * #ClutterActorClass.allocate function.
+ * #mx_bin_allocate_child() can be used if no special allocation requirements
+ * are needed.
+ *
+ * #MxFrame is a simple implementation of #MxBin that can be used as a single
+ * actor container that implements alignment and padding.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <clutter/clutter.h>
+
+#include "mx-bin.h"
+#include "mx-enum-types.h"
+#include "mx-private.h"
+//#include "mx-focusable.h"
+
+
+#define MX_BIN_GET_PRIVATE(obj)       (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MX_TYPE_BIN, MxBinPrivate))
+
+struct _MxBinPrivate
+{
+  ClutterActor *child;
+  gboolean      child_has_space;
+
+  MxAlign       x_align;
+  MxAlign       y_align;
+
+  guint         x_fill : 1;
+  guint         y_fill : 1;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_CHILD,
+  PROP_X_ALIGN,
+  PROP_Y_ALIGN,
+  PROP_X_FILL,
+  PROP_Y_FILL
+};
+
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MxBin, mx_bin, CLUTTER_TYPE_GROUP,
+                                  G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+                                                         clutter_container_iface_init));
+
+/*
+void
+_mx_bin_get_align_factors (MxBin   *bin,
+                           gdouble *x_align,
+                           gdouble *y_align)
+{
+  MxBinPrivate *priv = bin->priv;
+  gdouble factor;
+
+  switch (priv->x_align)
+    {
+    case MX_ALIGN_START:
+      factor = 0.0;
+      break;
+
+    case MX_ALIGN_MIDDLE:
+      factor = 0.5;
+      break;
+
+    case MX_ALIGN_END:
+      factor = 1.0;
+      break;
+
+    default:
+      factor = 0.0;
+      break;
+    }
+
+  if (x_align)
+    *x_align = factor;
+
+  switch (priv->y_align)
+    {
+    case MX_ALIGN_START:
+      factor = 0.0;
+      break;
+
+    case MX_ALIGN_MIDDLE:
+      factor = 0.5;
+      break;
+
+    case MX_ALIGN_END:
+      factor = 1.0;
+      break;
+
+    default:
+      factor = 0.0;
+      break;
+    }
+
+  if (y_align)
+    *y_align = factor;
+}
+*/
+
+static void
+mx_bin_add (ClutterContainer *container,
+            ClutterActor     *actor)
+{
+  mx_bin_set_child (MX_BIN (container), actor);
+}
+
+static void
+mx_bin_remove (ClutterContainer *container,
+               ClutterActor     *actor)
+{
+  MxBinPrivate *priv = MX_BIN (container)->priv;
+
+  if (priv->child == actor)
+    mx_bin_set_child (MX_BIN (container), NULL);
+}
+
+static void
+mx_bin_foreach (ClutterContainer *container,
+                ClutterCallback   callback,
+                gpointer          user_data)
+{
+  MxBinPrivate *priv = MX_BIN (container)->priv;
+
+  if (priv->child)
+    callback (priv->child, user_data);
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+  iface->add = mx_bin_add;
+  iface->remove = mx_bin_remove;
+  iface->foreach = mx_bin_foreach;
+}
+
+static void
+mx_bin_paint (ClutterActor *self)
+{
+  MxBinPrivate *priv = MX_BIN (self)->priv;
+
+  /* allow MxWidget to paint the background */
+  CLUTTER_ACTOR_CLASS (mx_bin_parent_class)->paint (self);
+
+  /* then paint our child */
+  if (priv->child && priv->child_has_space)
+    clutter_actor_paint (priv->child);
+}
+
+static void
+mx_bin_pick (ClutterActor       *self,
+             const ClutterColor *pick_color)
+{
+  MxBinPrivate *priv = MX_BIN (self)->priv;
+
+  /* get the default pick implementation */
+  CLUTTER_ACTOR_CLASS (mx_bin_parent_class)->pick (self, pick_color);
+
+  if (priv->child)
+    clutter_actor_paint (priv->child);
+}
+
+/**
+ * mx_bin_allocate_child:
+ * @bin: An #MxBin
+ * @box: The box to allocate the child within
+ * @flags: #ClutterAllocationFlags, usually provided by the.
+ * clutter_actor_allocate function.
+ *
+ * Allocates the child of an #MxBin inside the given box. This function should
+ * usually only be called by subclasses of #MxBin.
+ *
+ * This function can be used to allocate the child of an #MxBin if no special
+ * allocation requirements are needed. It is similar to
+ * #mx_allocate_align_fill, except that it reads the alignment, padding and
+ * fill values from the #MxBin, and will call #clutter_actor_allocate on the
+ * child.
+ *
+ */
+void
+mx_bin_allocate_child (MxBin                  *bin,
+                       const ClutterActorBox  *box,
+                       ClutterAllocationFlags  flags)
+{
+  MxBinPrivate *priv;
+
+  g_return_if_fail (MX_IS_BIN (bin));
+
+  priv = bin->priv;
+
+  if (priv->child)
+    {
+      MxPadding padding = { 0, };
+      ClutterActorBox allocation = { 0, };
+
+//      mx_widget_get_padding (MX_WIDGET (bin), &padding);
+
+      allocation.x1 = padding.left;
+      allocation.x2 = box->x2 - box->x1 - padding.right;
+      allocation.y1 = padding.top;
+      allocation.y2 = box->y2 - box->y1 - padding.bottom;
+
+/*      mx_allocate_align_fill (priv->child,
+                              &allocation,
+                              priv->x_align,
+                              priv->y_align,
+                              priv->x_fill,
+                              priv->y_fill);*/
+
+      clutter_actor_allocate (priv->child, &allocation, flags);
+    }
+}
+
+static void
+mx_bin_get_preferred_width (ClutterActor *self,
+                            gfloat        for_height,
+                            gfloat       *min_width_p,
+                            gfloat       *natural_width_p)
+{
+  MxBinPrivate *priv = MX_BIN (self)->priv;
+  gfloat min_width, natural_width;
+  gfloat available_height;
+  MxPadding padding = { 0, };
+
+//  mx_widget_get_padding (MX_WIDGET (self), &padding);
+
+  available_height = for_height - padding.top - padding.bottom;
+
+  min_width = natural_width = padding.left + padding.right;
+
+  if (priv->child == NULL)
+    {
+      if (min_width_p)
+        *min_width_p = min_width;
+
+      if (natural_width_p)
+        *natural_width_p = natural_width;
+    }
+  else
+    {
+      clutter_actor_get_preferred_width (priv->child, available_height,
+                                         min_width_p,
+                                         natural_width_p);
+
+      if (min_width_p)
+        *min_width_p += min_width;
+
+      if (natural_width_p)
+        *natural_width_p += natural_width;
+    }
+}
+
+static void
+mx_bin_get_preferred_height (ClutterActor *self,
+                             gfloat        for_width,
+                             gfloat       *min_height_p,
+                             gfloat       *natural_height_p)
+{
+  MxBinPrivate *priv = MX_BIN (self)->priv;
+  gfloat min_height, natural_height;
+  gfloat available_width;
+  MxPadding padding = { 0, };
+
+//  mx_widget_get_padding (MX_WIDGET (self), &padding);
+
+  available_width = for_width - padding.left - padding.right;
+
+  min_height = natural_height = padding.top + padding.bottom;
+
+  if (priv->child == NULL)
+    {
+      if (min_height_p)
+        *min_height_p = min_height;
+
+      if (natural_height_p)
+        *natural_height_p = natural_height;
+    }
+  else
+    {
+      clutter_actor_get_preferred_height (priv->child, available_width,
+                                          min_height_p,
+                                          natural_height_p);
+
+      if (min_height_p)
+        *min_height_p += min_height;
+
+      if (natural_height_p)
+        *natural_height_p += natural_height;
+    }
+}
+
+static void
+mx_bin_dispose (GObject *gobject)
+{
+  MxBinPrivate *priv = MX_BIN (gobject)->priv;
+
+  if (priv->child)
+    {
+      clutter_actor_destroy (priv->child);
+      priv->child = NULL;
+    }
+
+  G_OBJECT_CLASS (mx_bin_parent_class)->dispose (gobject);
+}
+
+static void
+mx_bin_set_property (GObject      *gobject,
+                     guint         prop_id,
+                     const GValue *value,
+                     GParamSpec   *pspec)
+{
+  MxBin *bin = MX_BIN (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_CHILD:
+      mx_bin_set_child (bin, g_value_get_object (value));
+      break;
+
+    case PROP_X_ALIGN:
+      mx_bin_set_alignment (bin,
+                            g_value_get_enum (value),
+                            bin->priv->y_align);
+      break;
+
+    case PROP_Y_ALIGN:
+      mx_bin_set_alignment (bin,
+                            bin->priv->x_align,
+                            g_value_get_enum (value));
+      break;
+
+    case PROP_X_FILL:
+      mx_bin_set_fill (bin,
+                       g_value_get_boolean (value),
+                       bin->priv->y_fill);
+      break;
+
+    case PROP_Y_FILL:
+      mx_bin_set_fill (bin,
+                       bin->priv->x_fill,
+                       g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+mx_bin_get_property (GObject    *gobject,
+                     guint       prop_id,
+                     GValue     *value,
+                     GParamSpec *pspec)
+{
+  MxBinPrivate *priv = MX_BIN (gobject)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_CHILD:
+      g_value_set_object (value, priv->child);
+      break;
+
+    case PROP_X_FILL:
+      g_value_set_boolean (value, priv->x_fill);
+      break;
+
+    case PROP_Y_FILL:
+      g_value_set_boolean (value, priv->y_fill);
+      break;
+
+    case PROP_X_ALIGN:
+      g_value_set_enum (value, priv->x_align);
+      break;
+
+    case PROP_Y_ALIGN:
+      g_value_set_enum (value, priv->y_align);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+mx_bin_class_init (MxBinClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  GParamSpec *pspec;
+
+  g_type_class_add_private (klass, sizeof (MxBinPrivate));
+
+  gobject_class->set_property = mx_bin_set_property;
+  gobject_class->get_property = mx_bin_get_property;
+  gobject_class->dispose = mx_bin_dispose;
+
+  actor_class->get_preferred_width = mx_bin_get_preferred_width;
+  actor_class->get_preferred_height = mx_bin_get_preferred_height;
+  actor_class->paint = mx_bin_paint;
+  actor_class->pick = mx_bin_pick;
+
+  /**
+   * MxBin:child:
+   *
+   * The child #ClutterActor of the #MxBin container.
+   */
+  pspec = g_param_spec_object ("child",
+                               "Child",
+                               "The child of the Bin",
+                               CLUTTER_TYPE_ACTOR,
+                               MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_CHILD, pspec);
+
+  /**
+   * MxBin:x-align:
+   *
+   * The horizontal alignment of the #MxBin child.
+   */
+  pspec = g_param_spec_enum ("x-align",
+                             "X Align",
+                             "The horizontal alignment",
+                             MX_TYPE_ALIGN,
+                             MX_ALIGN_MIDDLE,
+                             MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_X_ALIGN, pspec);
+
+  /**
+   * MxBin:y-align:
+   *
+   * The vertical alignment of the #MxBin child.
+   */
+  pspec = g_param_spec_enum ("y-align",
+                             "Y Align",
+                             "The vertical alignment",
+                             MX_TYPE_ALIGN,
+                             MX_ALIGN_MIDDLE,
+                             MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_Y_ALIGN, pspec);
+
+  /**
+   * MxBin:x-fill:
+   *
+   * Whether the child should fill the horizontal allocation
+   */
+  pspec = g_param_spec_boolean ("x-fill",
+                                "X Fill",
+                                "Whether the child should fill the "
+                                "horizontal allocation",
+                                FALSE,
+                                MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_X_FILL, pspec);
+
+  /**
+   * MxBin:y-fill:
+   *
+   * Whether the child should fill the vertical allocation
+   */
+  pspec = g_param_spec_boolean ("y-fill",
+                                "Y Fill",
+                                "Whether the child should fill the "
+                                "vertical allocation",
+                                FALSE,
+                                MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_Y_FILL, pspec);
+}
+
+static void
+mx_bin_init (MxBin *bin)
+{
+  bin->priv = MX_BIN_GET_PRIVATE (bin);
+
+  bin->priv->x_align = MX_ALIGN_MIDDLE;
+  bin->priv->y_align = MX_ALIGN_MIDDLE;
+  bin->priv->child_has_space = TRUE;
+}
+
+/**
+ * mx_bin_set_child:
+ * @bin: a #MxBin
+ * @child: a #ClutterActor, or %NULL
+ *
+ * Sets @child as the child of @bin.
+ *
+ * If @bin already has a child, the previous child is removed.
+ */
+void
+mx_bin_set_child (MxBin        *bin,
+                  ClutterActor *child)
+{
+  MxBinPrivate *priv;
+
+  g_return_if_fail (MX_IS_BIN (bin));
+  g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));
+
+  priv = bin->priv;
+
+  if (priv->child == child)
+    return;
+
+  if (priv->child)
+    {
+      ClutterActor *old_child = priv->child;
+
+      g_object_ref (old_child);
+
+      priv->child = NULL;
+      clutter_actor_unparent (old_child);
+
+      g_signal_emit_by_name (bin, "actor-removed", old_child);
+
+      g_object_unref (old_child);
+    }
+
+  if (child)
+    {
+      priv->child = child;
+      clutter_actor_set_parent (child, CLUTTER_ACTOR (bin));
+
+      g_signal_emit_by_name (bin, "actor-added", priv->child);
+    }
+
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
+
+  g_object_notify (G_OBJECT (bin), "child");
+}
+
+/**
+ * mx_bin_get_child:
+ * @bin: a #MxBin
+ *
+ * Retrieves a pointer to the child of @bin.
+ *
+ * Return value: (transfer none): a #ClutterActor, or %NULL
+ */
+ClutterActor *
+mx_bin_get_child (MxBin *bin)
+{
+  g_return_val_if_fail (MX_IS_BIN (bin), NULL);
+
+  return bin->priv->child;
+}
+
+/**
+ * mx_bin_set_alignment:
+ * @bin: a #MxBin
+ * @x_align: horizontal alignment
+ * @y_align: vertical alignment
+ *
+ * Sets the horizontal and vertical alignment of the child
+ * inside a #MxBin.
+ */
+void
+mx_bin_set_alignment (MxBin  *bin,
+                      MxAlign x_align,
+                      MxAlign y_align)
+{
+  MxBinPrivate *priv;
+  gboolean changed = FALSE;
+
+  g_return_if_fail (MX_IS_BIN (bin));
+
+  priv = bin->priv;
+
+  g_object_freeze_notify (G_OBJECT (bin));
+
+  if (priv->x_align != x_align)
+    {
+      priv->x_align = x_align;
+      g_object_notify (G_OBJECT (bin), "x-align");
+      changed = TRUE;
+    }
+
+  if (priv->y_align != y_align)
+    {
+      priv->y_align = y_align;
+      g_object_notify (G_OBJECT (bin), "y-align");
+      changed = TRUE;
+    }
+
+  if (changed)
+    clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
+
+  g_object_thaw_notify (G_OBJECT (bin));
+}
+
+/**
+ * mx_bin_get_alignment:
+ * @bin: a #MxBin
+ * @x_align: return location for the horizontal alignment, or %NULL
+ * @y_align: return location for the vertical alignment, or %NULL
+ *
+ * Retrieves the horizontal and vertical alignment of the child
+ * inside a #MxBin, as set by mx_bin_set_alignment().
+ */
+void
+mx_bin_get_alignment (MxBin   *bin,
+                      MxAlign *x_align,
+                      MxAlign *y_align)
+{
+  MxBinPrivate *priv;
+
+  g_return_if_fail (MX_IS_BIN (bin));
+
+  priv = bin->priv;
+
+  if (x_align)
+    *x_align = priv->x_align;
+
+  if (y_align)
+    *y_align = priv->y_align;
+}
+
+/**
+ * mx_bin_set_fill:
+ * @bin: a #MxBin
+ * @x_fill: %TRUE if the child should fill horizontally the @bin
+ * @y_fill: %TRUE if the child should fill vertically the @bin
+ *
+ * Sets whether the child of @bin should fill out the horizontal
+ * and/or vertical allocation of the parent
+ */
+void
+mx_bin_set_fill (MxBin   *bin,
+                 gboolean x_fill,
+                 gboolean y_fill)
+{
+  MxBinPrivate *priv;
+  gboolean changed = FALSE;
+
+  g_return_if_fail (MX_IS_BIN (bin));
+
+  priv = bin->priv;
+
+  g_object_freeze_notify (G_OBJECT (bin));
+
+  if (priv->x_fill != x_fill)
+    {
+      priv->x_fill = x_fill;
+      changed = TRUE;
+
+      g_object_notify (G_OBJECT (bin), "x-fill");
+    }
+
+  if (priv->y_fill != y_fill)
+    {
+      priv->y_fill = y_fill;
+      changed = TRUE;
+
+      g_object_notify (G_OBJECT (bin), "y-fill");
+    }
+
+  if (changed)
+    clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
+
+  g_object_thaw_notify (G_OBJECT (bin));
+}
+
+/**
+ * mx_bin_get_fill:
+ * @bin: a #MxBin
+ * @x_fill: (out): return location for the horizontal fill, or %NULL
+ * @y_fill: (out): return location for the vertical fill, or %NULL
+ *
+ * Retrieves the horizontal and vertical fill settings
+ */
+void
+mx_bin_get_fill (MxBin    *bin,
+                 gboolean *x_fill,
+                 gboolean *y_fill)
+{
+  g_return_if_fail (MX_IS_BIN (bin));
+
+  if (x_fill)
+    *x_fill = bin->priv->x_fill;
+
+  if (y_fill)
+    *y_fill = bin->priv->y_fill;
+}
diff --git a/mx/mx-bin.h b/mx/mx-bin.h
new file mode 100644
index 0000000..666e809
--- /dev/null
+++ b/mx/mx-bin.h
@@ -0,0 +1,99 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-bin.h: Basic container actor
+ *
+ * Copyright 2009, 2008 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi linux intel com>
+ *
+ */
+
+#ifndef __MX_BIN_H__
+#define __MX_BIN_H__
+
+#include "mx-types.h"
+#include <clutter/clutter.h>
+
+
+G_BEGIN_DECLS
+
+#define MX_TYPE_BIN                   (mx_bin_get_type ())
+#define MX_BIN(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), MX_TYPE_BIN, MxBin))
+#define MX_IS_BIN(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MX_TYPE_BIN))
+#define MX_BIN_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), MX_TYPE_BIN, MxBinClass))
+#define MX_IS_BIN_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), MX_TYPE_BIN))
+#define MX_BIN_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), MX_TYPE_BIN, MxBinClass))
+
+typedef struct _MxBin                 MxBin;
+typedef struct _MxBinPrivate          MxBinPrivate;
+typedef struct _MxBinClass            MxBinClass;
+
+/**
+ * MxBin:
+ *
+ * The #MxBin struct contains only private data
+ */
+struct _MxBin
+{
+  /*< private >*/
+  ClutterGroup parent_instance;
+
+  MxBinPrivate *priv;
+};
+
+/**
+ * MxBinClass:
+ *
+ * The #MxBinClass struct contains only private data
+ */
+struct _MxBinClass
+{
+  /*< private >*/
+  ClutterGroupClass parent_class;
+
+  /* padding for future expansion */
+  void (*_padding_0) (void);
+  void (*_padding_1) (void);
+  void (*_padding_2) (void);
+  void (*_padding_3) (void);
+  void (*_padding_4) (void);
+};
+
+GType mx_bin_get_type (void) G_GNUC_CONST;
+
+void          mx_bin_allocate_child (MxBin                  *bin,
+                                     const ClutterActorBox  *box,
+                                     ClutterAllocationFlags  flags);
+void          mx_bin_set_child      (MxBin                  *bin,
+                                     ClutterActor           *child);
+ClutterActor *mx_bin_get_child      (MxBin                  *bin);
+void          mx_bin_set_alignment  (MxBin                  *bin,
+                                     MxAlign                 x_align,
+                                     MxAlign                 y_align);
+void          mx_bin_get_alignment  (MxBin                  *bin,
+                                     MxAlign                *x_align,
+                                     MxAlign                *y_align);
+void          mx_bin_set_fill       (MxBin                  *bin,
+                                     gboolean                x_fill,
+                                     gboolean                y_fill);
+void          mx_bin_get_fill       (MxBin                  *bin,
+                                     gboolean               *x_fill,
+                                     gboolean               *y_fill);
+
+G_END_DECLS
+
+#endif /* __MX_BIN_H__ */
diff --git a/mx/mx-draggable.c b/mx/mx-draggable.c
new file mode 100644
index 0000000..eced211
--- /dev/null
+++ b/mx/mx-draggable.c
@@ -0,0 +1,706 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-draggable.c: draggable interface
+ *
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi linux intel com>
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mx-draggable.h"
+#include "mx-enum-types.h"
+#include "mx-marshal.h"
+#include "mx-private.h"
+
+typedef struct _DragContext DragContext;
+
+struct _DragContext
+{
+  MxDraggable        *draggable;
+  ClutterActor       *stage;
+  ClutterActor       *actor;
+
+  guint               threshold;
+
+  MxDragAxis          axis;
+
+#if 0
+  MxDragContainment   containment;
+  ClutterActorBox    *containment_area;
+#endif
+
+  gfloat              press_x;
+  gfloat              press_y;
+  guint               press_button;
+  ClutterModifierType press_modifiers;
+
+  gfloat              last_x;
+  gfloat              last_y;
+
+  guint               emit_delayed_press : 1;
+  guint               in_drag            : 1;
+};
+
+enum
+{
+  DRAG_BEGIN,
+  DRAG_MOTION,
+  DRAG_END,
+
+  LAST_SIGNAL
+};
+
+static GQuark quark_draggable_context = 0;
+static guint draggable_signals[LAST_SIGNAL] = { 0, };
+
+static gboolean on_stage_capture (ClutterActor *stage,
+                                  ClutterEvent *event,
+                                  DragContext  *context);
+
+static gboolean
+draggable_release (DragContext        *context,
+                   ClutterButtonEvent *event)
+{
+  ClutterActor *stage, *actor;
+  gfloat event_x, event_y;
+  gfloat actor_x, actor_y;
+  gboolean res;
+
+  if (!context->in_drag)
+    return FALSE;
+
+  event_x = event->x;
+  event_y = event->y;
+  actor_x = 0;
+  actor_y = 0;
+
+  if (context->actor && !context->emit_delayed_press)
+    actor = context->actor;
+  else
+    actor = CLUTTER_ACTOR (context->draggable);
+
+  res = clutter_actor_transform_stage_point (actor,
+                                             event_x, event_y,
+                                             &actor_x, &actor_y);
+  if (!res)
+    return FALSE;
+
+  stage = clutter_actor_get_stage (CLUTTER_ACTOR (context->draggable));
+
+  context->last_x = actor_x;
+  context->last_y = actor_y;
+
+  context->in_drag = FALSE;
+
+  g_signal_handlers_disconnect_by_func (stage,
+                                        G_CALLBACK (on_stage_capture),
+                                        context);
+
+  if (!context->emit_delayed_press)
+    g_signal_emit (context->draggable, draggable_signals[DRAG_END], 0,
+                   context->last_x,
+                   context->last_y);
+
+  g_object_set_data (G_OBJECT (stage), "mx-drag-actor", NULL);
+
+  return FALSE;
+}
+
+static gboolean
+draggable_motion (DragContext        *context,
+                  ClutterMotionEvent *event)
+{
+  gfloat event_x, event_y;
+  gfloat actor_x, actor_y;
+  gfloat delta_x, delta_y;
+  ClutterActor *actor;
+  gboolean res;
+
+  if (!context->in_drag)
+    return FALSE;
+
+  event_x = event->x;
+  event_y = event->y;
+  actor_x = 0;
+  actor_y = 0;
+
+  if (context->actor && !context->emit_delayed_press)
+    actor = context->actor;
+  else
+    actor = CLUTTER_ACTOR (context->draggable);
+
+  res = clutter_actor_transform_stage_point (actor,
+                                             event_x, event_y,
+                                             &actor_x, &actor_y);
+  if (!res)
+    return FALSE;
+
+  context->last_x = actor_x;
+  context->last_y = actor_y;
+
+  delta_x = delta_y = 0;
+
+  if (context->axis == 0)
+    {
+      delta_x = context->last_x - context->press_x;
+      delta_y = context->last_y - context->press_y;
+    }
+  else
+    {
+      if (context->axis == MX_DRAG_AXIS_X)
+        delta_x = context->last_x - context->press_x;
+      else
+        delta_y = context->last_y - context->press_y;
+    }
+
+  if (context->emit_delayed_press)
+    {
+      if (ABS (delta_x) >= context->threshold
+          || ABS (delta_y) >= context->threshold)
+        {
+          ClutterActor *stage;
+
+          context->emit_delayed_press = FALSE;
+
+          g_signal_emit (context->draggable, draggable_signals[DRAG_BEGIN], 0,
+                         context->press_x,
+                         context->press_y,
+                         context->press_button,
+                         context->press_modifiers);
+
+          actor = CLUTTER_ACTOR (context->draggable);
+          stage = clutter_actor_get_stage (actor);
+          g_object_set_data (G_OBJECT (stage), "mx-drag-actor", actor);
+        }
+      else
+        return FALSE;
+    }
+
+  g_signal_emit (context->draggable, draggable_signals[DRAG_MOTION], 0,
+                 delta_x,
+                 delta_y);
+
+  return FALSE;
+}
+
+static gboolean
+on_stage_capture (ClutterActor *stage,
+                  ClutterEvent *event,
+                  DragContext  *context)
+{
+  switch (event->type)
+    {
+    case CLUTTER_MOTION:
+      if (context->in_drag)
+        {
+          ClutterMotionEvent *mevent = (ClutterMotionEvent *) event;
+
+          /* We can miss release events in the case of grabs, so check that
+           * the button is still down here.
+           */
+          if (!(mevent->modifier_state & CLUTTER_BUTTON1_MASK))
+            return draggable_release (context, (ClutterButtonEvent *) event);
+          else
+            return draggable_motion (context, (ClutterMotionEvent *) event);
+        }
+      break;
+
+    case CLUTTER_BUTTON_RELEASE:
+      if (context->in_drag)
+        return draggable_release (context, (ClutterButtonEvent *) event);
+      break;
+
+    default:
+      break;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+on_draggable_press (ClutterActor       *actor,
+                    ClutterButtonEvent *event,
+                    DragContext        *context)
+{
+  MxDraggable *draggable = context->draggable;
+  ClutterActor *stage;
+  gfloat event_x, event_y;
+  gfloat actor_x, actor_y;
+  gboolean res;
+
+  event_x = event->x;
+  event_y = event->y;
+  actor_x = 0;
+  actor_y = 0;
+
+  res = clutter_actor_transform_stage_point (actor,
+                                             event_x, event_y,
+                                             &actor_x, &actor_y);
+  if (!res)
+    return FALSE;
+
+  stage = clutter_actor_get_stage (actor);
+
+  context->press_x = actor_x;
+  context->press_y = actor_y;
+  context->last_x = context->press_x;
+  context->last_y = context->press_y;
+  context->press_button = event->button;
+  context->press_modifiers = event->modifier_state;
+  context->emit_delayed_press = FALSE;
+
+  g_object_get (G_OBJECT (draggable),
+                "drag-threshold", &context->threshold,
+                "axis", &context->axis,
+#if 0
+                "containment-type", &context->containment,
+                "containment-area", &context->containment_area,
+#endif
+                "drag-actor", &context->actor,
+                NULL);
+
+  if (context->threshold == 0)
+    {
+      g_signal_emit (draggable, draggable_signals[DRAG_BEGIN], 0,
+                     context->press_x,
+                     context->press_y,
+                     context->press_button,
+                     context->press_modifiers);
+
+      g_object_set_data (G_OBJECT (stage), "mx-drag-actor", actor);
+    }
+  else
+    context->emit_delayed_press = TRUE;
+
+  context->in_drag = TRUE;
+
+  context->stage = stage;
+  g_signal_connect_after (stage,
+                          "captured-event", G_CALLBACK (on_stage_capture),
+                          context);
+
+  return FALSE;
+}
+
+static void
+drag_context_free (gpointer data)
+{
+  if (G_LIKELY (data))
+    {
+      DragContext *context = data;
+
+      /* disconnect any signal handlers we may have installed */
+      g_signal_handlers_disconnect_by_func (context->draggable,
+                                            G_CALLBACK (on_draggable_press),
+                                            context);
+      if (context->stage)
+        {
+          g_signal_handlers_disconnect_by_func (context->stage,
+                                                G_CALLBACK (on_stage_capture),
+                                                context);
+          context->stage = NULL;
+        }
+
+      if (context->actor)
+        {
+          g_object_unref (G_OBJECT (context->actor));
+          context->actor = NULL;
+        }
+#if 0
+      if (context->containment_area)
+        g_boxed_free (CLUTTER_TYPE_ACTOR_BOX, context->containment_area);
+#endif
+
+      g_slice_free (DragContext, context);
+    }
+}
+
+static DragContext *
+drag_context_create (MxDraggable *draggable)
+{
+  DragContext *context;
+
+  context = g_slice_new (DragContext);
+
+  context->draggable = draggable;
+  context->threshold = 0;
+  context->axis = 0;
+#if 0
+  context->containment = MX_DISABLE_CONTAINMENT;
+  context->containment_area = NULL;
+#endif
+  context->in_drag = FALSE;
+  context->emit_delayed_press = FALSE;
+  context->stage = NULL;
+  context->actor = NULL;
+
+  /* attach the context to the draggable */
+  g_object_set_qdata_full (G_OBJECT (draggable), quark_draggable_context,
+                           context,
+                           drag_context_free);
+
+  return context;
+}
+
+static void
+mx_draggable_real_enable (MxDraggable *draggable)
+{
+  DragContext *context;
+  ClutterActor *stage;
+
+  context = g_object_get_qdata (G_OBJECT (draggable), quark_draggable_context);
+  if (G_UNLIKELY (context != NULL))
+    return;
+
+  stage = clutter_actor_get_stage (CLUTTER_ACTOR (draggable));
+  if (G_UNLIKELY (stage == NULL))
+    {
+      g_warning ("Draggable actors can only be enabled when they "
+                 "on the stage");
+      return;
+    }
+
+  context = drag_context_create (draggable);
+  g_signal_connect (draggable,
+                    "button-press-event", G_CALLBACK (on_draggable_press),
+                    context);
+
+  g_object_notify (G_OBJECT (draggable), "drag-enabled");
+}
+
+static void
+mx_draggable_real_disable (MxDraggable *draggable)
+{
+  DragContext *context;
+  ClutterActor *stage;
+
+  context = g_object_get_qdata (G_OBJECT (draggable), quark_draggable_context);
+  if (G_UNLIKELY (context == NULL))
+    return;
+
+  stage = clutter_actor_get_stage (CLUTTER_ACTOR (draggable));
+
+  g_signal_handlers_disconnect_by_func (draggable,
+                                        G_CALLBACK (on_draggable_press),
+                                        context);
+  g_signal_handlers_disconnect_by_func (stage,
+                                        G_CALLBACK (on_stage_capture),
+                                        context);
+  context->stage = NULL;
+
+  g_object_set_qdata (G_OBJECT (draggable), quark_draggable_context, NULL);
+
+  g_object_notify (G_OBJECT (draggable), "drag-enabled");
+}
+
+static void
+mx_draggable_base_init (gpointer g_iface)
+{
+  static gboolean is_initialized = FALSE;
+
+  if (G_UNLIKELY (!is_initialized))
+    {
+      MxDraggableIface *iface = g_iface;
+      GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+      GParamSpec *pspec;
+
+      is_initialized = TRUE;
+
+      quark_draggable_context =
+        g_quark_from_static_string ("mx-draggable-context");
+
+      pspec = g_param_spec_boolean ("drag-enabled",
+                                    "Drag Enabled",
+                                    "Whether the Draggable is enabled",
+                                    TRUE,
+                                    MX_PARAM_READWRITE);
+      g_object_interface_install_property (g_iface, pspec);
+
+      pspec = g_param_spec_uint ("drag-threshold",
+                                 "Drag Threshold",
+                                 "The amount of pixels required to "
+                                 "start dragging",
+                                 0, G_MAXUINT,
+                                 0,
+                                 MX_PARAM_READWRITE);
+      g_object_interface_install_property (g_iface, pspec);
+
+#if 0
+      pspec = g_param_spec_enum ("containment-type",
+                                 "Containment Type",
+                                 "The type of containment to be used",
+                                 MX_TYPE_DRAG_CONTAINMENT,
+                                 MX_DISABLE_CONTAINMENT,
+                                 MX_PARAM_READWRITE);
+      g_object_interface_install_property (g_iface, pspec);
+
+      pspec = g_param_spec_boxed ("containment-area",
+                                  "Containment Area",
+                                  "The area to which the draggable is "
+                                  "contained",
+                                  CLUTTER_TYPE_ACTOR_BOX,
+                                  MX_PARAM_READWRITE);
+      g_object_interface_install_property (g_iface, pspec);
+#endif
+
+      pspec = g_param_spec_enum ("axis",
+                                 "Axis",
+                                 "The axis along which the dragging "
+                                 "should be performed",
+                                 MX_TYPE_DRAG_AXIS,
+                                 MX_DRAG_AXIS_NONE,
+                                 MX_PARAM_READWRITE);
+      g_object_interface_install_property (g_iface, pspec);
+
+      pspec = g_param_spec_object ("drag-actor",
+                                   "Drag Actor",
+                                   "An actor to use in place of the "
+                                   "draggable while dragging.",
+                                   CLUTTER_TYPE_ACTOR,
+                                   MX_PARAM_READWRITE);
+      g_object_interface_install_property (g_iface, pspec);
+
+      draggable_signals[DRAG_BEGIN] =
+        g_signal_new (g_intern_static_string ("drag-begin"),
+                      iface_type,
+                      G_SIGNAL_RUN_FIRST,
+                      G_STRUCT_OFFSET (MxDraggableIface, drag_begin),
+                      NULL, NULL,
+                      _mx_marshal_VOID__FLOAT_FLOAT_INT_ENUM,
+                      G_TYPE_NONE, 4,
+                      G_TYPE_FLOAT,
+                      G_TYPE_FLOAT,
+                      G_TYPE_INT,
+                      CLUTTER_TYPE_MODIFIER_TYPE);
+
+      draggable_signals[DRAG_MOTION] =
+        g_signal_new (g_intern_static_string ("drag-motion"),
+                      iface_type,
+                      G_SIGNAL_RUN_FIRST,
+                      G_STRUCT_OFFSET (MxDraggableIface, drag_motion),
+                      NULL, NULL,
+                      _mx_marshal_VOID__FLOAT_FLOAT,
+                      G_TYPE_NONE, 2,
+                      G_TYPE_FLOAT,
+                      G_TYPE_FLOAT);
+
+      draggable_signals[DRAG_END] =
+        g_signal_new (g_intern_static_string ("drag-end"),
+                      iface_type,
+                      G_SIGNAL_RUN_FIRST,
+                      G_STRUCT_OFFSET (MxDraggableIface, drag_end),
+                      NULL, NULL,
+                      _mx_marshal_VOID__FLOAT_FLOAT,
+                      G_TYPE_NONE, 2,
+                      G_TYPE_FLOAT,
+                      G_TYPE_FLOAT);
+
+      iface->enable = mx_draggable_real_enable;
+      iface->disable = mx_draggable_real_disable;
+    }
+}
+
+GType
+mx_draggable_get_type (void)
+{
+  static GType our_type = 0;
+
+  if (G_UNLIKELY (our_type == 0))
+    {
+      const GTypeInfo draggable_info = {
+        sizeof (MxDraggableIface),
+        mx_draggable_base_init,
+        NULL, /* base_finalize */
+      };
+
+      our_type = g_type_register_static (G_TYPE_INTERFACE,
+                                         g_intern_static_string ("MxDraggable"),
+                                         &draggable_info, 0);
+
+      g_type_interface_add_prerequisite (our_type, CLUTTER_TYPE_ACTOR);
+    }
+
+  return our_type;
+}
+
+void
+mx_draggable_set_axis (MxDraggable *draggable,
+                       MxDragAxis   axis)
+{
+  g_return_if_fail (MX_IS_DRAGGABLE (draggable));
+
+  g_object_set (G_OBJECT (draggable), "axis", axis, NULL);
+}
+
+MxDragAxis
+mx_draggable_get_axis (MxDraggable *draggable)
+{
+  MxDragAxis retval = 0;
+
+  g_return_val_if_fail (MX_IS_DRAGGABLE (draggable), 0);
+
+  g_object_get (G_OBJECT (draggable), "axis", &retval, NULL);
+
+  return retval;
+}
+
+void
+mx_draggable_set_drag_threshold (MxDraggable *draggable,
+                                 guint        threshold)
+{
+  g_return_if_fail (MX_IS_DRAGGABLE (draggable));
+
+  g_object_set (G_OBJECT (draggable), "drag-threshold", threshold, NULL);
+}
+
+guint
+mx_draggable_get_drag_threshold (MxDraggable *draggable)
+{
+  guint retval = 0;
+
+  g_return_val_if_fail (MX_IS_DRAGGABLE (draggable), 0);
+
+  g_object_get (G_OBJECT (draggable), "drag-threshold", &retval, NULL);
+
+  return retval;
+}
+#if 0
+void
+mx_draggable_set_containment_type (MxDraggable      *draggable,
+                                   MxDragContainment containment)
+{
+  g_return_if_fail (MX_IS_DRAGGABLE (draggable));
+
+  g_object_set (G_OBJECT (draggable), "containment-type", containment, NULL);
+}
+
+MxDragContainment
+mx_draggable_get_containment_type (MxDraggable *draggable)
+{
+  MxDragContainment retval = MX_DISABLE_CONTAINMENT;
+
+  g_return_val_if_fail (MX_IS_DRAGGABLE (draggable), 0);
+
+  g_object_get (G_OBJECT (draggable), "containment-type", &retval, NULL);
+
+  return retval;
+}
+
+void
+mx_draggable_set_containment_area (MxDraggable *draggable,
+                                   gfloat       x_1,
+                                   gfloat       y_1,
+                                   gfloat       x_2,
+                                   gfloat       y_2)
+{
+  ClutterActorBox box;
+
+  g_return_if_fail (MX_IS_DRAGGABLE (draggable));
+
+  box.x1 = x_1;
+  box.y1 = y_1;
+  box.x2 = x_2;
+  box.y2 = y_2;
+
+  g_object_set (G_OBJECT (draggable), "containment-area", &box, NULL);
+}
+
+void
+mx_draggable_get_containment_area (MxDraggable *draggable,
+                                   gfloat      *x_1,
+                                   gfloat      *y_1,
+                                   gfloat      *x_2,
+                                   gfloat      *y_2)
+{
+  ClutterActorBox *box = NULL;
+
+  g_return_if_fail (MX_IS_DRAGGABLE (draggable));
+
+  g_object_get (G_OBJECT (draggable), "containment-area", &box, NULL);
+
+  if (box == NULL)
+    return;
+
+  if (x_1)
+    *x_1 = box->x1;
+
+  if (y_1)
+    *y_1 = box->y1;
+
+  if (x_2)
+    *x_2 = box->x2;
+
+  if (y_2)
+    *y_2 = box->y2;
+
+  g_boxed_free (CLUTTER_TYPE_ACTOR_BOX, box);
+}
+#endif
+
+void
+mx_draggable_set_drag_actor (MxDraggable  *draggable,
+                             ClutterActor *actor)
+{
+  g_return_if_fail (MX_IS_DRAGGABLE (draggable));
+
+  g_object_set (G_OBJECT (draggable), "drag-actor", actor, NULL);
+}
+
+ClutterActor *
+mx_draggable_get_drag_actor (MxDraggable *draggable)
+{
+  ClutterActor *actor = NULL;
+
+  g_return_val_if_fail (MX_IS_DRAGGABLE (draggable), NULL);
+
+  g_object_get (G_OBJECT (draggable), "drag-actor", &actor, NULL);
+
+  return actor;
+}
+
+void
+mx_draggable_enable (MxDraggable *draggable)
+{
+  g_return_if_fail (MX_IS_DRAGGABLE (draggable));
+
+  MX_DRAGGABLE_GET_IFACE (draggable)->enable (draggable);
+}
+
+void
+mx_draggable_disable (MxDraggable *draggable)
+{
+  g_return_if_fail (MX_IS_DRAGGABLE (draggable));
+
+  MX_DRAGGABLE_GET_IFACE (draggable)->disable (draggable);
+}
+
+gboolean
+mx_draggable_is_enabled (MxDraggable *draggable)
+{
+  gboolean retval = FALSE;
+
+  g_return_val_if_fail (MX_IS_DRAGGABLE (draggable), FALSE);
+
+  g_object_get (G_OBJECT (draggable), "drag-enabled", &retval, NULL);
+
+  return retval;
+}
diff --git a/mx/mx-draggable.h b/mx/mx-draggable.h
new file mode 100644
index 0000000..0718c86
--- /dev/null
+++ b/mx/mx-draggable.h
@@ -0,0 +1,132 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-draggable.h: draggable interface
+ *
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi linux intel com>
+ *
+ */
+
+#ifndef __MX_DRAGGABLE_H__
+#define __MX_DRAGGABLE_H__
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define MX_TYPE_DRAGGABLE             (mx_draggable_get_type ())
+#define MX_DRAGGABLE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), MX_TYPE_DRAGGABLE, MxDraggable))
+#define MX_IS_DRAGGABLE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MX_TYPE_DRAGGABLE))
+#define MX_DRAGGABLE_GET_IFACE(obj)   (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MX_TYPE_DRAGGABLE, MxDraggableIface))
+
+/**
+ * MxDraggable:
+ *
+ * This is an opaque structure whose members cannot be directly accessed.
+ */
+typedef struct _MxDraggable           MxDraggable; /* dummy typedef */
+typedef struct _MxDraggableIface      MxDraggableIface;
+
+typedef enum {
+  MX_DRAG_AXIS_NONE,
+  MX_DRAG_AXIS_X,
+  MX_DRAG_AXIS_Y
+} MxDragAxis;
+
+#if 0
+/*
+typedef enum {
+  MX_DISABLE_CONTAINMENT,
+  MX_CONTAIN_IN_STAGE,
+  MX_CONTAIN_IN_PARENT,
+  MX_CONTAIN_IN_AREA
+} MxDragContainment;
+*/
+#endif
+
+/**
+ * MxDraggableIface:
+ * @enable: virtual function called when enabling a #MxDraggable; MX
+ *    already provides a default implementation
+ * @disable: virtual function called when disabling a #MxDraggable; MX
+ *    already provides a default implementation
+ * @drag_begin: class handler for the #MxDraggable::drag-begin signal
+ * @drag_motion: class handler for the #MxDraggable::drag-motion signal
+ * @drag_end: class handler for the #MxDraggable::drag-end signal
+ *
+ * Interface for draggable #ClutterActor<!-- -->s.
+ */
+struct _MxDraggableIface
+{
+  /*< private >*/
+  GTypeInterface g_iface;
+
+  /*< public >*/
+  /* vfuncs, not signals */
+  void (* enable)  (MxDraggable *draggable);
+  void (* disable) (MxDraggable *draggable);
+
+  /* signals */
+  void (* drag_begin)  (MxDraggable         *draggable,
+                        gfloat               event_x,
+                        gfloat               event_y,
+                        gint                 event_button,
+                        ClutterModifierType  modifiers);
+  void (* drag_motion) (MxDraggable         *draggable,
+                        gfloat               delta_x,
+                        gfloat               delta_y);
+  void (* drag_end)    (MxDraggable         *draggable,
+                        gfloat               event_x,
+                        gfloat               event_y);
+};
+
+GType mx_draggable_get_type (void) G_GNUC_CONST;
+
+void              mx_draggable_set_axis             (MxDraggable       *draggable,
+                                                     MxDragAxis         axis);
+MxDragAxis        mx_draggable_get_axis             (MxDraggable       *draggable);
+
+void              mx_draggable_set_drag_threshold   (MxDraggable       *draggable,
+                                                     guint              threshold);
+guint             mx_draggable_get_drag_threshold   (MxDraggable       *draggable);
+#if 0
+void              mx_draggable_set_containment_type (MxDraggable       *draggable,
+                                                     MxDragContainment  containment);
+MxDragContainment mx_draggable_get_containment_type (MxDraggable       *draggable);
+void              mx_draggable_set_containment_area (MxDraggable       *draggable,
+                                                     gfloat             x_1,
+                                                     gfloat             y_1,
+                                                     gfloat             x_2,
+                                                     gfloat             y_2);
+void              mx_draggable_get_containment_area (MxDraggable       *draggable,
+                                                     gfloat            *x_1,
+                                                     gfloat            *y_1,
+                                                     gfloat            *x_2,
+                                                     gfloat            *y_2);
+#endif
+void              mx_draggable_set_drag_actor       (MxDraggable       *draggable,
+                                                     ClutterActor      *actor);
+ClutterActor *    mx_draggable_get_drag_actor       (MxDraggable       *draggable);
+
+void              mx_draggable_disable              (MxDraggable       *draggable);
+void              mx_draggable_enable               (MxDraggable       *draggable);
+gboolean          mx_draggable_is_enabled           (MxDraggable       *draggable);
+
+G_END_DECLS
+
+#endif /* __MX_DRAGGABLE_H__ */
diff --git a/tidy/tidy-enum-types.c.in b/mx/mx-enum-types.c.in
similarity index 95%
rename from tidy/tidy-enum-types.c.in
rename to mx/mx-enum-types.c.in
index 5f78912..7af6194 100644
--- a/tidy/tidy-enum-types.c.in
+++ b/mx/mx-enum-types.c.in
@@ -1,5 +1,5 @@
 /*** BEGIN file-header ***/
-#include "tidy-enum-types.h"
+#include "mx-enum-types.h"
 /*** END file-header ***/
 
 /*** BEGIN file-production ***/
diff --git a/tidy/tidy-enum-types.h.in b/mx/mx-enum-types.h.in
similarity index 70%
rename from tidy/tidy-enum-types.h.in
rename to mx/mx-enum-types.h.in
index 517cccb..49bce41 100644
--- a/tidy/tidy-enum-types.h.in
+++ b/mx/mx-enum-types.h.in
@@ -1,6 +1,6 @@
 /*** BEGIN file-header ***/
-#ifndef __TIDY_ENUM_TYPES_H__
-#define __TIDY_ENUM_TYPES_H__
+#ifndef __MX_ENUM_TYPES_H__
+#define __MX_ENUM_TYPES_H__
 
 #include <glib-object.h>
 
@@ -15,11 +15,11 @@ G_BEGIN_DECLS
 /*** BEGIN file-tail ***/
 G_END_DECLS
 
-#endif /* !__TIDY_ENUM_TYPES_H__ */
+#endif /* !__MX_ENUM_TYPES_H__ */
 /*** END file-tail ***/
 
 /*** BEGIN value-header ***/
 GType @enum_name _get_type (void) G_GNUC_CONST;
-#define TIDY_TYPE_ ENUMSHORT@ (@enum_name _get_type())
+#define MX_TYPE_ ENUMSHORT@ (@enum_name _get_type())
 
 /*** END value-header ***/
diff --git a/mx/mx-kinetic-scroll-view.c b/mx/mx-kinetic-scroll-view.c
new file mode 100644
index 0000000..ebc5fd2
--- /dev/null
+++ b/mx/mx-kinetic-scroll-view.c
@@ -0,0 +1,1195 @@
+/* mx-kinetic-scroll-view.c: Kinetic scrolling container actor
+ *
+ * Copyright (C) 2008 OpenedHand
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris linux intel com>
+ */
+
+/**
+ * SECTION:mx-kinetic-scroll-view
+ * @short_description: A kinetic scrolling container widget
+ *
+ * #MxKineticScrollView is a single child container for actors that implements
+ * #MxScrollable. It allows the contained child to be dragged to scroll, and
+ * maintains the momentum once the drag is complete. Deceleration after
+ * dragging is configurable, and it will always snap to the
+ * #MxAdjustment:step-increment boundary.
+ *
+ * #MxKineticScrollView also implements #MxScrollable itself, allowing it to
+ * be embedded in an #MxScrollView to provide scroll-bars.
+ */
+
+#include "mx-kinetic-scroll-view.h"
+#include "mx-enum-types.h"
+#include "mx-marshal.h"
+#include "mx-private.h"
+#include "mx-scrollable.h"
+#include <math.h>
+
+static void mx_scrollable_iface_init (MxScrollableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MxKineticScrollView,
+                         mx_kinetic_scroll_view, MX_TYPE_BIN,
+                         G_IMPLEMENT_INTERFACE (MX_TYPE_SCROLLABLE,
+                                                mx_scrollable_iface_init))
+
+#define KINETIC_SCROLL_VIEW_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+                                        MX_TYPE_KINETIC_SCROLL_VIEW, \
+                                        MxKineticScrollViewPrivate))
+
+typedef struct {
+  /* Units to store the origin of a click when scrolling */
+  gfloat   x;
+  gfloat   y;
+  GTimeVal time;
+} MxKineticScrollViewMotion;
+
+struct _MxKineticScrollViewPrivate
+{
+  ClutterActor          *child;
+
+  guint                  use_captured : 1;
+  guint                  in_drag      : 1;
+  guint                  hmoving      : 1;
+  guint                  vmoving      : 1;
+  guint32                button;
+
+  /* Mouse motion event information */
+  GArray                *motion_buffer;
+  guint                  last_motion;
+
+  /* Variables for storing acceleration information */
+  ClutterTimeline       *deceleration_timeline;
+  gfloat                 dx;
+  gfloat                 dy;
+  gdouble                decel_rate;
+  gdouble                overshoot;
+  gdouble                accumulated_delta;
+};
+
+enum {
+  PROP_0,
+
+  PROP_DECELERATION,
+/*  PROP_BUFFER_SIZE,*/
+  PROP_HADJUST,
+  PROP_VADJUST,
+  PROP_BUTTON,
+  PROP_USE_CAPTURED,
+  PROP_OVERSHOOT
+};
+
+enum
+{
+  /* normal signals */
+  PANNING_COMPLETED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+/* MxScrollableIface implementation */
+
+static void
+mx_kinetic_scroll_view_set_adjustments (MxScrollable *scrollable,
+                                        MxAdjustment *hadjustment,
+                                        MxAdjustment *vadjustment)
+{
+  MxKineticScrollViewPrivate *priv = MX_KINETIC_SCROLL_VIEW (scrollable)->priv;
+
+  if (priv->child)
+    mx_scrollable_set_adjustments (MX_SCROLLABLE (priv->child),
+                                   hadjustment,
+                                   vadjustment);
+}
+
+static void
+mx_kinetic_scroll_view_get_adjustments (MxScrollable  *scrollable,
+                                        MxAdjustment **hadjustment,
+                                        MxAdjustment **vadjustment)
+{
+  MxKineticScrollViewPrivate *priv = MX_KINETIC_SCROLL_VIEW (scrollable)->priv;
+
+  if (priv->child)
+    {
+      mx_scrollable_get_adjustments (MX_SCROLLABLE (priv->child),
+                                     hadjustment,
+                                     vadjustment);
+    }
+  else
+    {
+      if (hadjustment)
+        *hadjustment = NULL;
+      if (vadjustment)
+        *vadjustment = NULL;
+    }
+}
+
+static void
+mx_scrollable_iface_init (MxScrollableIface *iface)
+{
+  iface->set_adjustments = mx_kinetic_scroll_view_set_adjustments;
+  iface->get_adjustments = mx_kinetic_scroll_view_get_adjustments;
+}
+
+/* Object implementation */
+
+static void
+mx_kinetic_scroll_view_get_property (GObject    *object,
+                                     guint       property_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  MxAdjustment *adjustment;
+  MxKineticScrollViewPrivate *priv = MX_KINETIC_SCROLL_VIEW (object)->priv;
+
+  switch (property_id)
+    {
+    case PROP_DECELERATION :
+      g_value_set_double (value, priv->decel_rate);
+      break;
+
+/*
+    case PROP_BUFFER_SIZE :
+      g_value_set_uint (value, priv->motion_buffer->len);
+      break;
+*/
+
+    case PROP_HADJUST:
+      mx_kinetic_scroll_view_get_adjustments (MX_SCROLLABLE (object),
+                                        &adjustment, NULL);
+      g_value_set_object (value, adjustment);
+      break;
+
+    case PROP_VADJUST:
+      mx_kinetic_scroll_view_get_adjustments (MX_SCROLLABLE (object),
+                                        NULL, &adjustment);
+      g_value_set_object (value, adjustment);
+      break;
+
+    case PROP_BUTTON:
+      g_value_set_uint (value, priv->button);
+      break;
+
+    case PROP_USE_CAPTURED:
+      g_value_set_boolean (value, priv->use_captured);
+      break;
+
+    case PROP_OVERSHOOT:
+      g_value_set_double (value, priv->overshoot);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+mx_kinetic_scroll_view_set_property (GObject      *object,
+                                     guint         property_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  MxAdjustment *adjustment;
+  MxScrollable *scrollable;
+  MxKineticScrollView *self = MX_KINETIC_SCROLL_VIEW (object);
+
+  switch (property_id)
+    {
+    case PROP_DECELERATION :
+      mx_kinetic_scroll_view_set_deceleration (self,
+                                               g_value_get_double (value));
+      break;
+
+/*
+    case PROP_BUFFER_SIZE :
+      mx_kinetic_scroll_view_set_buffer_size (self, g_value_get_uint (value));
+      break;
+*/
+
+    case PROP_HADJUST:
+      scrollable = MX_SCROLLABLE (object);
+      mx_kinetic_scroll_view_get_adjustments (scrollable, NULL, &adjustment);
+      mx_kinetic_scroll_view_set_adjustments (scrollable,
+                                        g_value_get_object (value),
+                                        adjustment);
+      break;
+
+    case PROP_VADJUST:
+      scrollable = MX_SCROLLABLE (object);
+      mx_kinetic_scroll_view_get_adjustments (scrollable, &adjustment, NULL);
+      mx_kinetic_scroll_view_set_adjustments (scrollable,
+                                        adjustment,
+                                        g_value_get_object (value));
+      break;
+
+    case PROP_BUTTON:
+      mx_kinetic_scroll_view_set_mouse_button (self, g_value_get_uint (value));
+      break;
+
+    case PROP_USE_CAPTURED:
+      mx_kinetic_scroll_view_set_use_captured (self,
+                                               g_value_get_boolean (value));
+      break;
+
+    case PROP_OVERSHOOT:
+      mx_kinetic_scroll_view_set_overshoot (self, g_value_get_double (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+mx_kinetic_scroll_view_dispose (GObject *object)
+{
+  MxKineticScrollViewPrivate *priv = MX_KINETIC_SCROLL_VIEW (object)->priv;
+
+  if (priv->deceleration_timeline)
+    {
+      clutter_timeline_stop (priv->deceleration_timeline);
+      g_object_unref (priv->deceleration_timeline);
+      priv->deceleration_timeline = NULL;
+    }
+
+  G_OBJECT_CLASS (mx_kinetic_scroll_view_parent_class)->dispose (object);
+}
+
+static void
+mx_kinetic_scroll_view_finalize (GObject *object)
+{
+  MxKineticScrollViewPrivate *priv = MX_KINETIC_SCROLL_VIEW (object)->priv;
+
+  g_array_free (priv->motion_buffer, TRUE);
+
+  G_OBJECT_CLASS (mx_kinetic_scroll_view_parent_class)->finalize (object);
+}
+
+static void
+mx_kinetic_scroll_view_get_preferred_width (ClutterActor *actor,
+                                            gfloat        for_height,
+                                            gfloat       *min_width_p,
+                                            gfloat       *nat_width_p)
+{
+  CLUTTER_ACTOR_CLASS (mx_kinetic_scroll_view_parent_class)->
+    get_preferred_width (actor, for_height, NULL, nat_width_p);
+
+  if (min_width_p)
+    {
+      MxPadding padding = { 0, };
+
+//      mx_widget_get_padding (MX_WIDGET (actor), &padding);
+      *min_width_p = padding.left + padding.right;
+    }
+}
+
+static void
+mx_kinetic_scroll_view_get_preferred_height (ClutterActor *actor,
+                                             gfloat        for_width,
+                                             gfloat       *min_height_p,
+                                             gfloat       *nat_height_p)
+{
+  CLUTTER_ACTOR_CLASS (mx_kinetic_scroll_view_parent_class)->
+    get_preferred_height (actor, for_width, NULL, nat_height_p);
+
+  if (min_height_p)
+    {
+      MxPadding padding = { 0, };
+
+//      mx_widget_get_padding (MX_WIDGET (actor), &padding);
+      *min_height_p = padding.top + padding.bottom;
+    }
+}
+
+static void
+mx_kinetic_scroll_view_allocate (ClutterActor           *actor,
+                                 const ClutterActorBox  *box,
+                                 ClutterAllocationFlags  flags)
+{
+  CLUTTER_ACTOR_CLASS (mx_kinetic_scroll_view_parent_class)->
+    allocate (actor, box, flags);
+
+  mx_bin_allocate_child (MX_BIN (actor), box, flags);
+}
+
+static void
+mx_kinetic_scroll_view_class_init (MxKineticScrollViewClass *klass)
+{
+  GParamSpec *pspec;
+
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (MxKineticScrollViewPrivate));
+
+  object_class->get_property = mx_kinetic_scroll_view_get_property;
+  object_class->set_property = mx_kinetic_scroll_view_set_property;
+  object_class->dispose = mx_kinetic_scroll_view_dispose;
+  object_class->finalize = mx_kinetic_scroll_view_finalize;
+
+  actor_class->get_preferred_width =
+    mx_kinetic_scroll_view_get_preferred_width;
+  actor_class->get_preferred_height =
+    mx_kinetic_scroll_view_get_preferred_height;
+  actor_class->allocate =
+    mx_kinetic_scroll_view_allocate;
+
+  pspec = g_param_spec_double ("deceleration",
+                               "Deceleration",
+                               "Rate at which the view will decelerate in.",
+                               1.1, G_MAXDOUBLE, 1.1,
+                               MX_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_DECELERATION, pspec);
+
+  /*
+  pspec = g_param_spec_uint ("buffer-size",
+                             "Buffer size",
+                             "Amount of motion events to buffer",
+                             1, G_MAXUINT, 3,
+                             MX_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_BUFFER_SIZE, pspec);
+  */
+
+  pspec = g_param_spec_uint ("mouse-button",
+                             "Mouse button",
+                             "The mouse button used to control scrolling",
+                             0, G_MAXUINT, 1,
+                             MX_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_BUTTON, pspec);
+
+  pspec = g_param_spec_boolean ("use-captured",
+                                "Use captured",
+                                "Use captured events to initiate scrolling",
+                                FALSE,
+                                MX_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_USE_CAPTURED, pspec);
+
+  pspec = g_param_spec_double ("overshoot",
+                               "Overshoot",
+                               "The rate at which the view will decelerate "
+                               "when scrolled beyond its boundaries.",
+                               0.0, 1.0, 0.0,
+                               MX_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_OVERSHOOT, pspec);
+
+  /* MxScrollable properties */
+  g_object_class_override_property (object_class,
+                                    PROP_HADJUST,
+                                    "horizontal-adjustment");
+
+  g_object_class_override_property (object_class,
+                                    PROP_VADJUST,
+                                    "vertical-adjustment");
+                                    
+  signals[PANNING_COMPLETED] =
+      g_signal_new ("panning-completed", G_OBJECT_CLASS_TYPE (object_class),
+          G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+          _mx_marshal_VOID__VOID, G_TYPE_NONE, 0);
+}
+
+static gboolean
+motion_event_cb (ClutterActor        *stage,
+                 ClutterMotionEvent  *event,
+                 MxKineticScrollView *scroll)
+{
+  gfloat x, y;
+
+  MxKineticScrollViewPrivate *priv = scroll->priv;
+  ClutterActor *actor = CLUTTER_ACTOR (scroll);
+
+  if (event->type != CLUTTER_MOTION)
+    return FALSE;
+
+  if (clutter_actor_transform_stage_point (actor,
+                                           event->x,
+                                           event->y,
+                                           &x, &y))
+    {
+      MxKineticScrollViewMotion *motion;
+      ClutterActor *child = mx_bin_get_child (MX_BIN (scroll));
+
+      /* Check if we've passed the drag threshold */
+      if (!priv->in_drag)
+        {
+          guint threshold = 8; // default value
+
+          motion = &g_array_index (priv->motion_buffer,
+                                   MxKineticScrollViewMotion, 0);
+
+          if ((ABS (motion->x - x) >= threshold) ||
+              (ABS (motion->y - y) >= threshold))
+            {
+              clutter_set_motion_events_enabled (TRUE);
+              priv->in_drag = TRUE;
+            }
+          else
+            return FALSE;
+        }
+
+      if (child)
+        {
+          gdouble dx, dy;
+          MxAdjustment *hadjust, *vadjust;
+
+          mx_scrollable_get_adjustments (MX_SCROLLABLE (child),
+                                         &hadjust, &vadjust);
+
+          motion = &g_array_index (priv->motion_buffer,
+                                   MxKineticScrollViewMotion,
+                                   priv->last_motion);
+
+          if (hadjust)
+            {
+              dx = (motion->x - x) + mx_adjustment_get_value (hadjust);
+              mx_adjustment_set_value (hadjust, dx);
+            }
+
+          if (vadjust)
+            {
+              dy = (motion->y - y) + mx_adjustment_get_value (vadjust);
+              mx_adjustment_set_value (vadjust, dy);
+            }
+        }
+
+      priv->last_motion ++;
+      if (priv->last_motion == priv->motion_buffer->len)
+        {
+          priv->motion_buffer = g_array_remove_index (priv->motion_buffer, 0);
+          g_array_set_size (priv->motion_buffer, priv->last_motion);
+          priv->last_motion --;
+        }
+
+      motion = &g_array_index (priv->motion_buffer,
+                               MxKineticScrollViewMotion, priv->last_motion);
+      motion->x = x;
+      motion->y = y;
+      g_get_current_time (&motion->time);
+    }
+
+  return TRUE;
+}
+
+static void
+clamp_adjustments (MxKineticScrollView *scroll,
+                   guint                duration,
+                   gboolean             horizontal,
+                   gboolean             vertical)
+{
+  ClutterActor *child = mx_bin_get_child (MX_BIN (scroll));
+
+  if (child)
+    {
+      gdouble d, value, lower, upper, step_increment, page_size;
+      MxAdjustment *hadj, *vadj;
+
+      mx_scrollable_get_adjustments (MX_SCROLLABLE (child),
+                                     &hadj, &vadj);
+
+      if (horizontal && hadj)
+        {
+          /* Snap to the nearest step increment on hadjustment */
+          mx_adjustment_get_values (hadj, &value, &lower, &upper,
+                                    &step_increment, NULL, &page_size);
+          d = (rint ((value - lower) / step_increment) *
+              step_increment) + lower;
+          d = CLAMP (d, lower, upper - page_size);
+          mx_adjustment_interpolate (hadj, d, duration, CLUTTER_EASE_OUT_QUAD);
+        }
+
+      if (vertical && vadj)
+        {
+          /* Snap to the nearest step increment on vadjustment */
+          mx_adjustment_get_values (vadj, &value, &lower, &upper,
+                                    &step_increment, NULL, &page_size);
+          d = (rint ((value - lower) / step_increment) *
+              step_increment) + lower;
+          d = CLAMP (d, lower, upper - page_size);
+          mx_adjustment_interpolate (vadj, d, duration, CLUTTER_EASE_OUT_QUAD);
+        }
+    }
+}
+
+static void
+deceleration_completed_cb (ClutterTimeline     *timeline,
+                           MxKineticScrollView *scroll)
+{
+  MxKineticScrollViewPrivate *priv = scroll->priv;
+
+  clamp_adjustments (scroll, (priv->overshoot > 0.0) ? 250 : 10,
+                     priv->hmoving, priv->vmoving);
+
+  g_object_unref (timeline);
+  priv->deceleration_timeline = NULL;
+  
+  g_signal_emit_by_name (scroll, "panning-completed", NULL);
+}
+
+static void
+deceleration_new_frame_cb (ClutterTimeline     *timeline,
+                           gint                 frame_num,
+                           MxKineticScrollView *scroll)
+{
+  MxKineticScrollViewPrivate *priv = scroll->priv;
+  ClutterActor *child = mx_bin_get_child (MX_BIN (scroll));
+
+  if (child)
+    {
+      MxAdjustment *hadjust, *vadjust;
+
+      gboolean stop = TRUE;
+
+      mx_scrollable_get_adjustments (MX_SCROLLABLE (child),
+                                     &hadjust, &vadjust);
+
+      priv->accumulated_delta += clutter_timeline_get_delta (timeline);
+
+      if (priv->accumulated_delta <= 1000.0/60.0)
+        stop = FALSE;
+
+      while (priv->accumulated_delta > 1000.0/60.0)
+        {
+          gdouble hvalue, vvalue;
+
+          if (hadjust)
+            {
+              if (ABS (priv->dx) > 0.1)
+                {
+                  hvalue = priv->dx + mx_adjustment_get_value (hadjust);
+                  mx_adjustment_set_value (hadjust, hvalue);
+
+                  if (priv->overshoot > 0.0)
+                    {
+                      if ((hvalue > mx_adjustment_get_upper (hadjust) -
+                           mx_adjustment_get_page_size (hadjust)) ||
+                          (hvalue < mx_adjustment_get_lower (hadjust)))
+                        priv->dx *= priv->overshoot;
+                    }
+
+                  priv->dx = priv->dx / priv->decel_rate;
+
+                  stop = FALSE;
+                }
+              else if (priv->hmoving)
+                {
+                  priv->hmoving = FALSE;
+                  clamp_adjustments (scroll,
+                                     (priv->overshoot > 0.0) ? 250 : 10,
+                                     TRUE, FALSE);
+                }
+            }
+
+          if (vadjust)
+            {
+              if (ABS (priv->dy) > 0.1)
+                {
+                  vvalue = priv->dy + mx_adjustment_get_value (vadjust);
+                  mx_adjustment_set_value (vadjust, vvalue);
+
+                  if (priv->overshoot > 0.0)
+                    {
+                      if ((vvalue > mx_adjustment_get_upper (vadjust) -
+                           mx_adjustment_get_page_size (vadjust)) ||
+                          (vvalue < mx_adjustment_get_lower (vadjust)))
+                        priv->dy *= priv->overshoot;
+                    }
+
+                  priv->dy = priv->dy / priv->decel_rate;
+
+                  stop = FALSE;
+                }
+              else if (priv->vmoving)
+                {
+                  priv->vmoving = FALSE;
+                  clamp_adjustments (scroll,
+                                     (priv->overshoot > 0.0) ? 250 : 10,
+                                     FALSE, TRUE);
+                }
+            }
+
+          priv->accumulated_delta -= 1000.0/60.0;
+        }
+
+      if (stop)
+        {
+          clutter_timeline_stop (timeline);
+          deceleration_completed_cb (timeline, scroll);
+        }
+    }
+}
+
+static gboolean
+button_release_event_cb (ClutterActor        *stage,
+                         ClutterButtonEvent  *event,
+                         MxKineticScrollView *scroll)
+{
+  MxKineticScrollViewPrivate *priv = scroll->priv;
+  ClutterActor *actor = CLUTTER_ACTOR (scroll);
+  ClutterActor *child = mx_bin_get_child (MX_BIN (scroll));
+  gboolean decelerating = FALSE;
+
+  if ((event->type != CLUTTER_BUTTON_RELEASE) ||
+      (event->button != priv->button))
+    return FALSE;
+
+  g_signal_handlers_disconnect_by_func (stage,
+                                        motion_event_cb,
+                                        scroll);
+  g_signal_handlers_disconnect_by_func (stage,
+                                        button_release_event_cb,
+                                        scroll);
+
+  if (!priv->in_drag)
+    return FALSE;
+
+  clutter_set_motion_events_enabled (TRUE);
+
+  if (child)
+    {
+      gfloat event_x, event_y;
+
+      if (clutter_actor_transform_stage_point (actor, event->x, event->y,
+                                               &event_x, &event_y))
+        {
+          gdouble value, lower, upper, step_increment, page_size,
+                  d, ax, ay, y, nx, ny, n;
+          gfloat frac, x_origin, y_origin;
+          GTimeVal release_time, motion_time;
+          MxAdjustment *hadjust, *vadjust;
+          glong time_diff;
+          guint duration;
+          gint i;
+
+          /* Get time delta */
+          g_get_current_time (&release_time);
+
+          /* Get average position/time of last x mouse events */
+          priv->last_motion ++;
+          x_origin = y_origin = 0;
+          motion_time = (GTimeVal){ 0, 0 };
+          for (i = 0; i < priv->last_motion; i++)
+            {
+              MxKineticScrollViewMotion *motion =
+                &g_array_index (priv->motion_buffer, MxKineticScrollViewMotion, i);
+
+              /* FIXME: This doesn't guard against overflows - Should
+               *        either fix that, or calculate the correct maximum
+               *        value for the buffer size
+               */
+              x_origin += motion->x;
+              y_origin += motion->y;
+              motion_time.tv_sec += motion->time.tv_sec;
+              motion_time.tv_usec += motion->time.tv_usec;
+            }
+          x_origin = x_origin / priv->last_motion;
+          y_origin = y_origin / priv->last_motion;
+          motion_time.tv_sec /= priv->last_motion;
+          motion_time.tv_usec /= priv->last_motion;
+
+          if (motion_time.tv_sec == release_time.tv_sec)
+            time_diff = release_time.tv_usec - motion_time.tv_usec;
+          else
+            time_diff = release_time.tv_usec +
+                        (G_USEC_PER_SEC - motion_time.tv_usec);
+
+          /* Work out the fraction of 1/60th of a second that has elapsed */
+          frac = (time_diff/1000.0) / (1000.0/60.0);
+
+          /* See how many units to move in 1/60th of a second */
+          priv->dx = (x_origin - event_x) / frac;
+          priv->dy = (y_origin - event_y) / frac;
+
+          /* If the delta is too low for the equations to work,
+           * bump the values up a bit.
+           */
+          if (ABS (priv->dx) < 1)
+            priv->dx = (priv->dx > 0) ? 1 : -1;
+          if (ABS (priv->dy) < 1)
+            priv->dy = (priv->dy > 0) ? 1 : -1;
+
+          /* We want n, where x / y^n < z,
+           * x = Distance to move per frame
+           * y = Deceleration rate
+           * z = maximum distance from target
+           *
+           * Rearrange to n = log (x / z) / log (y)
+           * To simplify, z = 1, so n = log (x) / log (y)
+           */
+          y = priv->decel_rate;
+          nx = logf (ABS (priv->dx)) / logf (y);
+          ny = logf (ABS (priv->dy)) / logf (y);
+          n = MAX (nx, ny);
+
+          duration = MAX (1, (gint)(MAX (nx, ny) * (1000/60.0)));
+
+          if (duration > 250)
+            {
+              /* Now we have n, adjust dx/dy so that we finish on a step
+               * boundary.
+               *
+               * Distance moved, using the above variable names:
+               *
+               * d = x + x/y + x/y^2 + ... + x/y^n
+               *
+               * Using geometric series,
+               *
+               * d = (1 - 1/y^(n+1))/(1 - 1/y)*x
+               *
+               * Let a = (1 - 1/y^(n+1))/(1 - 1/y),
+               *
+               * d = a * x
+               *
+               * Find d and find its nearest page boundary, then solve for x
+               *
+               * x = d / a
+               */
+
+              /* Get adjustments, work out y^n */
+              mx_scrollable_get_adjustments (MX_SCROLLABLE (child),
+                                             &hadjust, &vadjust);
+              ax = (1.0 - 1.0 / pow (y, n + 1)) / (1.0 - 1.0 / y);
+              ay = (1.0 - 1.0 / pow (y, n + 1)) / (1.0 - 1.0 / y);
+
+              /* Solving for dx */
+              if (hadjust)
+                {
+                  mx_adjustment_get_values (hadjust, &value, &lower, &upper,
+                                            &step_increment, NULL, &page_size);
+
+                  /* Make sure we pick the next nearest step increment in the
+                   * same direction as the push.
+                   */
+                  priv->dx *= n;
+                  if (ABS (priv->dx) < step_increment / 2)
+                    d = round ((value + priv->dx - lower) / step_increment);
+                  else if (priv->dx > 0)
+                    d = ceil ((value + priv->dx - lower) / step_increment);
+                  else
+                    d = floor ((value + priv->dx - lower) / step_increment);
+
+                  if (priv->overshoot <= 0.0)
+                    d = CLAMP ((d * step_increment) + lower,
+                               lower, upper - page_size) - value;
+                  else
+                    d = ((d * step_increment) + lower) - value;
+
+                  priv->dx = d / ax;
+                }
+
+              /* Solving for dy */
+              if (vadjust)
+                {
+                  mx_adjustment_get_values (vadjust, &value, &lower, &upper,
+                                            &step_increment, NULL, &page_size);
+
+                  priv->dy *= n;
+                  if (ABS (priv->dy) < step_increment / 2)
+                    d = round ((value + priv->dy - lower) / step_increment);
+                  else if (priv->dy > 0)
+                    d = ceil ((value + priv->dy - lower) / step_increment);
+                  else
+                    d = floor ((value + priv->dy - lower) / step_increment);
+
+                  if (priv->overshoot <= 0.0)
+                    d = CLAMP ((d * step_increment) + lower,
+                               lower, upper - page_size) - value;
+                  else
+                    d = ((d * step_increment) + lower) - value;
+
+                  priv->dy = d / ay;
+                }
+
+              priv->deceleration_timeline = clutter_timeline_new (duration);
+
+              g_signal_connect (priv->deceleration_timeline, "new_frame",
+                                G_CALLBACK (deceleration_new_frame_cb), scroll);
+              g_signal_connect (priv->deceleration_timeline, "completed",
+                                G_CALLBACK (deceleration_completed_cb), scroll);
+              priv->accumulated_delta = 0;
+              priv->hmoving = priv->vmoving = TRUE;
+              clutter_timeline_start (priv->deceleration_timeline);
+              decelerating = TRUE;
+            }
+        }
+    }
+
+  /* Reset motion event buffer */
+  priv->last_motion = 0;
+
+  if (!decelerating)
+    {
+      clamp_adjustments (scroll, 250, TRUE, TRUE);
+      g_signal_emit_by_name (scroll, "panning-completed", NULL);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+button_press_event_cb (ClutterActor        *actor,
+                       ClutterEvent        *event,
+                       MxKineticScrollView *scroll)
+{
+  MxKineticScrollViewPrivate *priv = scroll->priv;
+  ClutterButtonEvent *bevent = (ClutterButtonEvent *)event;
+  ClutterActor *stage = clutter_actor_get_stage (actor);
+
+  if ((event->type == CLUTTER_BUTTON_PRESS) &&
+      (bevent->button == priv->button) &&
+      stage)
+    {
+      MxKineticScrollViewMotion *motion;
+
+      /* Reset motion buffer */
+      priv->last_motion = 0;
+      motion = &g_array_index (priv->motion_buffer, MxKineticScrollViewMotion, 0);
+
+      if (clutter_actor_transform_stage_point (actor, bevent->x, bevent->y,
+                                               &motion->x, &motion->y))
+        {
+          guint threshold = 8; //default value
+
+          g_get_current_time (&motion->time);
+
+          if (priv->deceleration_timeline)
+            {
+              clutter_timeline_stop (priv->deceleration_timeline);
+              g_object_unref (priv->deceleration_timeline);
+              priv->deceleration_timeline = NULL;
+            }
+
+          g_signal_connect (stage,
+                            "captured-event",
+                            G_CALLBACK (motion_event_cb),
+                            scroll);
+          g_signal_connect (stage,
+                            "captured-event",
+                            G_CALLBACK (button_release_event_cb),
+                            scroll);
+
+          /* If there's a zero drag threshold, start the drag immediately */
+          if (threshold == 0)
+            {
+              priv->in_drag = TRUE;
+              clutter_set_motion_events_enabled (FALSE);
+
+              /* Swallow the press event */
+              return TRUE;
+            }
+          else
+            priv->in_drag = FALSE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+mx_kinetic_scroll_view_actor_added_cb (ClutterContainer *container,
+                                       ClutterActor     *actor)
+{
+  MxKineticScrollViewPrivate *priv = MX_KINETIC_SCROLL_VIEW (container)->priv;
+
+  if (MX_IS_SCROLLABLE (actor))
+    {
+      MxAdjustment *hadjust, *vadjust;
+
+      priv->child = actor;
+
+      /* Make sure the adjustments have been created so the child
+       * will initialise them during its allocation (necessary for
+       * MxBoxLayout, for example)
+       */
+      mx_scrollable_get_adjustments (MX_SCROLLABLE (actor), &hadjust, &vadjust);
+    }
+  else
+    g_warning ("Attempting to add an actor of type %s to "
+               "a MxKineticScrollView, but the actor does "
+               "not implement MxScrollable.",
+               g_type_name (G_OBJECT_TYPE (actor)));
+}
+
+static void
+mx_kinetic_scroll_view_actor_removed_cb (ClutterContainer *container,
+                                         ClutterActor     *actor)
+{
+  MxKineticScrollViewPrivate *priv = MX_KINETIC_SCROLL_VIEW (container)->priv;
+  priv->child = NULL;
+}
+
+static void
+mx_kinetic_scroll_view_init (MxKineticScrollView *self)
+{
+  MxKineticScrollViewPrivate *priv = self->priv =
+    KINETIC_SCROLL_VIEW_PRIVATE (self);
+
+  priv->motion_buffer =
+    g_array_sized_new (FALSE, TRUE, sizeof (MxKineticScrollViewMotion), 3);
+  g_array_set_size (priv->motion_buffer, 3);
+  priv->decel_rate = 1.1f;
+  priv->button = 1;
+
+  clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
+  g_signal_connect (self, "button-press-event",
+                    G_CALLBACK (button_press_event_cb), self);
+  g_signal_connect (self, "actor-added",
+                    G_CALLBACK (mx_kinetic_scroll_view_actor_added_cb), self);
+  g_signal_connect (self, "actor-removed",
+                    G_CALLBACK (mx_kinetic_scroll_view_actor_removed_cb), self);
+
+  mx_bin_set_alignment (MX_BIN (self), MX_ALIGN_START, MX_ALIGN_START);
+}
+
+/**
+ * mx_kinetic_scroll_view_new:
+ *
+ * Creates a new #MxKineticScrollView.
+ *
+ * Returns: a newly allocated #MxKineticScrollView
+ */
+ClutterActor *
+mx_kinetic_scroll_view_new ()
+{
+  return g_object_new (MX_TYPE_KINETIC_SCROLL_VIEW, NULL);
+}
+
+/**
+ * mx_kinetic_scroll_view_stop:
+ * @scroll: A #MxKineticScrollView
+ *
+ * Stops any current movement due to kinetic scrolling.
+ */
+void
+mx_kinetic_scroll_view_stop (MxKineticScrollView *scroll)
+{
+  MxKineticScrollViewPrivate *priv;
+
+  g_return_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll));
+
+  priv = scroll->priv;
+
+  if (priv->deceleration_timeline)
+    {
+      clutter_timeline_stop (priv->deceleration_timeline);
+      g_object_unref (priv->deceleration_timeline);
+      priv->deceleration_timeline = NULL;
+    }
+}
+
+/**
+ * mx_kinetic_scroll_view_set_deceleration:
+ * @scroll: A #MxKineticScrollView
+ * @rate: The deceleration rate
+ *
+ * Sets the deceleration rate when a drag is finished on the kinetic
+ * scroll-view. This is the value that the momentum is divided by
+ * every 60th of a second.
+ */
+void
+mx_kinetic_scroll_view_set_deceleration (MxKineticScrollView *scroll,
+                                         gdouble              rate)
+{
+  MxKineticScrollViewPrivate *priv;
+
+  g_return_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll));
+  g_return_if_fail (rate >= 1.1);
+
+  priv = scroll->priv;
+
+  if (priv->decel_rate != rate)
+    {
+      priv->decel_rate = rate;
+      g_object_notify (G_OBJECT (scroll), "deceleration");
+    }
+}
+
+/**
+ * mx_kinetic_scroll_view_get_deceleration:
+ * @scroll: A #MxKineticScrollView
+ *
+ * Retrieves the deceleration rate of the kinetic scroll-view.
+ *
+ * Returns: The deceleration rate of the kinetic scroll-view
+ */
+gdouble
+mx_kinetic_scroll_view_get_deceleration (MxKineticScrollView *scroll)
+{
+  g_return_val_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll), 0.0);
+  return scroll->priv->decel_rate;
+}
+
+/*
+void
+mx_kinetic_scroll_view_set_buffer_size (MxKineticScrollView *scroll,
+                                        guint                size)
+{
+  MxKineticScrollViewPrivate *priv;
+
+  g_return_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll));
+  g_return_if_fail (size > 0);
+
+  priv = scroll->priv;
+  if (priv->motion_buffer->len != size)
+    {
+      g_array_set_size (priv->motion_buffer, size);
+      g_object_notify (G_OBJECT (scroll), "buffer-size");
+    }
+}
+
+guint
+mx_kinetic_scroll_view_get_buffer_size (MxKineticScrollView *scroll)
+{
+  g_return_val_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll), 0);
+  return scroll->priv->motion_buffer->len;
+}
+*/
+
+/**
+ * mx_kinetic_scroll_view_set_mouse_button:
+ * @scroll: A #MxKineticScrollView
+ * @button: A mouse button number
+ *
+ * Sets the mouse button number used to initiate drag events on the kinetic
+ * scroll-view.
+ */
+void
+mx_kinetic_scroll_view_set_mouse_button (MxKineticScrollView *scroll,
+                                         guint32              button)
+{
+  MxKineticScrollViewPrivate *priv;
+
+  g_return_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll));
+
+  priv = scroll->priv;
+
+  if (priv->button != button)
+    {
+      priv->button = button;
+      g_object_notify (G_OBJECT (scroll), "mouse-button");
+    }
+}
+
+/**
+ * mx_kinetic_scroll_view_get_mouse_button:
+ * @scroll: A #MxKineticScrollView
+ *
+ * Gets the #MxKineticScrollView:mouse-button property
+ *
+ * Returns: The mouse button number used to initiate drag events on the
+ *          kinetic scroll-view
+ */
+guint32
+mx_kinetic_scroll_view_get_mouse_button (MxKineticScrollView *scroll)
+{
+  g_return_val_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll), 0);
+  return scroll->priv->button;
+}
+
+/**
+ * mx_kinetic_scroll_view_set_use_captured:
+ * @scroll: A #MxKineticScrollView
+ * @use_captured: %TRUE to use captured events
+ *
+ * Sets whether to use captured events to initiate drag events. This can be
+ * used to block events that would initiate scrolling from reaching the child
+ * actor.
+ */
+void
+mx_kinetic_scroll_view_set_use_captured (MxKineticScrollView *scroll,
+                                         gboolean             use_captured)
+{
+  MxKineticScrollViewPrivate *priv;
+
+  g_return_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll));
+
+  priv = scroll->priv;
+  if (priv->use_captured != use_captured)
+    {
+      priv->use_captured = use_captured;
+
+      g_signal_handlers_disconnect_by_func (scroll,
+                                            button_press_event_cb,
+                                            scroll);
+
+      g_signal_connect (scroll,
+                        use_captured ? "captured-event" : "button-press-event",
+                        G_CALLBACK (button_press_event_cb),
+                        scroll);
+
+      g_object_notify (G_OBJECT (scroll), "use-captured");
+    }
+}
+
+/**
+ * mx_kinetic_scroll_view_get_use_captured:
+ * @scroll: A #MxKineticScrollView
+ *
+ * Gets the #MxKineticScrollView:use-captured property.
+ *
+ * Returns: %TRUE if captured-events should be used to initiate scrolling
+ */
+gboolean
+mx_kinetic_scroll_view_get_use_captured (MxKineticScrollView *scroll)
+{
+  g_return_val_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll), FALSE);
+  return scroll->priv->use_captured;
+}
+
+/**
+ * mx_kinetic_scroll_view_set_overshoot:
+ * @scroll: A #MxKineticScrollView
+ * @overshoot: The rate at which the view will decelerate when scrolling beyond
+ *             its boundaries.
+ *
+ * Sets the rate at which the view will decelerate when scrolling beyond its
+ * boundaries. The deceleration rate will be multiplied by this value every
+ * 60th of a second when the view is scrolling outside of the range set by its
+ * adjustments.
+ *
+ * See mx_kinetic_scroll_view_set_deceleration()
+ */
+void
+mx_kinetic_scroll_view_set_overshoot (MxKineticScrollView *scroll,
+                                      gdouble              overshoot)
+{
+  MxKineticScrollViewPrivate *priv;
+
+  g_return_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll));
+
+  priv = scroll->priv;
+  if (priv->overshoot != overshoot)
+    {
+      priv->overshoot = overshoot;
+      g_object_notify (G_OBJECT (scroll), "overshoot");
+    }
+}
+
+/**
+ * mx_kinetic_scroll_view_get_overshoot:
+ * @scroll: A #MxKineticScrollView
+ *
+ * Retrieves the deceleration rate multiplier used when the scroll-view is
+ * scrolling beyond its boundaries.
+ */
+gdouble
+mx_kinetic_scroll_view_get_overshoot (MxKineticScrollView *scroll)
+{
+  g_return_val_if_fail (MX_IS_KINETIC_SCROLL_VIEW (scroll), 0.0);
+  return scroll->priv->overshoot;
+}
diff --git a/mx/mx-kinetic-scroll-view.h b/mx/mx-kinetic-scroll-view.h
new file mode 100644
index 0000000..b8efe28
--- /dev/null
+++ b/mx/mx-kinetic-scroll-view.h
@@ -0,0 +1,92 @@
+/* mx-kinetic-scroll-view.h: Kinetic scrolling container actor
+ *
+ * Copyright (C) 2008 OpenedHand
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris linux intel com>
+ */
+
+#ifndef __MX_KINETIC_SCROLL_VIEW_H__
+#define __MX_KINETIC_SCROLL_VIEW_H__
+
+#include <glib-object.h>
+#include "mx-bin.h"
+
+G_BEGIN_DECLS
+
+#define MX_TYPE_KINETIC_SCROLL_VIEW            (mx_kinetic_scroll_view_get_type())
+#define MX_KINETIC_SCROLL_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MX_TYPE_KINETIC_SCROLL_VIEW, MxKineticScrollView))
+#define MX_IS_KINETIC_SCROLL_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MX_TYPE_KINETIC_SCROLL_VIEW))
+#define MX_KINETIC_SCROLL_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MX_TYPE_KINETIC_SCROLL_VIEW, MxKineticScrollViewClass))
+#define MX_IS_KINETIC_SCROLL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MX_TYPE_KINETIC_SCROLL_VIEW))
+#define MX_KINETIC_SCROLL_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MX_TYPE_KINETIC_SCROLL_VIEW, MxKineticScrollViewClass))
+
+/**
+ * MxKineticScrollView:
+ *
+ * The contents of this structure is private and should only be accessed using
+ * the provided API.
+ */
+typedef struct _MxKineticScrollView          MxKineticScrollView;
+typedef struct _MxKineticScrollViewPrivate   MxKineticScrollViewPrivate;
+typedef struct _MxKineticScrollViewClass     MxKineticScrollViewClass;
+
+struct _MxKineticScrollView
+{
+  /*< private >*/
+  MxBin                  parent_instance;
+
+  MxKineticScrollViewPrivate *priv;
+};
+
+struct _MxKineticScrollViewClass
+{
+  MxBinClass parent_class;
+};
+
+GType mx_kinetic_scroll_view_get_type (void) G_GNUC_CONST;
+
+ClutterActor *mx_kinetic_scroll_view_new  (void);
+
+void mx_kinetic_scroll_view_stop (MxKineticScrollView *scroll);
+
+void mx_kinetic_scroll_view_set_deceleration (MxKineticScrollView *scroll,
+                                              gdouble              rate);
+gdouble mx_kinetic_scroll_view_get_deceleration (MxKineticScrollView *scroll);
+
+/*
+void mx_kinetic_scroll_view_set_buffer_size (MxKineticScrollView *scroll,
+                                             guint                size);
+guint mx_kinetic_scroll_view_get_buffer_size (MxKineticScrollView *scroll);
+*/
+
+void mx_kinetic_scroll_view_set_use_captured (MxKineticScrollView *scroll,
+                                              gboolean        use_captured);
+gboolean mx_kinetic_scroll_view_get_use_captured (MxKineticScrollView *scroll);
+
+void mx_kinetic_scroll_view_set_mouse_button (MxKineticScrollView *scroll,
+                                              guint32         button);
+guint32 mx_kinetic_scroll_view_get_mouse_button (MxKineticScrollView *scroll);
+
+void mx_kinetic_scroll_view_set_overshoot (MxKineticScrollView *scroll,
+                                           gdouble              overshoot);
+gdouble mx_kinetic_scroll_view_get_overshoot (MxKineticScrollView *scroll);
+
+G_END_DECLS
+
+#endif /* __MX_KINETIC_SCROLL_VIEW_H__ */
diff --git a/mx/mx-marshal.list b/mx/mx-marshal.list
new file mode 100644
index 0000000..bd59b23
--- /dev/null
+++ b/mx/mx-marshal.list
@@ -0,0 +1,8 @@
+VOID:OBJECT
+VOID:VOID
+VOID:PARAM
+VOID:UINT
+VOID:UINT,UINT
+VOID:OBJECT,OBJECT
+VOID:FLOAT,FLOAT,INT,ENUM
+VOID:FLOAT,FLOAT
diff --git a/tidy/tidy-private.h b/mx/mx-private.h
similarity index 82%
rename from tidy/tidy-private.h
rename to mx/mx-private.h
index 5f17d93..b18eaf3 100644
--- a/tidy/tidy-private.h
+++ b/mx/mx-private.h
@@ -1,4 +1,4 @@
-/* tidy-private.h: Private declarations
+/* mx-private.h: Private declarations
  *
  * Copyright (C) 2007 OpenedHand
  *
@@ -18,8 +18,8 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#ifndef __TIDY_PRIVATE_H__
-#define __TIDY_PRIVATE_H__
+#ifndef __MX_PRIVATE_H__
+#define __MX_PRIVATE_H__
 
 #include <glib.h>
 
@@ -27,14 +27,14 @@ G_BEGIN_DECLS
 
 #define I_(str)         (g_intern_static_string ((str)))
 
-#define TIDY_PARAM_READABLE     \
-        (G_PARAM_READABLE |     \
+#define MX_PARAM_READWRITE    \
+        (G_PARAM_READABLE | G_PARAM_WRITABLE | \
          G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
 
-#define TIDY_PARAM_READWRITE    \
+#define MX_PARAM_READWRITE    \
         (G_PARAM_READABLE | G_PARAM_WRITABLE | \
          G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
 
 G_END_DECLS
 
-#endif /* __TIDY_PRIVATE_H__ */
+#endif /* __MX_PRIVATE_H__ */
diff --git a/mx/mx-scrollable.c b/mx/mx-scrollable.c
new file mode 100644
index 0000000..52912b4
--- /dev/null
+++ b/mx/mx-scrollable.c
@@ -0,0 +1,99 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-scrollable.c: Scrollable interface
+ *
+ * Copyright 2008 OpenedHand
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ * Port to Mx by: Robert Staudinger <robsta openedhand com>
+ *
+ */
+
+#include "mx-scrollable.h"
+#include "mx-private.h"
+
+static void
+mx_scrollable_base_init (gpointer g_iface)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      GParamSpec *pspec;
+      pspec = g_param_spec_object ("horizontal-adjustment",
+                                   "Horizontal adjustment",
+                                   "The MxAdjustment for horizontal scrolling.",
+                                   MX_TYPE_ADJUSTMENT,
+                                   MX_PARAM_READWRITE);
+      g_object_interface_install_property (g_iface, pspec);
+
+      pspec = g_param_spec_object ("vertical-adjustment",
+                                   "Vertical adjustment",
+                                   "The MxAdjustment for vertical scrolling.",
+                                   MX_TYPE_ADJUSTMENT,
+                                   MX_PARAM_READWRITE);
+      g_object_interface_install_property (g_iface, pspec);
+
+      initialized = TRUE;
+    }
+}
+
+GType
+mx_scrollable_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0)
+    {
+      static const GTypeInfo info =
+      {
+        sizeof (MxScrollableIface),
+        mx_scrollable_base_init,          /* base_init */
+        NULL,
+      };
+      type = g_type_register_static (G_TYPE_INTERFACE,
+                                     "MxScrollable", &info, 0);
+    }
+  return type;
+}
+
+void
+mx_scrollable_set_adjustments (MxScrollable *scrollable,
+                               MxAdjustment *hadjustment,
+                               MxAdjustment *vadjustment)
+{
+  MX_SCROLLABLE_GET_IFACE (scrollable)->set_adjustments (scrollable,
+                                                         hadjustment,
+                                                         vadjustment);
+}
+
+/**
+ * mx_scroll_bar_get_adjustments:
+ * @hadjustment: (transfer none) (out) (allow-none): location to store the horizontal adjustment, or %NULL
+ * @vadjustment: (transfer none) (out) (allow-none): location to store the vertical adjustment, or %NULL
+ *
+ * Gets the adjustment objects that store the offsets of the scrollable widget
+ * into its possible scrolling area.
+ */
+void
+mx_scrollable_get_adjustments (MxScrollable  *scrollable,
+                               MxAdjustment **hadjustment,
+                               MxAdjustment **vadjustment)
+{
+  MX_SCROLLABLE_GET_IFACE (scrollable)->get_adjustments (scrollable,
+                                                         hadjustment,
+                                                         vadjustment);
+}
diff --git a/mx/mx-scrollable.h b/mx/mx-scrollable.h
new file mode 100644
index 0000000..493f3ae
--- /dev/null
+++ b/mx/mx-scrollable.h
@@ -0,0 +1,71 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-scrollable.h: Scrollable interface
+ *
+ * Copyright 2008 OpenedHand
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ * Port to Mx by: Robert Staudinger <robsta openedhand com>
+ *
+ */
+
+#ifndef __MX_SCROLLABLE_H__
+#define __MX_SCROLLABLE_H__
+
+#include <glib-object.h>
+#include "mx-adjustment.h"
+
+G_BEGIN_DECLS
+
+#define MX_TYPE_SCROLLABLE            (mx_scrollable_get_type ())
+#define MX_SCROLLABLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MX_TYPE_SCROLLABLE, MxScrollable))
+#define MX_IS_SCROLLABLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MX_TYPE_SCROLLABLE))
+#define MX_SCROLLABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MX_TYPE_SCROLLABLE, MxScrollableIface))
+
+/**
+ * MxScrollable:
+ *
+ * This is an opaque structure whose members cannot be directly accessed.
+ */
+typedef struct _MxScrollable MxScrollable; /* Dummy object */
+typedef struct _MxScrollableIface MxScrollableIface;
+
+struct _MxScrollableIface
+{
+  GTypeInterface parent;
+
+  void (* set_adjustments) (MxScrollable  *scrollable,
+                            MxAdjustment  *hadjustment,
+                            MxAdjustment  *vadjustment);
+  void (* get_adjustments) (MxScrollable  *scrollable,
+                            MxAdjustment **hadjustment,
+                            MxAdjustment **vadjustment);
+};
+
+GType mx_scrollable_get_type (void) G_GNUC_CONST;
+
+void mx_scrollable_set_adjustments (MxScrollable  *scrollable,
+                                    MxAdjustment  *hadjustment,
+                                    MxAdjustment  *vadjustment);
+void mx_scrollable_get_adjustments (MxScrollable  *scrollable,
+                                    MxAdjustment **hadjustment,
+                                    MxAdjustment **vadjustment);
+
+G_END_DECLS
+
+#endif /* __MX_SCROLLABLE_H__ */
diff --git a/mx/mx-types.h b/mx/mx-types.h
new file mode 100644
index 0000000..11eebbc
--- /dev/null
+++ b/mx/mx-types.h
@@ -0,0 +1,80 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright 2009, 2010 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/**
+ * SECTION:mx-types
+ * @short_description: type definitions used throughout Mx
+ *
+ * Common types for MxWidgets.
+ */
+
+
+#ifndef __MX_TYPES_H__
+#define __MX_TYPES_H__
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define MX_TYPE_PADDING               (mx_padding_get_type ())
+
+#define MX_PARAM_TRANSLATEABLE 1 << 8
+
+typedef struct _MxPadding     MxPadding;
+
+/**
+ * MxPadding:
+ * @top: padding from the top
+ * @right: padding from the right
+ * @bottom: padding from the bottom
+ * @left: padding from the left
+ *
+ * The padding from the internal border of the parent container.
+ */
+struct _MxPadding
+{
+  gfloat top;
+  gfloat right;
+  gfloat bottom;
+  gfloat left;
+};
+
+GType mx_padding_get_type (void) G_GNUC_CONST;
+
+
+
+/**
+ * MxAlign:
+ * @MX_ALIGN_START: Align at the beginning of the axis
+ * @MX_ALIGN_MIDDLE: Align in the middle of the axis
+ * @MX_ALIGN_END: Align at the end of the axis
+ *
+ * Set the alignment of the item
+ */
+typedef enum { /*< prefix=MX_ALIGN >*/
+  MX_ALIGN_START,
+  MX_ALIGN_MIDDLE,
+  MX_ALIGN_END
+} MxAlign;
+
+
+G_END_DECLS
+
+#endif /* __MX_TYPES_H__ */
diff --git a/mx/mx-viewport.c b/mx/mx-viewport.c
new file mode 100644
index 0000000..001614f
--- /dev/null
+++ b/mx/mx-viewport.c
@@ -0,0 +1,678 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-viewport.c: Viewport actor
+ *
+ * Copyright 2008 OpenedHand
+ * Copyright 2009, 2010 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ * Port to Mx by: Robert Staudinger <robsta openedhand com>
+ *
+ */
+
+/**
+ * SECTION:mx-viewport
+ * @short_description: single child scrollable container
+ *
+ * #MxViewport allows non-scrollable children (like images or text) 
+ * to be scrollable by implementing the #MxScrollable and #ClutterContainer 
+ * interface.
+ *
+ * To use it, add the non-scrollable child to an #MxViewport; then sit the 
+ * viewport inside an #MxScrollView to get the scrollbars.
+ *
+ * <figure id="mx-viewport">
+ *   <title>#MxViewport around an #MxLabel</title>
+ *   <para>An example of a large label (which isn't normally scrollable), 
+ *   placed inside an #MxViewport, which is in turn inside an #MxScrollView.
+ *   </para>
+ *   <graphic fileref="MxViewport.png" format="PNG"/>
+ * </figure>
+ *
+ * Do not use #MxViewport if you need good performance as it does can not
+ * be selective about the area of its child that is painted/picked. Therefore
+ * if the child is very large or contains a lot of children, you will experience
+ * poor performance.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <clutter/clutter.h>
+
+#include "mx-viewport.h"
+#include "mx-adjustment.h"
+#include "mx-scrollable.h"
+#include "mx-private.h"
+#include "mx-bin.h"
+
+static void scrollable_interface_init (MxScrollableIface *iface);
+
+static void scrollable_set_adjustments (MxScrollable *scrollable,
+                                        MxAdjustment *hadjustment,
+                                        MxAdjustment *vadjustment);
+
+static void scrollable_get_adjustments (MxScrollable  *scrollable,
+                                        MxAdjustment **hadjustment,
+                                        MxAdjustment **vadjustment);
+
+G_DEFINE_TYPE_WITH_CODE (MxViewport, mx_viewport, MX_TYPE_BIN,
+                         G_IMPLEMENT_INTERFACE (MX_TYPE_SCROLLABLE,
+                                                scrollable_interface_init))
+
+#define VIEWPORT_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), MX_TYPE_VIEWPORT, \
+                                MxViewportPrivate))
+
+struct _MxViewportPrivate
+{
+  gfloat        x;
+  gfloat        y;
+  gfloat        z;
+
+  MxAdjustment *hadjustment;
+  MxAdjustment *vadjustment;
+
+  gboolean      sync_adjustments;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_X_ORIGIN,
+  PROP_Y_ORIGIN,
+  PROP_Z_ORIGIN,
+  PROP_HADJUST,
+  PROP_VADJUST,
+  PROP_SYNC_ADJUST
+};
+
+static void
+mx_viewport_get_property (GObject    *object,
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  MxAdjustment *adjustment;
+
+  MxViewportPrivate *priv = MX_VIEWPORT (object)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_X_ORIGIN:
+      g_value_set_float (value, priv->x);
+      break;
+
+    case PROP_Y_ORIGIN:
+      g_value_set_float (value, priv->y);
+      break;
+
+    case PROP_Z_ORIGIN:
+      g_value_set_float (value, priv->z);
+      break;
+
+    case PROP_HADJUST:
+      scrollable_get_adjustments (MX_SCROLLABLE (object), &adjustment, NULL);
+      g_value_set_object (value, adjustment);
+      break;
+
+    case PROP_VADJUST:
+      scrollable_get_adjustments (MX_SCROLLABLE (object), NULL, &adjustment);
+      g_value_set_object (value, adjustment);
+      break;
+
+    case PROP_SYNC_ADJUST:
+      g_value_set_boolean (value, priv->sync_adjustments);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+mx_viewport_set_property (GObject      *object,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  MxViewport *viewport = MX_VIEWPORT (object);
+  MxViewportPrivate *priv = viewport->priv;
+
+  switch (prop_id)
+    {
+    case PROP_X_ORIGIN:
+      mx_viewport_set_origin (viewport,
+                              g_value_get_float (value),
+                              priv->y,
+                              priv->z);
+      break;
+
+    case PROP_Y_ORIGIN:
+      mx_viewport_set_origin (viewport,
+                              priv->x,
+                              g_value_get_float (value),
+                              priv->z);
+      break;
+
+    case PROP_Z_ORIGIN:
+      mx_viewport_set_origin (viewport,
+                              priv->x,
+                              priv->y,
+                              g_value_get_float (value));
+      break;
+
+    case PROP_HADJUST:
+      scrollable_set_adjustments (MX_SCROLLABLE (object),
+                                  g_value_get_object (value),
+                                  priv->vadjustment);
+      break;
+
+    case PROP_VADJUST:
+      scrollable_set_adjustments (MX_SCROLLABLE (object),
+                                  priv->hadjustment,
+                                  g_value_get_object (value));
+      break;
+
+    case PROP_SYNC_ADJUST:
+      mx_viewport_set_sync_adjustments (viewport, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+mx_viewport_dispose (GObject *gobject)
+{
+  MxViewportPrivate *priv = MX_VIEWPORT (gobject)->priv;
+
+  if (priv->hadjustment)
+    {
+      g_object_unref (priv->hadjustment);
+      priv->hadjustment = NULL;
+    }
+
+  if (priv->vadjustment)
+    {
+      g_object_unref (priv->vadjustment);
+      priv->vadjustment = NULL;
+    }
+
+  G_OBJECT_CLASS (mx_viewport_parent_class)->dispose (gobject);
+}
+
+static void
+mx_viewport_paint (ClutterActor *self)
+{
+  MxViewportPrivate *priv = MX_VIEWPORT (self)->priv;
+
+  cogl_push_matrix ();
+
+  cogl_translate ((int) priv->x * -1,
+                  (int) priv->y * -1,
+                  (int) priv->z * -1);
+
+  CLUTTER_ACTOR_CLASS (mx_viewport_parent_class)->paint (self);
+
+  cogl_pop_matrix ();
+}
+
+static void
+mx_viewport_pick (ClutterActor       *self,
+                  const ClutterColor *color)
+{
+  mx_viewport_paint (self);
+}
+
+static void
+mx_viewport_allocate (ClutterActor          *self,
+                      const ClutterActorBox *box,
+                      ClutterAllocationFlags flags)
+{
+  MxViewportPrivate *priv = MX_VIEWPORT (self)->priv;
+  MxPadding padding = { 0, };
+  ClutterActor *child;
+  gfloat width, height;
+  gfloat available_width, available_height;
+
+  /* Chain up. */
+  CLUTTER_ACTOR_CLASS (mx_viewport_parent_class)-> allocate (self, box, flags);
+
+//  mx_widget_get_padding (MX_WIDGET (self), &padding);
+  available_width = box->x2 - box->x1 - padding.left - padding.right;
+  available_height = box->y2 - box->y1 - padding.top - padding.bottom;
+
+  child = mx_bin_get_child (MX_BIN (self));
+
+  if (child)
+    {
+      gfloat natural_width, natural_height;
+      ClutterActorBox child_box;
+      MxAlign x_align, y_align;
+      gboolean x_fill, y_fill;
+
+      clutter_actor_get_preferred_size (child, NULL, NULL, &natural_width,
+                                        &natural_height);
+      mx_bin_get_fill (MX_BIN (self), &x_fill, &y_fill);
+
+      if (x_fill && (available_width > natural_width))
+        width = available_width;
+      else
+        width = natural_width;
+
+      if (y_fill && (available_height > natural_height))
+        height = available_height;
+      else
+        height = natural_height;
+
+      mx_bin_get_alignment (MX_BIN (self), &x_align, &y_align);
+
+      if (!x_fill && width < available_width)
+        {
+          switch (x_align)
+            {
+            case MX_ALIGN_START:
+              child_box.x1 = padding.left;
+              break;
+            case MX_ALIGN_MIDDLE:
+              child_box.x1 = padding.left + (available_width - width) / 2.f;
+              break;
+            case MX_ALIGN_END:
+              child_box.x1 = box->x2 - box->x1 - padding.right - width;
+              break;
+            }
+        }
+      else
+        child_box.x1 = padding.left;
+
+      if (!y_fill && height < available_height)
+        {
+          switch (y_align)
+            {
+            case MX_ALIGN_START:
+              child_box.y1 = padding.top;
+              break;
+            case MX_ALIGN_MIDDLE:
+              child_box.y1 = padding.top + (available_height - height) / 2.f;
+              break;
+            case MX_ALIGN_END:
+              child_box.y1 = box->y2 - box->y1 - padding.bottom - height;
+              break;
+            }
+        }
+      else
+        child_box.y1 = padding.top;
+
+      child_box.x2 = child_box.x1 + width;
+      child_box.y2 = child_box.y1 + height;
+
+      clutter_actor_allocate (child, &child_box, flags);
+    }
+  else
+    {
+      width = 0;
+      height = 0;
+    }
+
+
+
+  /* Refresh adjustments */
+  if (priv->sync_adjustments)
+    {
+      if (priv->hadjustment)
+        {
+          g_object_set (G_OBJECT (priv->hadjustment),
+                        "lower", 0.0,
+                        "page-size", available_width,
+                        "upper", width,
+                        "page-increment", available_width / 3,
+                        "step-increment", available_width / 12,
+                        NULL);
+        }
+
+      if (priv->vadjustment)
+        {
+          g_object_set (G_OBJECT (priv->vadjustment),
+                        "lower", 0.0,
+                        "page-size", available_height,
+                        "upper", height,
+                        "page-increment", available_height / 3,
+                        "step-increment", available_height / 12,
+                        NULL);
+        }
+    }
+}
+
+static void
+mx_viewport_class_init (MxViewportClass *klass)
+{
+  GParamSpec *pspec;
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (MxViewportPrivate));
+
+  gobject_class->get_property = mx_viewport_get_property;
+  gobject_class->set_property = mx_viewport_set_property;
+  gobject_class->dispose = mx_viewport_dispose;
+
+  actor_class->paint = mx_viewport_paint;
+  actor_class->pick = mx_viewport_pick;
+  actor_class->allocate = mx_viewport_allocate;
+
+
+  pspec = g_param_spec_float ("x-origin",
+                              "X Origin",
+                              "Origin's X coordinate in pixels",
+                              -G_MAXFLOAT, G_MAXFLOAT, 0,
+                              MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_X_ORIGIN, pspec);
+
+  pspec = g_param_spec_float ("y-origin",
+                              "Y Origin",
+                              "Origin's Y coordinate in pixels",
+                              -G_MAXFLOAT, G_MAXFLOAT, 0,
+                              MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_Y_ORIGIN, pspec);
+
+  pspec = g_param_spec_float ("z-origin",
+                              "Z Origin",
+                              "Origin's Z coordinate in pixels",
+                              -G_MAXFLOAT, G_MAXFLOAT, 0,
+                              MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_Z_ORIGIN, pspec);
+
+  pspec = g_param_spec_boolean ("sync-adjustments",
+                                "Synchronise adjustments",
+                                "Whether to synchronise adjustments with "
+                                "viewport size",
+                                TRUE,
+                                MX_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_SYNC_ADJUST, pspec);
+
+  g_object_class_override_property (gobject_class,
+                                    PROP_HADJUST,
+                                    "horizontal-adjustment");
+
+  g_object_class_override_property (gobject_class,
+                                    PROP_VADJUST,
+                                    "vertical-adjustment");
+}
+
+static void
+hadjustment_value_notify_cb (MxAdjustment *adjustment,
+                             GParamSpec   *pspec,
+                             MxViewport   *viewport)
+{
+  MxViewportPrivate *priv = viewport->priv;
+  gdouble value;
+
+  value = mx_adjustment_get_value (adjustment);
+
+  mx_viewport_set_origin (viewport,
+                          (float)(value),
+                          priv->y,
+                          priv->z);
+}
+
+static void
+vadjustment_value_notify_cb (MxAdjustment *adjustment,
+                             GParamSpec   *arg1,
+                             MxViewport   *viewport)
+{
+  MxViewportPrivate *priv = viewport->priv;
+  gdouble value;
+
+  value = mx_adjustment_get_value (adjustment);
+
+  mx_viewport_set_origin (viewport,
+                          priv->x,
+                          (float)(value),
+                          priv->z);
+}
+
+static void
+scrollable_set_adjustments (MxScrollable *scrollable,
+                            MxAdjustment *hadjustment,
+                            MxAdjustment *vadjustment)
+{
+  MxViewportPrivate *priv = MX_VIEWPORT (scrollable)->priv;
+
+  if (hadjustment != priv->hadjustment)
+    {
+      if (priv->hadjustment)
+        {
+          g_signal_handlers_disconnect_by_func (priv->hadjustment,
+                                                hadjustment_value_notify_cb,
+                                                scrollable);
+          g_object_unref (priv->hadjustment);
+        }
+
+      if (hadjustment)
+        {
+          g_object_ref (hadjustment);
+          g_signal_connect (hadjustment, "notify::value",
+                            G_CALLBACK (hadjustment_value_notify_cb),
+                            scrollable);
+        }
+
+      priv->hadjustment = hadjustment;
+    }
+
+  if (vadjustment != priv->vadjustment)
+    {
+      if (priv->vadjustment)
+        {
+          g_signal_handlers_disconnect_by_func (priv->vadjustment,
+                                                vadjustment_value_notify_cb,
+                                                scrollable);
+          g_object_unref (priv->vadjustment);
+        }
+
+      if (vadjustment)
+        {
+          g_object_ref (vadjustment);
+          g_signal_connect (vadjustment, "notify::value",
+                            G_CALLBACK (vadjustment_value_notify_cb),
+                            scrollable);
+        }
+
+      priv->vadjustment = vadjustment;
+    }
+}
+
+static void
+scrollable_get_adjustments (MxScrollable  *scrollable,
+                            MxAdjustment **hadjustment,
+                            MxAdjustment **vadjustment)
+{
+  MxViewportPrivate *priv;
+
+  g_return_if_fail (MX_IS_VIEWPORT (scrollable));
+
+  priv = ((MxViewport *) scrollable)->priv;
+
+  if (hadjustment)
+    {
+      if (priv->hadjustment)
+        *hadjustment = priv->hadjustment;
+      else
+        {
+          MxAdjustment *adjustment;
+
+          /* create an initial adjustment. this is filled with correct values
+           * as soon as allocate() is called */
+
+          adjustment = mx_adjustment_new ();
+
+          scrollable_set_adjustments (scrollable,
+                                      adjustment,
+                                      priv->vadjustment);
+
+          g_object_unref (adjustment);
+
+          *hadjustment = adjustment;
+        }
+    }
+
+  if (vadjustment)
+    {
+      if (priv->vadjustment)
+        *vadjustment = priv->vadjustment;
+      else
+        {
+          MxAdjustment *adjustment;
+
+          /* create an initial adjustment. this is filled with correct values
+           * as soon as allocate() is called */
+
+          adjustment = mx_adjustment_new ();
+
+          scrollable_set_adjustments (scrollable,
+                                      priv->hadjustment,
+                                      adjustment);
+
+          g_object_unref (adjustment);
+
+          *vadjustment = adjustment;
+        }
+    }
+}
+
+static void
+scrollable_interface_init (MxScrollableIface *iface)
+{
+  iface->set_adjustments = scrollable_set_adjustments;
+  iface->get_adjustments = scrollable_get_adjustments;
+}
+
+static void
+mx_viewport_init (MxViewport *self)
+{
+  self->priv = VIEWPORT_PRIVATE (self);
+
+  self->priv->sync_adjustments = TRUE;
+
+  g_object_set (G_OBJECT (self),
+                "reactive", FALSE,
+                "clip-to-allocation", TRUE,
+                "x-align", MX_ALIGN_START,
+                "y-align", MX_ALIGN_START,
+                NULL);
+}
+
+ClutterActor *
+mx_viewport_new (void)
+{
+  return g_object_new (MX_TYPE_VIEWPORT, NULL);
+}
+
+void
+mx_viewport_set_origin (MxViewport *viewport,
+                        gfloat      x,
+                        gfloat      y,
+                        gfloat      z)
+{
+  MxViewportPrivate *priv;
+
+  g_return_if_fail (MX_IS_VIEWPORT (viewport));
+
+  priv = viewport->priv;
+
+  g_object_freeze_notify (G_OBJECT (viewport));
+
+  if (x != priv->x)
+    {
+      priv->x = x;
+      g_object_notify (G_OBJECT (viewport), "x-origin");
+
+      if (priv->hadjustment)
+        mx_adjustment_set_value (priv->hadjustment,
+                                 (float)(x));
+    }
+
+  if (y != priv->y)
+    {
+      priv->y = y;
+      g_object_notify (G_OBJECT (viewport), "y-origin");
+
+      if (priv->vadjustment)
+        mx_adjustment_set_value (priv->vadjustment,
+                                 (float)(y));
+    }
+
+  if (z != priv->z)
+    {
+      priv->z = z;
+      g_object_notify (G_OBJECT (viewport), "z-origin");
+    }
+
+  g_object_thaw_notify (G_OBJECT (viewport));
+
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (viewport));
+}
+
+void
+mx_viewport_get_origin (MxViewport *viewport,
+                        gfloat     *x,
+                        gfloat     *y,
+                        gfloat     *z)
+{
+  MxViewportPrivate *priv;
+
+  g_return_if_fail (MX_IS_VIEWPORT (viewport));
+
+  priv = viewport->priv;
+
+  if (x)
+    *x = priv->x;
+
+  if (y)
+    *y = priv->y;
+
+  if (z)
+    *z = priv->z;
+}
+
+void
+mx_viewport_set_sync_adjustments (MxViewport *viewport,
+                                  gboolean    sync_adjustments)
+{
+  MxViewportPrivate *priv;
+
+  g_return_if_fail (MX_IS_VIEWPORT (viewport));
+
+  priv = viewport->priv;
+  if (priv->sync_adjustments != sync_adjustments)
+    {
+      priv->sync_adjustments = sync_adjustments;
+      g_object_notify (G_OBJECT (viewport), "sync-adjustments");
+    }
+}
+
+gboolean
+mx_viewport_get_sync_adjustments (MxViewport *viewport)
+{
+  g_return_val_if_fail (MX_IS_VIEWPORT (viewport), FALSE);
+  return viewport->priv->sync_adjustments;
+}
diff --git a/mx/mx-viewport.h b/mx/mx-viewport.h
new file mode 100644
index 0000000..7b4042b
--- /dev/null
+++ b/mx/mx-viewport.h
@@ -0,0 +1,91 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * mx-viewport.h: Viewport actor
+ *
+ * Copyright 2008 OpenedHand
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ * Port to Mx by: Robert Staudinger <robsta openedhand com>
+ *
+ */
+
+#ifndef __MX_VIEWPORT_H__
+#define __MX_VIEWPORT_H__
+
+#include <clutter/clutter.h>
+#include "mx-bin.h"
+
+G_BEGIN_DECLS
+
+#define MX_TYPE_VIEWPORT            (mx_viewport_get_type())
+#define MX_VIEWPORT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MX_TYPE_VIEWPORT, MxViewport))
+#define MX_IS_VIEWPORT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MX_TYPE_VIEWPORT))
+#define MX_VIEWPORT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MX_TYPE_VIEWPORT, MxViewportClass))
+#define MX_IS_VIEWPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MX_TYPE_VIEWPORT))
+#define MX_VIEWPORT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MX_TYPE_VIEWPORT, MxViewportClass))
+
+typedef struct _MxViewport          MxViewport;
+typedef struct _MxViewportPrivate   MxViewportPrivate;
+typedef struct _MxViewportClass     MxViewportClass;
+
+/**
+ * MxViewport:
+ *
+ * The contents of this structure are private and should only be accessed
+ * through the public API.
+ */
+struct _MxViewport
+{
+  /*< private >*/
+  MxBin parent;
+
+  MxViewportPrivate *priv;
+};
+
+struct _MxViewportClass
+{
+  MxBinClass parent_class;
+
+  /* padding for future expansion */
+  void (*_padding_0) (void);
+  void (*_padding_1) (void);
+  void (*_padding_2) (void);
+  void (*_padding_3) (void);
+  void (*_padding_4) (void);
+};
+
+GType mx_viewport_get_type (void) G_GNUC_CONST;
+
+ClutterActor *mx_viewport_new (void);
+
+void mx_viewport_set_origin (MxViewport *viewport,
+                             gfloat      x,
+                             gfloat      y,
+                             gfloat      z);
+void mx_viewport_get_origin (MxViewport *viewport,
+                             gfloat     *x,
+                             gfloat     *y,
+                             gfloat     *z);
+
+void mx_viewport_set_sync_adjustments (MxViewport *viewport,
+                                       gboolean    sync);
+gboolean mx_viewport_get_sync_adjustments (MxViewport *viewport);
+
+G_END_DECLS
+
+#endif /* __MX_VIEWPORT_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]