]> err.no Git - libchamplain/commitdiff
Compiling Tidy integration
authorPierre-Luc Beaudoin <pierre-luc@squidy.info>
Sat, 16 Aug 2008 01:16:30 +0000 (21:16 -0400)
committerPierre-Luc Beaudoin <pierre-luc@squidy.info>
Sat, 16 Aug 2008 01:16:30 +0000 (21:16 -0400)
24 files changed:
Makefile.am
config.h.in
configure.ac
src/Makefile.am
src/champlain_private.h
src/champlain_widget.c
tidy/Makefile.am [new file with mode: 0644]
tidy/tidy-adjustment.c [new file with mode: 0644]
tidy/tidy-adjustment.h [new file with mode: 0644]
tidy/tidy-debug.h [new file with mode: 0644]
tidy/tidy-enum-types.c.in [new file with mode: 0644]
tidy/tidy-enum-types.h.in [new file with mode: 0644]
tidy/tidy-finger-scroll.c [new file with mode: 0644]
tidy/tidy-finger-scroll.h [new file with mode: 0644]
tidy/tidy-marshal.c [new file with mode: 0644]
tidy/tidy-marshal.h [new file with mode: 0644]
tidy/tidy-marshal.list [new file with mode: 0644]
tidy/tidy-private.h [new file with mode: 0644]
tidy/tidy-scroll-view.c [new file with mode: 0644]
tidy/tidy-scroll-view.h [new file with mode: 0644]
tidy/tidy-scrollable.c [new file with mode: 0644]
tidy/tidy-scrollable.h [new file with mode: 0644]
tidy/tidy-viewport.c [new file with mode: 0644]
tidy/tidy-viewport.h [new file with mode: 0644]

index af437a64d6d80a47ea903fd842a648fc59cbcd9a..5c179c2152f884a23ceeffe60286957dc6bfb463 100644 (file)
@@ -1 +1 @@
-SUBDIRS = src
+SUBDIRS = tidy src 
index c364eda452065738703c0071054ddf27c4a00954..09ee04cec204f33198751b569bd1a340347b7b11 100644 (file)
@@ -1,5 +1,35 @@
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
 /* Name of package */
 #undef PACKAGE
 
@@ -18,5 +48,8 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
 /* Version number of package */
 #undef VERSION
index 934c87d1c5134885b53c4ccd9466e36b79ed06a3..4699df4309ec72d1cf3c130b802f12dc65e72176 100644 (file)
@@ -9,6 +9,7 @@ AC_CONFIG_HEADER([config.h])
 AM_INIT_AUTOMAKE
 AC_LIBTOOL_DLOPEN
 AC_LIBLTDL_CONVENIENCE
+AM_PROG_LIBTOOL
 
 # Checks for programs.
 AC_PROG_CC
@@ -20,7 +21,7 @@ AC_SUBST(DEPS_CFLAGS)
 AC_SUBST(DEPS_LIBS)
 
 PKG_CHECK_MODULES(DEPS,
-       [ glib-2.0 >= 2.2,
+       [   glib-2.0 >= 2.2,
       gobject-2.0 >= 2.10,
       gtk+-2.0 >= 2.2,
       clutter-0.8 >= 0.8,
@@ -35,5 +36,6 @@ PKG_CHECK_MODULES(DEPS,
 # Checks for library functions.
 
 AC_CONFIG_FILES([Makefile
-                 src/Makefile])
+                 src/Makefile
+                 tidy/Makefile])
 AC_OUTPUT
index 77d7ce5e426a4368fe18b6a3ef3842183a3fde93..db2b1cae96529ded601184067ddb06ad711febc9 100644 (file)
@@ -21,8 +21,8 @@ champlain_SOURCES = $(CHAMPLAIN_MARSHAL_LIST) \
                                        launcher.c
                                        
 
-champlain_LDADD = $(DEPS_LIBS)
-AM_CPPFLAGS = $(DEPS_CFLAGS)
+champlain_LDADD = $(DEPS_LIBS) ../tidy/libtidy-1.0.la
+AM_CPPFLAGS = $(DEPS_CFLAGS) -I../tidy
 
 
 EXTRA_DIST = $(CHAMPLAIN_MARSHAL_LIST)
index 1a0568f13f37bff36fcd414bdc1b7d741571cf76..6bf6132288f2e15375b6f1f27b6df1c835dc4b67 100644 (file)
 #ifndef CHAMPLAIN_PRIVATE_H
 #define CHAMPLAIN_PRIVATE_H
 
+#include <clutter/clutter.h>
+#include <clutter/clutter.h>
+
 void champlain_map_create_tiles(gint zoom_level);
 
 ChamplainMapZoomLevel* champlain_map_zoom_level_new(gint zoom_level, gint row, gint column, gint tile_size);
 
+//gboolean tile_is_visible(ClutterUnit viewport_w, ClutterUnit viewport_h, ChamplainPoint position, ChamplainMapTile* tile);
+
 ChamplainMapTile* champlain_map_tile_new(gint x, gint y, gint tile_size);
 
 #endif
index a58e37a28d0222222ac32fc309d89abdcd0b49e1..9d3416f865cd7e7cc9b3ecd386b3d9c51c9b2afc 100644 (file)
@@ -25,6 +25,7 @@
 #include "champlain_widget.h"
 #include "champlain-marshal.h"
 
+#include <tidy-finger-scroll.h>
 #include <math.h>
 #include <glib.h>
 #include <glib-object.h>
@@ -59,8 +60,6 @@ typedef struct
 struct _ChamplainWidgetPrivate
 {
   GtkWidget *clutterEmbed;
-  GtkAdjustment *horizontalAdjustment;
-  GtkAdjustment *verticalAdjustment;
   ClutterActor *viewport;
 
   // Scrolling  
@@ -73,67 +72,7 @@ struct _ChamplainWidgetPrivate
 
 G_DEFINE_TYPE (ChamplainWidget, champlain_widget, GTK_TYPE_ALIGNMENT);
 
-static void
-adjustement_changed_cb (GtkAdjustment * adjustment, ChamplainWidgetPrivate * champlainWidget)
-{
-  ChamplainWidgetPrivate *priv = CHAMPLAIN_WIDGET_GET_PRIVATE (champlainWidget);
-  /*
-     if (adjustment == priv->horizontalAdjustment)
-     priv->scrollOffset.x = (int)gtk_adjustment_get_value(adjustment);
-     else if (adjustment == priv->verticalAdjustment)
-     priv->scrollOffset.y = (int)gtk_adjustment_get_value(adjustment);
-   */
-  // Check if the offset is empty
 
-}
-
-static void
-champlain_widget_set_scroll_adjustments (ChamplainWidget * champlainWidget,
-                                        GtkAdjustment * hadjustment, GtkAdjustment * vadjustment)
-{
-  ChamplainWidgetPrivate *priv = CHAMPLAIN_WIDGET_GET_PRIVATE (champlainWidget);
-
-  if (priv->horizontalAdjustment)
-    {
-      g_signal_handlers_disconnect_by_func (G_OBJECT
-                                           (priv->horizontalAdjustment),
-                                           (gpointer) adjustement_changed_cb, champlainWidget);
-      g_signal_handlers_disconnect_by_func (G_OBJECT
-                                           (priv->verticalAdjustment),
-                                           (gpointer) adjustement_changed_cb, champlainWidget);
-
-      g_object_unref (priv->horizontalAdjustment);
-      g_object_unref (priv->verticalAdjustment);
-    }
-
-  priv->horizontalAdjustment = hadjustment;
-  priv->verticalAdjustment = vadjustment;
-
-  if (hadjustment)
-    {
-      g_object_ref_sink (priv->horizontalAdjustment);
-      g_object_ref_sink (priv->verticalAdjustment);
-
-      gdouble val = gtk_adjustment_get_value (hadjustment);
-      val = gtk_adjustment_get_value (vadjustment);
-      // Connect the signals
-
-      g_object_set (G_OBJECT (priv->horizontalAdjustment), "lower", -180.0, NULL);
-      g_object_set (G_OBJECT (priv->horizontalAdjustment), "upper", 180.0, NULL);
-      g_object_set (G_OBJECT (priv->horizontalAdjustment), "page-size", 20.0, NULL);
-      g_object_set (G_OBJECT (priv->horizontalAdjustment), "step-increment", 5.0, NULL);
-      g_object_set (G_OBJECT (priv->horizontalAdjustment), "page-increment", 15.0, NULL);
-
-      g_object_set (G_OBJECT (priv->verticalAdjustment), "lower", -90.0, NULL);
-      g_object_set (G_OBJECT (priv->verticalAdjustment), "upper", 90.0, NULL);
-      g_object_set (G_OBJECT (priv->verticalAdjustment), "page-size", 20.0, NULL);
-      g_object_set (G_OBJECT (priv->verticalAdjustment), "step-increment", 5.0, NULL);
-      g_object_set (G_OBJECT (priv->verticalAdjustment), "page-increment", 15.0, NULL);
-
-      //g_signal_connect(G_OBJECT(priv->horizontalAdjustment), "value-changed", (gpointer)adjustement_changed_cb, champlainWidget);
-      //g_signal_connect(G_OBJECT(priv->verticalAdjustment), "value-changed", (gpointer)adjustement_changed_cb, champlainWidget);
-    }
-}
 
 static void
 champlain_widget_finalize (GObject * object)
@@ -141,20 +80,6 @@ champlain_widget_finalize (GObject * object)
   ChamplainWidget *widget = CHAMPLAIN_WIDGET (object);
   ChamplainWidgetPrivate *priv = CHAMPLAIN_WIDGET_GET_PRIVATE (widget);
 
-  if (priv->horizontalAdjustment)
-    {
-      g_object_unref (priv->horizontalAdjustment);
-      //g_signal_handlers_disconnect_by_func (G_OBJECT
-                       //                  (priv->horizontalAdjustment), (gpointer) adjustement_changed_cb, widget);
-    }
-
-  if (priv->verticalAdjustment)
-    {
-      g_object_unref (priv->verticalAdjustment);
-      //g_signal_handlers_disconnect_by_func (G_OBJECT
-                       //                  (priv->verticalAdjustment), (gpointer) adjustement_changed_cb, widget);
-    }
-
   G_OBJECT_CLASS (champlain_widget_parent_class)->finalize (object);
 }
 
@@ -163,18 +88,6 @@ champlain_widget_class_init (ChamplainWidgetClass * champlainWidgetClass)
 {
   g_type_class_add_private (champlainWidgetClass, sizeof (ChamplainWidgetPrivate));
 
-  /*
-   * make us scrollable (e.g. addable to a GtkScrolledWindow)
-   */
-  champlainWidgetClass->set_scroll_adjustments = champlain_widget_set_scroll_adjustments;
-  GTK_WIDGET_CLASS (champlainWidgetClass)->set_scroll_adjustments_signal =
-    g_signal_new ("set-scroll-adjustments",
-                 G_TYPE_FROM_CLASS (champlainWidgetClass),
-                 (GSignalFlags) (G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
-                 G_STRUCT_OFFSET (ChamplainWidgetClass,
-                                  set_scroll_adjustments), NULL, NULL,
-                 champlain_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
-
   GObjectClass *objectClass = G_OBJECT_CLASS (champlainWidgetClass);
   objectClass->finalize = champlain_widget_finalize;
 }
@@ -183,86 +96,6 @@ static void
 champlain_widget_init (ChamplainWidget * champlainWidget)
 {
   ChamplainWidgetPrivate *priv = CHAMPLAIN_WIDGET_GET_PRIVATE (champlainWidget);
-
-  priv->horizontalAdjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
-  priv->verticalAdjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
-
-  g_object_ref_sink (priv->horizontalAdjustment);
-  g_object_ref_sink (priv->verticalAdjustment);
-
-
-}
-
-static gboolean
-tile_is_visible(ClutterUnit viewport_w, ClutterUnit viewport_h, ChamplainPoint position, ChamplainMapTile* tile)
-{
-       ClutterUnit size = CLUTTER_UNITS_FROM_INT(tile->size);
-
-      
-       if( ((tile->x + 1)* size + position.x < 0 || tile->x* size + position.x > viewport_w) ||
-                       ((tile->y + 1)* size + position.y < 0 || tile->y* size + position.y > viewport_h))
-               {
-                       g_print ("Tile I: %d, %d\t p: %d, %d \n",
-              tile->x, tile->y,
-              CLUTTER_UNITS_TO_INT (position.x),
-              CLUTTER_UNITS_TO_INT (position.y));
-                       return FALSE;
-               }
-       g_print ("Tile V: %d, %d\t p: %d, %d \n",
-              tile->x, tile->y,
-              CLUTTER_UNITS_TO_INT (position.x),
-              CLUTTER_UNITS_TO_INT (position.y));
-       return TRUE;
-
-}
-
-static void
-champlain_widget_verify_tiles (ChamplainWidget * champlainWidget)
-{
-  ChamplainWidgetPrivate *priv = CHAMPLAIN_WIDGET_GET_PRIVATE (champlainWidget);
-  ClutterActor *stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (priv->clutterEmbed));
-  ClutterUnit stage_w, stage_h;
-  clutter_actor_get_sizeu(stage, &stage_w, &stage_h);
-  g_print("Stage: %d, %d\n", CLUTTER_UNITS_TO_INT(stage_w), CLUTTER_UNITS_TO_INT(stage_h));
-  // Check for tiles that left the viewport
-  
-  int i;
-  int tile_count = priv->map->current_level->tiles->len;
-  for (i = 0; i < tile_count; i++) 
-               {
-               ChamplainMapTile* tile = g_ptr_array_index (priv->map->current_level->tiles, i);
-               if (tile_is_visible(stage_w, stage_h, priv->position, tile))
-                       {
-                               if(!tile->visible) 
-                                       {
-                                                       tile->visible = TRUE;
-                                                       clutter_container_add (CLUTTER_CONTAINER (priv->map->current_level->group), tile->actor, NULL);
-                                               }
-                       }
-                       else 
-                       {
-                               if (tile->visible) 
-                                       {
-                                                       clutter_container_remove_actor (CLUTTER_CONTAINER (priv->map->current_level->group), tile->actor);
-                                                       tile->visible = FALSE;
-                                               }
-                       }
-               }
-               
-               
-  // Check for missing tiles in the viewport
-  /*if ( priv->position.x > 0 )
-       {
-               gboolean exist = FALSE;
-                       for (i = 0; i < 20; i++) 
-                               {
-                                       ClutterActor * tile = CLUTTER_ACTOR(g_ptr_array_index (priv->tiles, i));
-                                       ClutterUnit actor_x, actor_y;
-                               clutter_actor_get_positionu(tile, &actor_x, &actor_y);
-                                       //if (actor_x < 0
-                               }
-  
-       }*/
 }
 
 static gboolean
@@ -284,17 +117,22 @@ viewport_motion_event_cb (ClutterActor * actor, ClutterMotionEvent * event, Cham
       dx = x - priv->position.x;
       dy = y - priv->position.y;
 
-      //g_print ("Motion n: %d, %d\t c: %d, %d \t d: %d, %d\n",
-           //   CLUTTER_UNITS_TO_INT (x), CLUTTER_UNITS_TO_INT (y),
-           //   CLUTTER_UNITS_TO_INT (priv->position.x),
-           //   CLUTTER_UNITS_TO_INT (priv->position.y), CLUTTER_UNITS_TO_INT (dx), CLUTTER_UNITS_TO_INT (dy));
+      /*g_print ("Motion n: %d, %d\t c: %d, %d \t d: %d, %d\t h: %d, %d\n",
+              CLUTTER_UNITS_TO_INT (x), 
+              CLUTTER_UNITS_TO_INT (y),
+              CLUTTER_UNITS_TO_INT (priv->position.x),
+              CLUTTER_UNITS_TO_INT (priv->position.y), 
+              CLUTTER_UNITS_TO_INT (dx), 
+              CLUTTER_UNITS_TO_INT (dy),
+              CLUTTER_UNITS_TO_INT (priv->hitPoint.x), 
+              CLUTTER_UNITS_TO_INT (priv->hitPoint.y));*/
 
       priv->position.x += dx - priv->hitPoint.x;
       priv->position.y += dy - priv->hitPoint.y;
 
       clutter_actor_set_positionu (priv->viewport, priv->position.x, priv->position.y);
-      champlain_widget_verify_tiles(champlainWidget);
-    }
+      
+    } else g_print("Couldn't convert point");
 
   return TRUE;
 }
@@ -348,6 +186,9 @@ viewport_captured_event_cb (ClutterActor * actor, ClutterEvent * event, Champlai
   if (event->type == CLUTTER_BUTTON_PRESS)
     {
       ClutterButtonEvent *bevent = (ClutterButtonEvent *) event;
+                               g_print ("d: %d, %d \n", 
+                                       bevent->x, 
+                                       bevent->y);
       ClutterUnit x, y;
       if ((bevent->button == 1) &&
                                (clutter_actor_transform_stage_point (stage,
@@ -355,9 +196,14 @@ viewport_captured_event_cb (ClutterActor * actor, ClutterEvent * event, Champlai
                                                (bevent->x), CLUTTER_UNITS_FROM_DEVICE (bevent->y), &x, &y)))
                        {
 
-                               //g_print ("Hit h: %d, %d\t c: %d, %d \n", CLUTTER_UNITS_TO_INT (x),
-                               //       CLUTTER_UNITS_TO_INT (y),
-                               //       CLUTTER_UNITS_TO_INT (priv->position.x), CLUTTER_UNITS_TO_INT (priv->position.y));
+                               g_print ("Hit h: %d, %d\t c: %d, %d \t d: %d, %d \n", 
+                                       CLUTTER_UNITS_TO_INT (x),
+                                       CLUTTER_UNITS_TO_INT (y),
+                                       CLUTTER_UNITS_TO_INT (priv->position.x), 
+                                       CLUTTER_UNITS_TO_INT (priv->position.y),
+                                       bevent->x, 
+                                       bevent->y);
+                                       
                                priv->hitPoint.x = x - priv->position.x;
                                priv->hitPoint.y = y - priv->position.y;
 
@@ -372,6 +218,7 @@ viewport_captured_event_cb (ClutterActor * actor, ClutterEvent * event, Champlai
                                g_signal_connect (priv->viewport,
                                                        "button-release-event", G_CALLBACK (viewport_button_release_event_cb), champlainWidget);
                        }
+                       else g_print("Couldn't convert point");
     }
 
   return FALSE;
@@ -387,7 +234,7 @@ champlain_widget_load_map (ChamplainWidget * champlainWidget)
        champlain_map_load(priv->map, 1);
        
   clutter_container_add_actor (CLUTTER_CONTAINER (priv->viewport), priv->map->current_level->group);
-       champlain_widget_verify_tiles (champlainWidget);
+       
 }
 
 GtkWidget *
@@ -400,19 +247,14 @@ champlain_widget_new ()
 
        /* Setup stage */
   ClutterActor *stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (priv->clutterEmbed));
+  
   ClutterColor black;
   clutter_color_parse ("black", &black);
   clutter_stage_set_color (CLUTTER_STAGE (stage), &black);
   gtk_container_add (GTK_CONTAINER (widget), priv->clutterEmbed);
-
-       /* Setup viewport */
-       priv->viewport = clutter_group_new ();
-  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->viewport), TRUE);
-  g_signal_connect (CLUTTER_ACTOR (priv->viewport),
-                   "captured-event", G_CALLBACK (viewport_captured_event_cb), widget);
-  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->viewport);
   
-  champlain_widget_load_map (widget);
+  ClutterActor* finger_scroll = tidy_finger_scroll_new(TIDY_FINGER_SCROLL_MODE_PUSH);
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), finger_scroll);
   
   return GTK_WIDGET (widget);
 }
diff --git a/tidy/Makefile.am b/tidy/Makefile.am
new file mode 100644 (file)
index 0000000..67a5161
--- /dev/null
@@ -0,0 +1,112 @@
+NULL =
+
+GLIB_GENMARSHAL = `pkg-config --variable=glib_genmarshal glib-2.0`
+GLIB_MKENUMS = `pkg-config --variable=glib_mkenums glib-2.0`
+
+INCLUDES = \
+       -I$(top_srcdir)                 \
+       -DPREFIX=\""$(prefix)"\"        \
+       -DLIBDIR=\""$(libdir)"\"        \
+       -DG_DISABLE_DEPRECATED          \
+       -DG_LOG_DOMAIN=\"Tidy\"         \
+       $(DEPS_CFLAGS)                  \
+       $(TIDY_DEBUG_CFLAGS)            \
+       $(NULL)
+
+LDADD = $(TIDY_LT_LDFLAGS) -export-dynamic -rpath $(libdir)
+
+BUILT_SOURCES = \
+       tidy-enum-types.h       \
+       tidy-enum-types.c       \
+       tidy-marshal.h          \
+       tidy-marshal.c
+
+STAMP_FILES = stamp-tidy-marshal.h stamp-tidy-enum-types.h
+
+# please, keep this sorted alphabetically
+source_h = \
+       $(top_srcdir)/tidy/tidy-adjustment.h            \
+       $(top_srcdir)/tidy/tidy-finger-scroll.h         \
+       $(top_srcdir)/tidy/tidy-scrollable.h            \
+       $(top_srcdir)/tidy/tidy-scroll-view.h           \
+       $(top_srcdir)/tidy/tidy-viewport.h              \
+       $(NULL)
+
+source_h_private = \
+       tidy-debug.h \
+       $(NULL)
+
+# please, keep this sorted alphabetically
+source_c = \
+       tidy-adjustment.c \
+       tidy-finger-scroll.c \
+       tidy-scroll-view.c \
+       tidy-scrollable.c \
+       tidy-viewport.c \
+       $(NULL)
+
+tidy-marshal.h: stamp-tidy-marshal.h
+       @true
+stamp-tidy-marshal.h: Makefile tidy-marshal.list
+       $(GLIB_GENMARSHAL) \
+               --prefix=_tidy_marshal \
+               --header \
+       $(srcdir)/tidy-marshal.list > xgen-tmh && \
+       (cmp -s xgen-tmh tidy-marshal.h || cp -f xgen-tmh tidy-marshal.h) && \
+       rm -f xgen-tmh && \
+       echo timestamp > $(@F)
+
+tidy-marshal.c: Makefile tidy-marshal.list
+       (echo "#include \"tidy-marshal.h\"" ; \
+        $(GLIB_GENMARSHAL) \
+               --prefix=_tidy_marshal \
+               --body \
+        $(srcdir)/tidy-marshal.list ) > xgen-tmc && \
+       cp -f xgen-tmc tidy-marshal.c && \
+       rm -f xgen-tmc
+
+tidy-enum-types.h: stamp-tidy-enum-types.h Makefile
+       @true
+stamp-tidy-enum-types.h: $(source_h) tidy-enum-types.h.in
+       ( cd $(srcdir) && \
+         $(GLIB_MKENUMS) \
+           --template $(srcdir)/tidy-enum-types.h.in \
+         $(source_h) ) >> xgen-teth && \
+       (cmp xgen-teth tidy-enum-types.h || cp xgen-teth tidy-enum-types.h) && \
+       rm -f xgen-teth && \
+       echo timestamp > $(@F)
+
+tidy-enum-types.c: stamp-tidy-enum-types.h tidy-enum-types.c.in
+       ( cd $(srcdir) && \
+         $(GLIB_MKENUMS) \
+           --template $(srcdir)/tidy-enum-types.c.in \
+         $(source_h) ) >> xgen-tetc && \
+       cp xgen-tetc tidy-enum-types.c && \
+       rm -f xgen-tetc
+
+lib_LTLIBRARIES = libtidy-1.0.la
+
+libtidy_1_0_la_LIBADD = $(DEPS_LIBS)
+libtidy_1_0_la_SOURCES = \
+       $(source_c) \
+       $(source_h) \
+       $(source_h_priv) \
+       $(BUILT_SOURCES) \
+       $(NULL)
+libtidy_1_0_la_LDFLAGS = $(TIDY_LT_LDFLAGS)
+
+tidyincludedir = $(includedir)/tidy-1.0/tidy
+tidyinclude_DATA = \
+       $(source_h) \
+       $(top_srcdir)/tidy/tidy-enum-types.h \
+       $(NULL)
+
+CLEANFILES = $(STAMP_FILES) $(BUILT_SOURCES)
+
+DISTCLEANFILES = tidy-version.h
+
+EXTRA_DIST = \
+       tidy-enum-types.h.in \
+       tidy-enum-types.c.in \
+       tidy-marshal.list
+
diff --git a/tidy/tidy-adjustment.c b/tidy/tidy-adjustment.c
new file mode 100644 (file)
index 0000000..f681716
--- /dev/null
@@ -0,0 +1,849 @@
+/* tidy-adjustment.c: Adjustment object
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>, inspired by GtkAdjustment
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib-object.h>
+#include <clutter/clutter-alpha.h>
+#include <clutter/clutter-fixed.h>
+#include <clutter/clutter-timeline.h>
+
+#include "tidy-adjustment.h"
+#include "tidy-marshal.h"
+#include "tidy-private.h"
+
+G_DEFINE_TYPE (TidyAdjustment, tidy_adjustment, G_TYPE_OBJECT)
+
+#define ADJUSTMENT_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TIDY_TYPE_ADJUSTMENT, TidyAdjustmentPrivate))
+
+struct _TidyAdjustmentPrivate
+{
+  ClutterFixed lower;
+  ClutterFixed upper;
+  ClutterFixed value;
+  ClutterFixed step_increment;
+  ClutterFixed page_increment;
+  ClutterFixed page_size;
+
+  /* For interpolation */
+  ClutterTimeline *interpolation;
+  ClutterFixed     dx;
+  ClutterFixed     old_position;
+  ClutterFixed     new_position;
+  
+  /* For elasticity */
+  gboolean      elastic;
+  guint         bounce_source;
+  ClutterAlpha *bounce_alpha;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_LOWER,
+  PROP_UPPER,
+  PROP_VALUE,
+  PROP_STEP_INC,
+  PROP_PAGE_INC,
+  PROP_PAGE_SIZE,
+  
+  PROP_ELASTIC,
+};
+
+enum
+{
+  CHANGED,
+
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static void tidy_adjustment_set_lower          (TidyAdjustment *adjustment,
+                                                gdouble         lower);
+static void tidy_adjustment_set_upper          (TidyAdjustment *adjustment,
+                                                gdouble         upper);
+static void tidy_adjustment_set_step_increment (TidyAdjustment *adjustment,
+                                                gdouble         step);
+static void tidy_adjustment_set_page_increment (TidyAdjustment *adjustment,
+                                                gdouble         page);
+static void tidy_adjustment_set_page_size      (TidyAdjustment *adjustment,
+                                                gdouble         size);
+
+static void
+tidy_adjustment_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  TidyAdjustmentPrivate *priv = TIDY_ADJUSTMENT (object)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_LOWER:
+      g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->lower));
+      break;
+
+    case PROP_UPPER:
+      g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->upper));
+      break;
+
+    case PROP_VALUE:
+      g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->value));
+      break;
+
+    case PROP_STEP_INC:
+      g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->step_increment));
+      break;
+
+    case PROP_PAGE_INC:
+      g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->page_increment));
+      break;
+
+    case PROP_PAGE_SIZE:
+      g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->page_size));
+      break;
+    
+    case PROP_ELASTIC:
+      g_value_set_boolean (value, priv->elastic);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tidy_adjustment_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  TidyAdjustment *adj = TIDY_ADJUSTMENT (object);
+
+  switch (prop_id)
+    {
+    case PROP_LOWER:
+      tidy_adjustment_set_lower (adj, g_value_get_double (value));
+      break;
+
+    case PROP_UPPER:
+      tidy_adjustment_set_upper (adj, g_value_get_double (value));
+      break;
+
+    case PROP_VALUE:
+      tidy_adjustment_set_value (adj, g_value_get_double (value));
+      break;
+
+    case PROP_STEP_INC:
+      tidy_adjustment_set_step_increment (adj, g_value_get_double (value));
+      break;
+
+    case PROP_PAGE_INC:
+      tidy_adjustment_set_page_increment (adj, g_value_get_double (value));
+      break;
+
+    case PROP_PAGE_SIZE:
+      tidy_adjustment_set_page_size (adj, g_value_get_double (value));
+      break;
+    
+    case PROP_ELASTIC:
+      tidy_adjustment_set_elastic (adj, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+stop_interpolation (TidyAdjustment *adjustment)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+
+  if (priv->interpolation)
+    {
+      clutter_timeline_stop (priv->interpolation);
+      g_object_unref (priv->interpolation);
+      priv->interpolation = NULL;
+      
+      if (priv->bounce_alpha)
+        {
+          g_object_unref (priv->bounce_alpha);
+          priv->bounce_alpha = NULL;
+        }
+    }
+  
+  if (priv->bounce_source)
+    {
+      g_source_remove (priv->bounce_source);
+      priv->bounce_source = 0;
+    }
+}
+
+static void
+tidy_adjustment_dispose (GObject *object)
+{
+  stop_interpolation (TIDY_ADJUSTMENT (object));
+  
+  G_OBJECT_CLASS (tidy_adjustment_parent_class)->dispose (object);
+}
+
+static void
+tidy_adjustment_class_init (TidyAdjustmentClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (TidyAdjustmentPrivate));
+
+  object_class->get_property = tidy_adjustment_get_property;
+  object_class->set_property = tidy_adjustment_set_property;
+  object_class->dispose = tidy_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,
+                                                        TIDY_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_UPPER,
+                                   g_param_spec_double ("upper",
+                                                        "Upper",
+                                                        "Upper bound",
+                                                        -G_MAXDOUBLE,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        TIDY_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_VALUE,
+                                   g_param_spec_double ("value",
+                                                        "Value",
+                                                        "Current value",
+                                                        -G_MAXDOUBLE,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        TIDY_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_STEP_INC,
+                                   g_param_spec_double ("step-increment",
+                                                        "Step Increment",
+                                                        "Step increment",
+                                                        -G_MAXDOUBLE,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        TIDY_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_PAGE_INC,
+                                   g_param_spec_double ("page-increment",
+                                                        "Page Increment",
+                                                        "Page increment",
+                                                        -G_MAXDOUBLE,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        TIDY_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_PAGE_SIZE,
+                                   g_param_spec_double ("page-size",
+                                                        "Page Size",
+                                                        "Page size",
+                                                        -G_MAXDOUBLE,
+                                                        G_MAXDOUBLE,
+                                                        0.0,
+                                                        TIDY_PARAM_READWRITE));
+  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,
+                                                         TIDY_PARAM_READWRITE));
+
+  signals[CHANGED] =
+    g_signal_new ("changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (TidyAdjustmentClass, changed),
+                  NULL, NULL,
+                  _tidy_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+static void
+tidy_adjustment_init (TidyAdjustment *self)
+{
+  self->priv = ADJUSTMENT_PRIVATE (self);
+}
+
+TidyAdjustment *
+tidy_adjustment_new (gdouble value,
+                     gdouble lower,
+                     gdouble upper,
+                     gdouble step_increment,
+                     gdouble page_increment,
+                     gdouble page_size)
+{
+  return g_object_new (TIDY_TYPE_ADJUSTMENT,
+                       "value", value,
+                       "lower", lower,
+                       "upper", upper,
+                       "step-increment", step_increment,
+                       "page-increment", page_increment,
+                       "page-size", page_size,
+                       NULL);
+}
+
+TidyAdjustment *
+tidy_adjustment_newx (ClutterFixed value,
+                      ClutterFixed lower,
+                      ClutterFixed upper,
+                      ClutterFixed step_increment,
+                      ClutterFixed page_increment,
+                      ClutterFixed page_size)
+{
+  TidyAdjustment *retval;
+  TidyAdjustmentPrivate *priv;
+
+  retval = g_object_new (TIDY_TYPE_ADJUSTMENT, NULL);
+  priv = retval->priv;
+
+  priv->value = value;
+  priv->lower = lower;
+  priv->upper = upper;
+  priv->step_increment = step_increment;
+  priv->page_increment = page_increment;
+  priv->page_size = page_size;
+
+  return retval;
+}
+
+ClutterFixed
+tidy_adjustment_get_valuex (TidyAdjustment *adjustment)
+{
+  TidyAdjustmentPrivate *priv;
+  
+  g_return_val_if_fail (TIDY_IS_ADJUSTMENT (adjustment), 0);
+  
+  priv = adjustment->priv;
+  
+  if (adjustment->priv->interpolation)
+    {
+      return MAX (priv->lower, MIN (priv->upper - priv->page_size,
+                                    adjustment->priv->new_position));
+    }
+  else
+    return adjustment->priv->value;
+}
+
+gdouble
+tidy_adjustment_get_value (TidyAdjustment *adjustment)
+{
+  g_return_val_if_fail (TIDY_IS_ADJUSTMENT (adjustment), 0.0);
+
+  return CLUTTER_FIXED_TO_FLOAT (adjustment->priv->value);
+}
+
+void
+tidy_adjustment_set_valuex (TidyAdjustment *adjustment,
+                            ClutterFixed    value)
+{
+  TidyAdjustmentPrivate *priv;
+  
+  g_return_if_fail (TIDY_IS_ADJUSTMENT (adjustment));
+  
+  priv = adjustment->priv;
+
+  stop_interpolation (adjustment);
+
+  if (!priv->elastic)
+    value = CLAMP (value, priv->lower, MAX (priv->lower,
+                                            priv->upper - priv->page_size));
+
+  if (priv->value != value)
+    {
+      priv->value = value;
+      g_object_notify (G_OBJECT (adjustment), "value");
+    }
+}
+
+void
+tidy_adjustment_set_value (TidyAdjustment *adjustment,
+                           gdouble         value)
+{
+  tidy_adjustment_set_valuex (adjustment, CLUTTER_FLOAT_TO_FIXED (value));
+}
+
+void
+tidy_adjustment_clamp_pagex (TidyAdjustment *adjustment,
+                             ClutterFixed    lower,
+                             ClutterFixed    upper)
+{
+  gboolean changed;
+  TidyAdjustmentPrivate *priv;
+  
+  g_return_if_fail (TIDY_IS_ADJUSTMENT (adjustment));
+  
+  priv = adjustment->priv;
+  
+  stop_interpolation (adjustment);
+
+  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)
+    g_object_notify (G_OBJECT (adjustment), "value");
+}
+
+void
+tidy_adjustment_clamp_page (TidyAdjustment *adjustment,
+                            gdouble         lower,
+                            gdouble         upper)
+{
+  tidy_adjustment_clamp_pagex (adjustment,
+                               CLUTTER_FLOAT_TO_FIXED (lower),
+                               CLUTTER_FLOAT_TO_FIXED (upper));
+}
+
+static void
+tidy_adjustment_set_lower (TidyAdjustment *adjustment,
+                           gdouble         lower)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+  ClutterFixed value = CLUTTER_FLOAT_TO_FIXED (lower);
+  
+  if (priv->lower != value)
+    {
+      priv->lower = value;
+
+      g_signal_emit (adjustment, signals[CHANGED], 0);
+
+      g_object_notify (G_OBJECT (adjustment), "lower");
+
+      tidy_adjustment_clamp_pagex (adjustment, priv->lower, priv->upper);
+    }
+}
+
+static void
+tidy_adjustment_set_upper (TidyAdjustment *adjustment,
+                           gdouble         upper)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+  ClutterFixed value = CLUTTER_FLOAT_TO_FIXED (upper);
+  
+  if (priv->upper != value)
+    {
+      priv->upper = value;
+
+      g_signal_emit (adjustment, signals[CHANGED], 0);
+
+      g_object_notify (G_OBJECT (adjustment), "upper");
+      
+      tidy_adjustment_clamp_pagex (adjustment, priv->lower, priv->upper);
+    }
+}
+
+static void
+tidy_adjustment_set_step_increment (TidyAdjustment *adjustment,
+                                    gdouble         step)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+  ClutterFixed value = CLUTTER_FLOAT_TO_FIXED (step);
+  
+  if (priv->step_increment != value)
+    {
+      priv->step_increment = value;
+
+      g_signal_emit (adjustment, signals[CHANGED], 0);
+
+      g_object_notify (G_OBJECT (adjustment), "step-increment");
+    }
+}
+
+static void
+tidy_adjustment_set_page_increment (TidyAdjustment *adjustment,
+                                    gdouble        page)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+  ClutterFixed value = CLUTTER_FLOAT_TO_FIXED (page);
+
+  if (priv->page_increment != value)
+    {
+      priv->page_increment = value;
+
+      g_signal_emit (adjustment, signals[CHANGED], 0);
+
+      g_object_notify (G_OBJECT (adjustment), "page-increment");
+    }
+}
+
+static void
+tidy_adjustment_set_page_size (TidyAdjustment *adjustment,
+                               gdouble         size)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+  ClutterFixed value = CLUTTER_FLOAT_TO_FIXED (size);
+
+  if (priv->page_size != value)
+    {
+      priv->page_size = value;
+
+      g_signal_emit (adjustment, signals[CHANGED], 0);
+
+      g_object_notify (G_OBJECT (adjustment), "page_size");
+
+      tidy_adjustment_clamp_pagex (adjustment, priv->lower, priv->upper);
+    }
+}
+
+void
+tidy_adjustment_set_valuesx (TidyAdjustment *adjustment,
+                             ClutterFixed    value,
+                             ClutterFixed    lower,
+                             ClutterFixed    upper,
+                             ClutterFixed    step_increment,
+                             ClutterFixed    page_increment,
+                             ClutterFixed    page_size)
+{
+  TidyAdjustmentPrivate *priv;
+  gboolean emit_changed = FALSE;
+  
+  g_return_if_fail (TIDY_IS_ADJUSTMENT (adjustment));
+  
+  priv = adjustment->priv;
+  
+  stop_interpolation (adjustment);
+
+  emit_changed = FALSE;
+  
+  g_object_freeze_notify (G_OBJECT (adjustment));
+
+  if (priv->lower != lower)
+    {
+      priv->lower = lower;
+      emit_changed = TRUE;
+
+      g_object_notify (G_OBJECT (adjustment), "lower");
+    }
+
+  if (priv->upper != upper)
+    {
+      priv->upper = upper;
+      emit_changed = TRUE;
+
+      g_object_notify (G_OBJECT (adjustment), "upper");
+    }
+
+  if (priv->step_increment != step_increment)
+    {
+      priv->step_increment = step_increment;
+      emit_changed = TRUE;
+
+      g_object_notify (G_OBJECT (adjustment), "step-increment");
+    }
+
+  if (priv->page_increment != page_increment)
+    {
+      priv->page_increment = page_increment;
+      emit_changed = TRUE;
+
+      g_object_notify (G_OBJECT (adjustment), "page-increment");
+    }
+
+  if (priv->page_size != page_size)
+    {
+      priv->page_size = page_size;
+      emit_changed = TRUE;
+
+      g_object_notify (G_OBJECT (adjustment), "page-size");
+    }
+  
+  tidy_adjustment_set_valuex (adjustment, value);
+
+  if (emit_changed)
+    g_signal_emit (G_OBJECT (adjustment), signals[CHANGED], 0);
+
+  g_object_thaw_notify (G_OBJECT (adjustment));
+}
+
+void
+tidy_adjustment_set_values (TidyAdjustment *adjustment,
+                            gdouble         value,
+                            gdouble         lower,
+                            gdouble         upper,
+                            gdouble         step_increment,
+                            gdouble         page_increment,
+                            gdouble         page_size)
+{
+  tidy_adjustment_set_valuesx (adjustment,
+                               CLUTTER_FLOAT_TO_FIXED (value),
+                               CLUTTER_FLOAT_TO_FIXED (lower),
+                               CLUTTER_FLOAT_TO_FIXED (upper),
+                               CLUTTER_FLOAT_TO_FIXED (step_increment),
+                               CLUTTER_FLOAT_TO_FIXED (page_increment),
+                               CLUTTER_FLOAT_TO_FIXED (page_size));
+}
+
+void
+tidy_adjustment_get_valuesx (TidyAdjustment *adjustment,
+                             ClutterFixed   *value,
+                             ClutterFixed   *lower,
+                             ClutterFixed   *upper,
+                             ClutterFixed   *step_increment,
+                             ClutterFixed   *page_increment,
+                             ClutterFixed   *page_size)
+{
+  TidyAdjustmentPrivate *priv;
+  
+  g_return_if_fail (TIDY_IS_ADJUSTMENT (adjustment));
+  
+  priv = adjustment->priv;
+  
+  if (lower)
+    *lower = priv->lower;
+
+  if (upper)
+    *upper = priv->upper;
+
+  if (value)
+    *value = tidy_adjustment_get_valuex (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;
+}
+
+void
+tidy_adjustment_get_values (TidyAdjustment *adjustment,
+                            gdouble        *value,
+                            gdouble        *lower,
+                            gdouble        *upper,
+                            gdouble        *step_increment,
+                            gdouble        *page_increment,
+                            gdouble        *page_size)
+{
+  TidyAdjustmentPrivate *priv;
+  
+  g_return_if_fail (TIDY_IS_ADJUSTMENT (adjustment));
+  
+  priv = adjustment->priv;
+  
+  if (lower)
+    *lower = CLUTTER_FIXED_TO_DOUBLE (priv->lower);
+
+  if (upper)
+    *upper = CLUTTER_FIXED_TO_DOUBLE (priv->upper);
+
+  if (value)
+    *value = CLUTTER_FIXED_TO_DOUBLE (tidy_adjustment_get_valuex (adjustment));
+
+  if (step_increment)
+    *step_increment = CLUTTER_FIXED_TO_DOUBLE (priv->step_increment);
+
+  if (page_increment)
+    *page_increment = CLUTTER_FIXED_TO_DOUBLE (priv->page_increment);
+
+  if (page_size)
+    *page_size = CLUTTER_FIXED_TO_DOUBLE (priv->page_size);
+}
+
+static void
+interpolation_new_frame_cb (ClutterTimeline *timeline,
+                            gint             frame_num,
+                            TidyAdjustment  *adjustment)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+
+  priv->interpolation = NULL;
+  if (priv->elastic)
+    {
+      gdouble progress = clutter_alpha_get_alpha (priv->bounce_alpha) /
+        (gdouble)CLUTTER_ALPHA_MAX_ALPHA;
+      gdouble dx = CLUTTER_FIXED_TO_FLOAT (priv->old_position) +
+        CLUTTER_FIXED_TO_FLOAT (priv->new_position - priv->old_position) *
+        progress;
+      tidy_adjustment_set_value (adjustment, dx);
+    }
+  else
+    tidy_adjustment_set_valuex (adjustment,
+                                priv->old_position +
+                                clutter_qmulx (CLUTTER_INT_TO_FIXED (frame_num),
+                                               priv->dx));
+  priv->interpolation = timeline;
+}
+
+static void
+interpolation_completed_cb (ClutterTimeline *timeline,
+                            TidyAdjustment  *adjustment)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+  
+  stop_interpolation (adjustment);
+  tidy_adjustment_set_valuex (adjustment,
+                              priv->new_position);
+}
+
+/* Note, there's super-optimal code that does a similar thing in
+ * clutter-alpha.c
+ *
+ * Tried this instead of CLUTTER_ALPHA_SINE_INC, but I think SINE_INC looks
+ * better. Leaving code here in case this is revisited.
+ */
+/*
+static guint32
+bounce_alpha_func (ClutterAlpha *alpha,
+                   gpointer      user_data)
+{
+  ClutterFixed progress, angle;
+  ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
+  
+  progress = clutter_timeline_get_progressx (timeline);
+  angle = clutter_qmulx (CFX_PI_2 + CFX_PI_4/2, progress);
+  
+  return clutter_sinx (angle) +
+    (CFX_ONE - clutter_sinx (CFX_PI_2 + CFX_PI_4/2));
+}
+*/
+
+void
+tidy_adjustment_interpolatex (TidyAdjustment *adjustment,
+                              ClutterFixed    value,
+                              guint           n_frames,
+                              guint           fps)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+
+  stop_interpolation (adjustment);
+  
+  if (n_frames <= 1)
+    {
+      tidy_adjustment_set_valuex (adjustment, value);
+      return;
+    }
+
+  priv->old_position = priv->value;
+  priv->new_position = value;
+  
+  priv->dx = clutter_qdivx (priv->new_position - priv->old_position,
+                            CLUTTER_INT_TO_FIXED (n_frames));
+  priv->interpolation = clutter_timeline_new (n_frames, fps);
+  
+  if (priv->elastic)
+    priv->bounce_alpha = clutter_alpha_new_full (priv->interpolation,
+                                                 CLUTTER_ALPHA_SINE_INC,
+                                                 NULL, NULL);
+  
+  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);
+  
+  clutter_timeline_start (priv->interpolation);
+}
+
+void
+tidy_adjustment_interpolate (TidyAdjustment *adjustment,
+                              gdouble        value,
+                              guint          n_frames,
+                              guint          fps)
+{
+  tidy_adjustment_interpolatex (adjustment,
+                                CLUTTER_FLOAT_TO_FIXED (value),
+                                n_frames,
+                                fps);
+}
+
+gboolean
+tidy_adjustment_get_elastic (TidyAdjustment *adjustment)
+{
+  return adjustment->priv->elastic;
+}
+
+void
+tidy_adjustment_set_elastic (TidyAdjustment *adjustment,
+                             gboolean        elastic)
+{
+  adjustment->priv->elastic = elastic;
+}
+
+gboolean
+tidy_adjustment_clamp (TidyAdjustment *adjustment,
+                       gboolean        interpolate,
+                       guint           n_frames,
+                       guint           fps)
+{
+  TidyAdjustmentPrivate *priv = adjustment->priv;
+  ClutterFixed dest = priv->value;
+  
+  if (priv->value < priv->lower)
+    dest = priv->lower;
+  if (priv->value > priv->upper - priv->page_size)
+    dest = priv->upper - priv->page_size;
+  
+  if (dest != priv->value)
+    {
+      if (interpolate)
+        tidy_adjustment_interpolatex (adjustment,
+                                      dest,
+                                      n_frames,
+                                      fps);
+      else
+        tidy_adjustment_set_valuex (adjustment, dest);
+      
+      return TRUE;
+    }
+  
+  return FALSE;
+}
diff --git a/tidy/tidy-adjustment.h b/tidy/tidy-adjustment.h
new file mode 100644 (file)
index 0000000..cd51049
--- /dev/null
@@ -0,0 +1,148 @@
+/* tidy-adjustment.h: Adjustment object
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>, inspired by GtkAdjustment
+ */
+
+#ifndef __TIDY_ADJUSTMENT_H__
+#define __TIDY_ADJUSTMENT_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-fixed.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_ADJUSTMENT            (tidy_adjustment_get_type())
+#define TIDY_ADJUSTMENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_ADJUSTMENT, TidyAdjustment))
+#define TIDY_IS_ADJUSTMENT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_ADJUSTMENT))
+#define TIDY_ADJUSTMENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_ADJUSTMENT, TidyAdjustmentClass))
+#define TIDY_IS_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_ADJUSTMENT))
+#define TIDY_ADJUSTMENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_ADJUSTMENT, TidyAdjustmentClass))
+
+typedef struct _TidyAdjustment          TidyAdjustment;
+typedef struct _TidyAdjustmentPrivate   TidyAdjustmentPrivate;
+typedef struct _TidyAdjustmentClass     TidyAdjustmentClass;
+
+/**
+ * TidyAdjustment:
+ *
+ * Class for handling an interval between to values. The contents of
+ * the #TidyAdjustment are private and should be accessed using the
+ * public API.
+ */
+struct _TidyAdjustment
+{
+  /*< private >*/
+  GObject parent_instance;
+  
+  TidyAdjustmentPrivate *priv;
+};
+
+/**
+ * TidyAdjustmentClass
+ * @changed: Class handler for the ::changed signal.
+ *
+ * Base class for #TidyAdjustment.
+ */
+struct _TidyAdjustmentClass
+{
+  /*< private >*/
+  GObjectClass parent_class;
+
+  /*< public >*/
+  void (* changed) (TidyAdjustment *adjustment);
+};
+
+GType tidy_adjustment_get_type (void) G_GNUC_CONST;
+
+TidyAdjustment *tidy_adjustment_new          (gdouble         value,
+                                              gdouble         lower,
+                                              gdouble         upper,
+                                              gdouble         step_increment,
+                                              gdouble         page_increment,
+                                              gdouble         page_size);
+TidyAdjustment *tidy_adjustment_newx         (ClutterFixed    value,
+                                              ClutterFixed    lower,
+                                              ClutterFixed    upper,
+                                              ClutterFixed    step_increment,
+                                              ClutterFixed    page_increment,
+                                              ClutterFixed    page_size);
+gdouble         tidy_adjustment_get_value    (TidyAdjustment *adjustment);
+ClutterFixed    tidy_adjustment_get_valuex   (TidyAdjustment *adjustment);
+void            tidy_adjustment_set_value    (TidyAdjustment *adjustment,
+                                              gdouble         value);
+void            tidy_adjustment_set_valuex   (TidyAdjustment *adjustment,
+                                              ClutterFixed    value);
+void            tidy_adjustment_clamp_page   (TidyAdjustment *adjustment,
+                                              gdouble         lower,
+                                              gdouble         upper);
+void            tidy_adjustment_clamp_pagex  (TidyAdjustment *adjustment,
+                                              ClutterFixed    lower,
+                                              ClutterFixed    upper);
+void            tidy_adjustment_set_values   (TidyAdjustment *adjustment,
+                                              gdouble         value,
+                                              gdouble         lower,
+                                              gdouble         upper,
+                                              gdouble         step_increment,
+                                              gdouble         page_increment,
+                                              gdouble         page_size);
+void            tidy_adjustment_set_valuesx  (TidyAdjustment *adjustment,
+                                              ClutterFixed    value,
+                                              ClutterFixed    lower,
+                                              ClutterFixed    upper,
+                                              ClutterFixed    step_increment,
+                                              ClutterFixed    page_increment,
+                                              ClutterFixed    page_size);
+void            tidy_adjustment_get_values   (TidyAdjustment *adjustment,
+                                              gdouble        *value,
+                                              gdouble        *lower,
+                                              gdouble        *upper,
+                                              gdouble        *step_increment,
+                                              gdouble        *page_increment,
+                                              gdouble        *page_size);
+void            tidy_adjustment_get_valuesx  (TidyAdjustment *adjustment,
+                                              ClutterFixed   *value,
+                                              ClutterFixed   *lower,
+                                              ClutterFixed   *upper,
+                                              ClutterFixed   *step_increment,
+                                              ClutterFixed   *page_increment,
+                                              ClutterFixed   *page_size);
+
+void            tidy_adjustment_interpolate  (TidyAdjustment *adjustment,
+                                              gdouble         value,
+                                              guint           n_frames,
+                                              guint           fps);
+void            tidy_adjustment_interpolatex (TidyAdjustment *adjustment,
+                                              ClutterFixed    value,
+                                              guint           n_frames,
+                                              guint           fps);
+
+gboolean        tidy_adjustment_get_elastic  (TidyAdjustment *adjustment);
+void            tidy_adjustment_set_elastic  (TidyAdjustment *adjustment,
+                                              gboolean        elastic);
+
+gboolean        tidy_adjustment_clamp        (TidyAdjustment *adjustment,
+                                              gboolean        interpolate,
+                                              guint           n_frames,
+                                              guint           fps);
+
+G_END_DECLS
+
+#endif /* __TIDY_ADJUSTMENT_H__ */
+
diff --git a/tidy/tidy-debug.h b/tidy/tidy-debug.h
new file mode 100644 (file)
index 0000000..0efb982
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __TIDY_DEBUG_H__
+#define __TIDY_DEBUG_H__
+
+#endif /* __TIDY_DEBUG_H__ */
diff --git a/tidy/tidy-enum-types.c.in b/tidy/tidy-enum-types.c.in
new file mode 100644 (file)
index 0000000..5f78912
--- /dev/null
@@ -0,0 +1,30 @@
+/*** BEGIN file-header ***/
+#include "tidy-enum-types.h"
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+#include "@filename@"
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type(void) {
+  static GType enum_type_id = 0;
+  if (G_UNLIKELY (!enum_type_id))
+    {
+      static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+        { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+        { 0, NULL, NULL }
+      };
+      enum_type_id = g_@type@_register_static("@EnumName@", values);
+    }
+  return enum_type_id;
+}
+/*** END value-tail ***/
diff --git a/tidy/tidy-enum-types.h.in b/tidy/tidy-enum-types.h.in
new file mode 100644 (file)
index 0000000..517cccb
--- /dev/null
@@ -0,0 +1,25 @@
+/*** BEGIN file-header ***/
+#ifndef __TIDY_ENUM_TYPES_H__
+#define __TIDY_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* !__TIDY_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())
+
+/*** END value-header ***/
diff --git a/tidy/tidy-finger-scroll.c b/tidy/tidy-finger-scroll.c
new file mode 100644 (file)
index 0000000..4bd6ad1
--- /dev/null
@@ -0,0 +1,670 @@
+/* tidy-finger-scroll.c: Finger scrolling container actor
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>
+ */
+
+#include "tidy-finger-scroll.h"
+#include "tidy-enum-types.h"
+#include "tidy-marshal.h"
+#include "tidy-scrollable.h"
+#include "tidy-scroll-view.h"
+#include <clutter/clutter.h>
+#include <math.h>
+
+G_DEFINE_TYPE (TidyFingerScroll, tidy_finger_scroll, TIDY_TYPE_SCROLL_VIEW)
+
+#define FINGER_SCROLL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+                                  TIDY_TYPE_FINGER_SCROLL, \
+                                  TidyFingerScrollPrivate))
+
+typedef struct {
+  /* Units to store the origin of a click when scrolling */
+  ClutterUnit x;
+  ClutterUnit y;
+  GTimeVal    time;
+} TidyFingerScrollMotion;
+
+struct _TidyFingerScrollPrivate
+{
+  /* Scroll mode */
+  TidyFingerScrollMode mode;
+  
+  GArray                *motion_buffer;
+  guint                  last_motion;
+  
+  /* Variables for storing acceleration information for kinetic mode */
+  ClutterTimeline       *deceleration_timeline;
+  ClutterUnit            dx;
+  ClutterUnit            dy;
+  ClutterFixed           decel_rate;
+  
+};
+
+enum {
+  PROP_MODE = 1,
+  PROP_DECEL_RATE,
+  PROP_BUFFER,
+};
+
+static void
+tidy_finger_scroll_get_property (GObject *object, guint property_id,
+                                 GValue *value, GParamSpec *pspec)
+{
+  TidyFingerScrollPrivate *priv = TIDY_FINGER_SCROLL (object)->priv;
+  
+  switch (property_id)
+    {
+    case PROP_MODE :
+      g_value_set_enum (value, priv->mode);
+      break;
+    case PROP_DECEL_RATE :
+      g_value_set_double (value, CLUTTER_FIXED_TO_FLOAT (priv->decel_rate));
+      break;
+    case PROP_BUFFER :
+      g_value_set_uint (value, priv->motion_buffer->len);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+tidy_finger_scroll_set_property (GObject *object, guint property_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+  TidyFingerScrollPrivate *priv = TIDY_FINGER_SCROLL (object)->priv;
+  
+  switch (property_id)
+    {
+    case PROP_MODE :
+      priv->mode = g_value_get_enum (value);
+      g_object_notify (object, "mode");
+      break;
+    case PROP_DECEL_RATE :
+      priv->decel_rate = CLUTTER_FLOAT_TO_FIXED (g_value_get_double (value));
+      g_object_notify (object, "decel-rate");
+      break;
+    case PROP_BUFFER :
+      g_array_set_size (priv->motion_buffer, g_value_get_uint (value));
+      g_object_notify (object, "motion-buffer");
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+tidy_finger_scroll_dispose (GObject *object)
+{
+  TidyFingerScrollPrivate *priv = TIDY_FINGER_SCROLL (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 (tidy_finger_scroll_parent_class)->dispose (object);
+}
+
+static void
+tidy_finger_scroll_finalize (GObject *object)
+{
+  TidyFingerScrollPrivate *priv = TIDY_FINGER_SCROLL (object)->priv;
+
+  g_array_free (priv->motion_buffer, TRUE);
+  
+  G_OBJECT_CLASS (tidy_finger_scroll_parent_class)->finalize (object);
+}
+
+
+static void
+tidy_finger_scroll_class_init (TidyFingerScrollClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (TidyFingerScrollPrivate));
+
+  object_class->get_property = tidy_finger_scroll_get_property;
+  object_class->set_property = tidy_finger_scroll_set_property;
+  object_class->dispose = tidy_finger_scroll_dispose;
+  object_class->finalize = tidy_finger_scroll_finalize;
+
+  g_object_class_install_property (object_class,
+                                   PROP_MODE,
+                                   g_param_spec_enum ("mode",
+                                                      "TidyFingerScrollMode",
+                                                      "Scrolling mode",
+                                                      TIDY_TYPE_FINGER_SCROLL_MODE,
+                                                      TIDY_FINGER_SCROLL_MODE_PUSH,
+                                                      G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_DECEL_RATE,
+                                   g_param_spec_double ("decel-rate",
+                                                        "Deceleration rate",
+                                                        "Rate at which the view "
+                                                        "will decelerate in "
+                                                        "kinetic mode.",
+                                                        CLUTTER_FIXED_TO_FLOAT (CFX_ONE + CFX_MIN),
+                                                        CLUTTER_FIXED_TO_FLOAT (CFX_MAX),
+                                                        1.1,
+                                                        G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_BUFFER,
+                                   g_param_spec_uint ("motion-buffer",
+                                                      "Motion buffer",
+                                                      "Amount of motion "
+                                                      "events to buffer",
+                                                      1, G_MAXUINT, 3,
+                                                      G_PARAM_READWRITE));
+}
+
+static gboolean
+motion_event_cb (ClutterActor *actor,
+                 ClutterMotionEvent *event,
+                 TidyFingerScroll *scroll)
+{
+  ClutterUnit x, y;
+  
+  TidyFingerScrollPrivate *priv = scroll->priv;
+
+  if (clutter_actor_transform_stage_point (actor,
+                                           CLUTTER_UNITS_FROM_DEVICE(event->x),
+                                           CLUTTER_UNITS_FROM_DEVICE(event->y),
+                                           &x, &y))
+    {
+      TidyFingerScrollMotion *motion;
+      ClutterActor *child =
+        tidy_scroll_view_get_child (TIDY_SCROLL_VIEW(scroll));
+      
+      if (child)
+        {
+          ClutterFixed dx, dy;
+          TidyAdjustment *hadjust, *vadjust;
+          
+          tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
+                                           &hadjust,
+                                           &vadjust);
+
+          motion = &g_array_index (priv->motion_buffer,
+                                   TidyFingerScrollMotion, priv->last_motion);
+          dx = CLUTTER_UNITS_TO_FIXED(motion->x - x) +
+               tidy_adjustment_get_valuex (hadjust);
+          dy = CLUTTER_UNITS_TO_FIXED(motion->y - y) +
+               tidy_adjustment_get_valuex (vadjust);
+          
+          tidy_adjustment_set_valuex (hadjust, dx);
+          tidy_adjustment_set_valuex (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,
+                               TidyFingerScrollMotion, priv->last_motion);
+      motion->x = x;
+      motion->y = y;
+      g_get_current_time (&motion->time);
+    }
+
+  return TRUE;
+}
+
+static void
+clamp_adjustments (TidyFingerScroll *scroll)
+{
+  ClutterActor *child = tidy_scroll_view_get_child (TIDY_SCROLL_VIEW (scroll));
+  
+  if (child)
+    {
+      guint fps, n_frames;
+      TidyAdjustment *hadj, *vadj;
+      gboolean snap;
+      
+      tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
+                                       &hadj, &vadj);
+      
+      /* FIXME: Hard-coded value here */
+      fps = clutter_get_default_frame_rate ();
+      n_frames = fps / 6;
+      
+      snap = TRUE;
+      if (tidy_adjustment_get_elastic (hadj))
+        snap = !tidy_adjustment_clamp (hadj, TRUE, n_frames, fps);
+      
+      /* Snap to the nearest step increment on hadjustment */
+      if (snap)
+        {
+          gdouble d, value, lower, step_increment;
+          
+          tidy_adjustment_get_values (hadj, &value, &lower, NULL,
+                                      &step_increment, NULL, NULL);
+          d = (rint ((value - lower) / step_increment) *
+              step_increment) + lower;
+          tidy_adjustment_set_value (hadj, d);
+        }
+      
+      snap = TRUE;
+      if (tidy_adjustment_get_elastic (vadj))
+        snap = !tidy_adjustment_clamp (vadj, TRUE, n_frames, fps);
+
+      /* Snap to the nearest step increment on vadjustment */
+      if (snap)
+        {
+          gdouble d, value, lower, step_increment;
+          
+          tidy_adjustment_get_values (vadj, &value, &lower, NULL,
+                                      &step_increment, NULL, NULL);
+          d = (rint ((value - lower) / step_increment) *
+              step_increment) + lower;
+          tidy_adjustment_set_value (vadj, d);
+        }
+    }
+}
+
+static void
+deceleration_completed_cb (ClutterTimeline *timeline,
+                           TidyFingerScroll *scroll)
+{
+  clamp_adjustments (scroll);
+  g_object_unref (timeline);
+  scroll->priv->deceleration_timeline = NULL;
+}
+
+static void
+deceleration_new_frame_cb (ClutterTimeline *timeline,
+                           gint frame_num,
+                           TidyFingerScroll *scroll)
+{
+  TidyFingerScrollPrivate *priv = scroll->priv;
+  ClutterActor *child = tidy_scroll_view_get_child (TIDY_SCROLL_VIEW(scroll));
+  
+  if (child)
+    {
+      ClutterFixed value, lower, upper, page_size;
+      TidyAdjustment *hadjust, *vadjust;
+      gint i;
+      gboolean stop = TRUE;
+      
+      tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
+                                       &hadjust,
+                                       &vadjust);
+      
+      for (i = 0; i < clutter_timeline_get_delta (timeline, NULL); i++)
+        {
+          tidy_adjustment_set_valuex (hadjust,
+                                      priv->dx +
+                                        tidy_adjustment_get_valuex (hadjust));
+          tidy_adjustment_set_valuex (vadjust,
+                                      priv->dy +
+                                        tidy_adjustment_get_valuex (vadjust));
+          priv->dx = clutter_qdivx (priv->dx, priv->decel_rate);
+          priv->dy = clutter_qdivx (priv->dy, priv->decel_rate);
+        }
+      
+      /* Check if we've hit the upper or lower bounds and stop the timeline */
+      tidy_adjustment_get_valuesx (hadjust, &value, &lower, &upper,
+                                   NULL, NULL, &page_size);
+      if (((priv->dx > 0) && (value < upper - page_size)) ||
+          ((priv->dx < 0) && (value > lower)))
+        stop = FALSE;
+      
+      if (stop)
+        {
+          tidy_adjustment_get_valuesx (vadjust, &value, &lower, &upper,
+                                       NULL, NULL, &page_size);
+          if (((priv->dy > 0) && (value < upper - page_size)) ||
+              ((priv->dy < 0) && (value > lower)))
+            stop = FALSE;
+        }
+      
+      if (stop)
+        {
+          clutter_timeline_stop (timeline);
+          deceleration_completed_cb (timeline, scroll);
+        }
+    }
+}
+
+static gboolean
+button_release_event_cb (ClutterActor *actor,
+                         ClutterButtonEvent *event,
+                         TidyFingerScroll *scroll)
+{
+  TidyFingerScrollPrivate *priv = scroll->priv;
+  ClutterActor *child = tidy_scroll_view_get_child (TIDY_SCROLL_VIEW(scroll));
+  gboolean decelerating = FALSE;
+
+  if (event->button != 1)
+    return FALSE;
+  
+  g_signal_handlers_disconnect_by_func (actor,
+                                        motion_event_cb,
+                                        scroll);
+  g_signal_handlers_disconnect_by_func (actor,
+                                        button_release_event_cb,
+                                        scroll);
+  
+  clutter_ungrab_pointer ();
+
+  if ((priv->mode == TIDY_FINGER_SCROLL_MODE_KINETIC) && (child))
+    {
+      ClutterUnit x, y;
+      
+      if (clutter_actor_transform_stage_point (actor,
+                                               CLUTTER_UNITS_FROM_DEVICE(event->x),
+                                               CLUTTER_UNITS_FROM_DEVICE(event->y),
+                                               &x, &y))
+        {
+          ClutterUnit frac, x_origin, y_origin;
+          GTimeVal release_time, motion_time;
+          TidyAdjustment *hadjust, *vadjust;
+          glong time_diff;
+          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++)
+            {
+              TidyFingerScrollMotion *motion =
+                &g_array_index (priv->motion_buffer, TidyFingerScrollMotion, 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 = CLUTTER_UNITS_FROM_FIXED (
+            clutter_qdivx (CLUTTER_UNITS_TO_FIXED (x_origin),
+                           CLUTTER_INT_TO_FIXED (priv->last_motion)));
+          y_origin = CLUTTER_UNITS_FROM_FIXED (
+            clutter_qdivx (CLUTTER_UNITS_TO_FIXED (y_origin),
+                           CLUTTER_INT_TO_FIXED (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 = clutter_qdivx (CLUTTER_FLOAT_TO_FIXED (time_diff/1000.0),
+                                CLUTTER_FLOAT_TO_FIXED (1000.0/60.0));
+          
+          /* See how many units to move in 1/60th of a second */
+          priv->dx = CLUTTER_UNITS_FROM_FIXED(clutter_qdivx (
+                     CLUTTER_UNITS_TO_FIXED(x_origin - x), frac));
+          priv->dy = CLUTTER_UNITS_FROM_FIXED(clutter_qdivx (
+                     CLUTTER_UNITS_TO_FIXED(y_origin - y), frac));
+          
+          /* Get adjustments to do step-increment snapping */
+          tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
+                                           &hadjust,
+                                           &vadjust);
+
+          if (ABS(CLUTTER_UNITS_TO_INT(priv->dx)) > 1 ||
+              ABS(CLUTTER_UNITS_TO_INT(priv->dy)) > 1)
+            {
+              gdouble value, lower, step_increment, d, a, x, y, n;
+              
+              /* TODO: Convert this all to fixed point? */
+              
+              /* 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)
+               *
+               * As z = 1, this will cause stops to be slightly abrupt - 
+               * add a constant 15 frames to compensate.
+               */
+              x = CLUTTER_FIXED_TO_FLOAT (MAX(ABS(priv->dx), ABS(priv->dy)));
+              y = CLUTTER_FIXED_TO_FLOAT (priv->decel_rate);
+              n = logf (x) / logf (y) + 15.0;
+
+              /* 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 */
+              a = (1.0 - 1.0 / pow (y, n + 1)) / (1.0 - 1.0 / y);
+
+              /* Solving for dx */
+              d = a * CLUTTER_UNITS_TO_FLOAT (priv->dx);
+              tidy_adjustment_get_values (hadjust, &value, &lower, NULL,
+                                          &step_increment, NULL, NULL);
+              d = ((rint (((value + d) - lower) / step_increment) *
+                    step_increment) + lower) - value;
+              priv->dx = CLUTTER_UNITS_FROM_FLOAT (d / a);
+
+              /* Solving for dy */
+              d = a * CLUTTER_UNITS_TO_FLOAT (priv->dy);
+              tidy_adjustment_get_values (vadjust, &value, &lower, NULL,
+                                          &step_increment, NULL, NULL);
+              d = ((rint (((value + d) - lower) / step_increment) *
+                    step_increment) + lower) - value;
+              priv->dy = CLUTTER_UNITS_FROM_FLOAT (d / a);
+              
+              priv->deceleration_timeline = clutter_timeline_new ((gint)n, 60);
+            }
+          else
+            {
+              gdouble value, lower, step_increment, d, a, y;
+              
+              /* Start a short effects timeline to snap to the nearest step 
+               * boundary (see equations above)
+               */
+              y = CLUTTER_FIXED_TO_FLOAT (priv->decel_rate);
+              a = (1.0 - 1.0 / pow (y, 4 + 1)) / (1.0 - 1.0 / y);
+              
+              tidy_adjustment_get_values (hadjust, &value, &lower, NULL,
+                                          &step_increment, NULL, NULL);
+              d = ((rint ((value - lower) / step_increment) *
+                    step_increment) + lower) - value;
+              priv->dx = CLUTTER_UNITS_FROM_FLOAT (d / a);
+              
+              tidy_adjustment_get_values (vadjust, &value, &lower, NULL,
+                                          &step_increment, NULL, NULL);
+              d = ((rint ((value - lower) / step_increment) *
+                    step_increment) + lower) - value;
+              priv->dy = CLUTTER_UNITS_FROM_FLOAT (d / a);
+              
+              priv->deceleration_timeline = clutter_timeline_new (4, 60);
+            }
+
+          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);
+          clutter_timeline_start (priv->deceleration_timeline);
+          decelerating = TRUE;
+        }
+    }
+
+  /* Reset motion event buffer */
+  priv->last_motion = 0;
+  
+  if (!decelerating)
+    {
+      clamp_adjustments (scroll);
+    }
+  
+  /* Pass through events to children.
+   * FIXME: this probably breaks click-count.
+   */
+  clutter_event_put ((ClutterEvent *)event);
+  
+  return TRUE;
+}
+
+static gboolean
+after_event_cb (TidyFingerScroll *scroll)
+{
+  /* Check the pointer grab - if something else has grabbed it - for example,
+   * a scroll-bar or some such, don't do our funky stuff.
+   */
+  if (clutter_get_pointer_grab () != CLUTTER_ACTOR (scroll))
+    {
+      g_signal_handlers_disconnect_by_func (scroll,
+                                            motion_event_cb,
+                                            scroll);
+      g_signal_handlers_disconnect_by_func (scroll,
+                                            button_release_event_cb,
+                                            scroll);
+    }
+  
+  return FALSE;
+}
+
+static gboolean
+captured_event_cb (ClutterActor     *actor,
+                   ClutterEvent     *event,
+                   TidyFingerScroll *scroll)
+{
+  TidyFingerScrollPrivate *priv = scroll->priv;
+  
+  if (event->type == CLUTTER_BUTTON_PRESS)
+    {
+      TidyFingerScrollMotion *motion;
+      ClutterButtonEvent *bevent = (ClutterButtonEvent *)event;
+      
+      /* Reset motion buffer */
+      priv->last_motion = 0;
+      motion = &g_array_index (priv->motion_buffer, TidyFingerScrollMotion, 0);
+      
+      if ((bevent->button == 1) &&
+          (clutter_actor_transform_stage_point (actor,
+                                           CLUTTER_UNITS_FROM_DEVICE(bevent->x),
+                                           CLUTTER_UNITS_FROM_DEVICE(bevent->y),
+                                           &motion->x, &motion->y)))
+        {
+          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;
+            }
+          
+          clutter_grab_pointer (actor);
+          
+          /* Add a high priority idle to check the grab after the event
+           * emission is finished.
+           */
+          g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+                           (GSourceFunc)after_event_cb,
+                           scroll,
+                           NULL);
+          
+          g_signal_connect (actor,
+                            "motion-event",
+                            G_CALLBACK (motion_event_cb),
+                            scroll);
+          g_signal_connect (actor,
+                            "button-release-event",
+                            G_CALLBACK (button_release_event_cb),
+                            scroll);
+        }
+    }
+  
+  return FALSE;
+}
+
+static void
+tidy_finger_scroll_init (TidyFingerScroll *self)
+{
+  ClutterActor *scrollbar;
+  TidyFingerScrollPrivate *priv = self->priv = FINGER_SCROLL_PRIVATE (self);
+  
+  priv->motion_buffer = g_array_sized_new (FALSE, TRUE,
+                                           sizeof (TidyFingerScrollMotion), 3);
+  g_array_set_size (priv->motion_buffer, 3);
+  priv->decel_rate = CLUTTER_FLOAT_TO_FIXED (1.1f);
+  
+  clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
+  g_signal_connect (CLUTTER_ACTOR (self),
+                    "captured-event",
+                    G_CALLBACK (captured_event_cb),
+                    self);
+  
+  
+}
+
+ClutterActor *
+tidy_finger_scroll_new (TidyFingerScrollMode mode)
+{
+  return CLUTTER_ACTOR (g_object_new (TIDY_TYPE_FINGER_SCROLL,
+                                      "mode", mode, NULL));
+}
+
+void
+tidy_finger_scroll_stop (TidyFingerScroll *scroll)
+{
+  TidyFingerScrollPrivate *priv;
+  
+  g_return_if_fail (TIDY_IS_FINGER_SCROLL (scroll));
+  
+  priv = scroll->priv;
+
+  if (priv->deceleration_timeline)
+    {
+      clutter_timeline_stop (priv->deceleration_timeline);
+      g_object_unref (priv->deceleration_timeline);
+      priv->deceleration_timeline = NULL;
+    }
+}
diff --git a/tidy/tidy-finger-scroll.h b/tidy/tidy-finger-scroll.h
new file mode 100644 (file)
index 0000000..eabc5f1
--- /dev/null
@@ -0,0 +1,75 @@
+/* tidy-finger-scroll.h: Finger scrolling container actor
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>
+ */
+
+#ifndef __TIDY_FINGER_SCROLL_H__
+#define __TIDY_FINGER_SCROLL_H__
+
+#include <glib-object.h>
+#include <tidy/tidy-scroll-view.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_FINGER_SCROLL            (tidy_finger_scroll_get_type())
+#define TIDY_FINGER_SCROLL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_FINGER_SCROLL, TidyFingerScroll))
+#define TIDY_IS_FINGER_SCROLL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_FINGER_SCROLL))
+#define TIDY_FINGER_SCROLL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_FINGER_SCROLL, TidyFingerScrollClass))
+#define TIDY_IS_FINGER_SCROLL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_FINGER_SCROLL))
+#define TIDY_FINGER_SCROLL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_FINGER_SCROLL, TidyFingerScrollClass))
+
+/**
+ * TidyFingerScrollMode:
+ * @TIDY_FINGER_SCROLL_MODE_PUSH: Non-kinetic scrolling
+ * @TIDY_FINGER_SCROLL_MODE_KINETIC: Kinetic scrolling
+ *
+ * Type of scrolling.
+ */
+typedef enum {
+  TIDY_FINGER_SCROLL_MODE_PUSH,
+  TIDY_FINGER_SCROLL_MODE_KINETIC
+} TidyFingerScrollMode;
+
+typedef struct _TidyFingerScroll          TidyFingerScroll;
+typedef struct _TidyFingerScrollPrivate   TidyFingerScrollPrivate;
+typedef struct _TidyFingerScrollClass     TidyFingerScrollClass;
+
+struct _TidyFingerScroll
+{
+  /*< private >*/
+  TidyScrollView parent_instance;
+  
+  TidyFingerScrollPrivate *priv;
+};
+
+struct _TidyFingerScrollClass
+{
+  TidyScrollViewClass parent_class;
+};
+
+GType tidy_finger_scroll_get_type (void) G_GNUC_CONST;
+
+ClutterActor *tidy_finger_scroll_new  (TidyFingerScrollMode mode);
+
+void          tidy_finger_scroll_stop (TidyFingerScroll *scroll);
+
+G_END_DECLS
+
+#endif /* __TIDY_FINGER_SCROLL_H__ */
diff --git a/tidy/tidy-marshal.c b/tidy/tidy-marshal.c
new file mode 100644 (file)
index 0000000..9379902
--- /dev/null
@@ -0,0 +1,132 @@
+#include "tidy-marshal.h"
+
+#include       <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v)     g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+#define g_marshal_value_peek_long(v)     g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
+#define g_marshal_value_peek_float(v)    g_value_get_float (v)
+#define g_marshal_value_peek_double(v)   g_value_get_double (v)
+#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v)    g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v)   g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ *          Do not access GValues directly in your code. Instead, use the
+ *          g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
+#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
+#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
+#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:OBJECT (./tidy-marshal.list:1) */
+
+/* VOID:VOID (./tidy-marshal.list:2) */
+
+/* VOID:PARAM (./tidy-marshal.list:3) */
+
+/* VOID:UINT (./tidy-marshal.list:4) */
+
+/* VOID:UINT,UINT (./tidy-marshal.list:5) */
+void
+_tidy_marshal_VOID__UINT_UINT (GClosure     *closure,
+                               GValue       *return_value G_GNUC_UNUSED,
+                               guint         n_param_values,
+                               const GValue *param_values,
+                               gpointer      invocation_hint G_GNUC_UNUSED,
+                               gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer     data1,
+                                                guint        arg_1,
+                                                guint        arg_2,
+                                                gpointer     data2);
+  register GMarshalFunc_VOID__UINT_UINT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_uint (param_values + 1),
+            g_marshal_value_peek_uint (param_values + 2),
+            data2);
+}
+
+/* VOID:OBJECT,OBJECT (./tidy-marshal.list:6) */
+void
+_tidy_marshal_VOID__OBJECT_OBJECT (GClosure     *closure,
+                                   GValue       *return_value G_GNUC_UNUSED,
+                                   guint         n_param_values,
+                                   const GValue *param_values,
+                                   gpointer      invocation_hint G_GNUC_UNUSED,
+                                   gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer     data1,
+                                                    gpointer     arg_1,
+                                                    gpointer     arg_2,
+                                                    gpointer     data2);
+  register GMarshalFunc_VOID__OBJECT_OBJECT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_object (param_values + 1),
+            g_marshal_value_peek_object (param_values + 2),
+            data2);
+}
+
diff --git a/tidy/tidy-marshal.h b/tidy/tidy-marshal.h
new file mode 100644 (file)
index 0000000..9846ed6
--- /dev/null
@@ -0,0 +1,40 @@
+
+#ifndef ___tidy_marshal_MARSHAL_H__
+#define ___tidy_marshal_MARSHAL_H__
+
+#include       <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:OBJECT (./tidy-marshal.list:1) */
+#define _tidy_marshal_VOID__OBJECT     g_cclosure_marshal_VOID__OBJECT
+
+/* VOID:VOID (./tidy-marshal.list:2) */
+#define _tidy_marshal_VOID__VOID       g_cclosure_marshal_VOID__VOID
+
+/* VOID:PARAM (./tidy-marshal.list:3) */
+#define _tidy_marshal_VOID__PARAM      g_cclosure_marshal_VOID__PARAM
+
+/* VOID:UINT (./tidy-marshal.list:4) */
+#define _tidy_marshal_VOID__UINT       g_cclosure_marshal_VOID__UINT
+
+/* VOID:UINT,UINT (./tidy-marshal.list:5) */
+extern void _tidy_marshal_VOID__UINT_UINT (GClosure     *closure,
+                                           GValue       *return_value,
+                                           guint         n_param_values,
+                                           const GValue *param_values,
+                                           gpointer      invocation_hint,
+                                           gpointer      marshal_data);
+
+/* VOID:OBJECT,OBJECT (./tidy-marshal.list:6) */
+extern void _tidy_marshal_VOID__OBJECT_OBJECT (GClosure     *closure,
+                                               GValue       *return_value,
+                                               guint         n_param_values,
+                                               const GValue *param_values,
+                                               gpointer      invocation_hint,
+                                               gpointer      marshal_data);
+
+G_END_DECLS
+
+#endif /* ___tidy_marshal_MARSHAL_H__ */
+
diff --git a/tidy/tidy-marshal.list b/tidy/tidy-marshal.list
new file mode 100644 (file)
index 0000000..7a60e80
--- /dev/null
@@ -0,0 +1,6 @@
+VOID:OBJECT
+VOID:VOID
+VOID:PARAM
+VOID:UINT
+VOID:UINT,UINT
+VOID:OBJECT,OBJECT
diff --git a/tidy/tidy-private.h b/tidy/tidy-private.h
new file mode 100644 (file)
index 0000000..5f17d93
--- /dev/null
@@ -0,0 +1,40 @@
+/* tidy-private.h: Private declarations
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TIDY_PRIVATE_H__
+#define __TIDY_PRIVATE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define I_(str)         (g_intern_static_string ((str)))
+
+#define TIDY_PARAM_READABLE     \
+        (G_PARAM_READABLE |     \
+         G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
+
+#define TIDY_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__ */
diff --git a/tidy/tidy-scroll-view.c b/tidy/tidy-scroll-view.c
new file mode 100644 (file)
index 0000000..3825d37
--- /dev/null
@@ -0,0 +1,348 @@
+/* tidy-scroll-view.h: Container with scroll-bars
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>
+ */
+
+#include "tidy-scroll-view.h"
+#include "tidy-marshal.h"
+#include "tidy-scrollable.h"
+#include <clutter/clutter.h>
+
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (TidyScrollView, tidy_scroll_view, CLUTTER_TYPE_ACTOR,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+                                                clutter_container_iface_init))
+
+#define SCROLL_VIEW_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+                                TIDY_TYPE_SCROLL_VIEW, \
+                                TidyScrollViewPrivate))
+
+struct _TidyScrollViewPrivate
+{
+  ClutterActor   *child;
+  
+  TidyAdjustment *hadjustment;
+  TidyAdjustment *vadjustment;
+};
+
+enum {
+  PROP_0,
+  PROP_CHILD,
+};
+
+static void
+tidy_scroll_view_get_property (GObject *object, guint property_id,
+                                 GValue *value, GParamSpec *pspec)
+{
+  TidyScrollViewPrivate *priv = ((TidyScrollView *)object)->priv;
+
+  switch (property_id)
+    {
+    case PROP_CHILD :
+      g_value_set_object (value, priv->child);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+tidy_scroll_view_set_property (GObject *object, guint property_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+  switch (property_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+tidy_scroll_view_dispose (GObject *object)
+{
+  TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (object)->priv;
+  
+  if (priv->child)
+    clutter_container_remove_actor (CLUTTER_CONTAINER (object), priv->child);
+  
+  G_OBJECT_CLASS (tidy_scroll_view_parent_class)->dispose (object);
+}
+
+static void
+tidy_scroll_view_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (tidy_scroll_view_parent_class)->finalize (object);
+}
+
+static void
+tidy_scroll_view_paint (ClutterActor *actor)
+{
+  TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (actor)->priv;
+  
+  if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
+    clutter_actor_paint (priv->child);
+}
+
+static void
+tidy_scroll_view_pick (ClutterActor *actor, const ClutterColor *color)
+{
+  /* Chain up so we get a bounding box pained (if we are reactive) */
+  CLUTTER_ACTOR_CLASS (tidy_scroll_view_parent_class)->pick (actor, color);
+  
+  /* Trigger pick on children */
+  tidy_scroll_view_paint (actor);
+}
+
+static void
+tidy_scroll_view_get_preferred_width (ClutterActor *actor,
+                                      ClutterUnit   for_height,
+                                      ClutterUnit  *min_width_p,
+                                      ClutterUnit  *natural_width_p)
+{
+
+  TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (actor)->priv;
+  
+  if (!priv->child)
+    return;
+  
+
+  /* Our natural width is the natural width of the child */
+  clutter_actor_get_preferred_width (priv->child,
+                                     for_height,
+                                     NULL,
+                                     natural_width_p);
+  
+}
+
+static void
+tidy_scroll_view_get_preferred_height (ClutterActor *actor,
+                                       ClutterUnit   for_width,
+                                       ClutterUnit  *min_height_p,
+                                       ClutterUnit  *natural_height_p)
+{
+
+  TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (actor)->priv;
+  
+  if (!priv->child)
+    return;
+  
+
+  /* Our natural height is the natural height of the child */
+  clutter_actor_get_preferred_height (priv->child,
+                                      for_width,
+                                      NULL,
+                                      natural_height_p);
+}
+
+static void
+tidy_scroll_view_allocate (ClutterActor          *actor,
+                           const ClutterActorBox *box,
+                           gboolean               absolute_origin_changed)
+{
+  ClutterActorBox child_box;
+  
+  TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (actor)->priv;
+  
+  /* Chain up */
+  CLUTTER_ACTOR_CLASS (tidy_scroll_view_parent_class)->
+    allocate (actor, box, absolute_origin_changed);
+  
+  
+
+  
+  /* Child */
+  child_box.x1 = 0;
+  child_box.x2 = box->x2 - box->x1;
+  child_box.y1 = 0;
+  child_box.y2 = box->y2 - box->y1;
+  
+  
+  if (priv->child)
+    {
+      clutter_actor_allocate (priv->child, &child_box, absolute_origin_changed);
+      clutter_actor_set_clipu (priv->child,
+                               child_box.x1,
+                               child_box.y1,
+                               child_box.x2 - child_box.x1,
+                               child_box.y2 - child_box.y1);
+    }
+  
+}
+
+static void
+tidy_scroll_view_class_init (TidyScrollViewClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (TidyScrollViewPrivate));
+
+  object_class->get_property = tidy_scroll_view_get_property;
+  object_class->set_property = tidy_scroll_view_set_property;
+  object_class->dispose= tidy_scroll_view_dispose;
+  object_class->finalize = tidy_scroll_view_finalize;
+  
+  actor_class->paint = tidy_scroll_view_paint;
+  actor_class->pick = tidy_scroll_view_pick;
+  actor_class->get_preferred_width = tidy_scroll_view_get_preferred_width;
+  actor_class->get_preferred_height = tidy_scroll_view_get_preferred_height;
+  actor_class->allocate = tidy_scroll_view_allocate;
+  
+  g_object_class_install_property (object_class,
+                                   PROP_CHILD,
+                                   g_param_spec_object ("child",
+                                                        "ClutterActor",
+                                                        "Child actor",
+                                                        CLUTTER_TYPE_ACTOR,
+                                                        G_PARAM_READABLE));
+}
+
+static void
+tidy_scroll_view_init (TidyScrollView *self)
+{
+  TidyScrollViewPrivate *priv = self->priv = SCROLL_VIEW_PRIVATE (self);
+  
+}
+
+static void
+tidy_scroll_view_add_actor (ClutterContainer *container,
+                            ClutterActor     *actor)
+{
+  TidyScrollView *self = TIDY_SCROLL_VIEW (container);
+  TidyScrollViewPrivate *priv = self->priv;
+  
+  if (priv->child)
+    {
+      g_warning ("Attempting to add an actor of type %s to "
+                 "a TidyScrollView that already contains "
+                 "an actor of type %s.",
+                 g_type_name (G_OBJECT_TYPE (actor)),
+                 g_type_name (G_OBJECT_TYPE (priv->child)));
+    }
+  else
+    {
+      if (TIDY_IS_SCROLLABLE(actor))
+        {
+          priv->child = actor;
+          clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
+          
+          /* Notify that child has been set */
+          g_signal_emit_by_name (container, "actor-added", priv->child);
+          g_object_notify (G_OBJECT (container), "child");
+          
+          clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+        }
+      else
+        {
+          g_warning ("Attempting to add an actor of type %s to "
+                     "a TidyScrollView, but the actor does "
+                     "not implement TidyScrollable.",
+                     g_type_name (G_OBJECT_TYPE (actor)));
+        }
+    }
+}
+
+static void
+tidy_scroll_view_remove_actor (ClutterContainer *container,
+                               ClutterActor     *actor)
+{
+  TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (container)->priv;
+  
+  if (actor == priv->child)
+    {
+      g_object_ref (priv->child);
+      
+      
+      clutter_actor_unparent (priv->child);
+
+      g_signal_emit_by_name (container, "actor-removed", priv->child);
+
+      g_object_unref (priv->child);
+      priv->child = NULL;
+
+      g_object_notify (G_OBJECT (container), "child");
+
+      if (CLUTTER_ACTOR_IS_VISIBLE (container))
+        clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+    }
+}
+
+static void
+tidy_scroll_view_foreach (ClutterContainer *container,
+                          ClutterCallback   callback,
+                          gpointer          callback_data)
+{
+  TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (container)->priv;
+
+  if (priv->child)
+    callback (priv->child, callback_data);
+}
+
+static void
+tidy_scroll_view_lower (ClutterContainer *container,
+                        ClutterActor     *actor,
+                        ClutterActor     *sibling)
+{
+  /* single child */
+}
+
+static void
+tidy_scroll_view_raise (ClutterContainer *container,
+                        ClutterActor     *actor,
+                        ClutterActor     *sibling)
+{
+  /* single child */
+}
+
+static void
+tidy_scroll_view_sort_depth_order (ClutterContainer *container)
+{
+  /* single child */
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+  iface->add = tidy_scroll_view_add_actor;
+  iface->remove = tidy_scroll_view_remove_actor;
+  iface->foreach = tidy_scroll_view_foreach;
+  iface->lower = tidy_scroll_view_lower;
+  iface->raise = tidy_scroll_view_raise;
+  iface->sort_depth_order = tidy_scroll_view_sort_depth_order;
+}
+
+ClutterActor *
+tidy_scroll_view_new (void)
+{
+  return CLUTTER_ACTOR (g_object_new (TIDY_TYPE_SCROLL_VIEW, NULL));
+}
+
+ClutterActor *
+tidy_scroll_view_get_child (TidyScrollView *scroll)
+{
+  TidyScrollViewPrivate *priv;
+  
+  g_return_val_if_fail (TIDY_IS_SCROLL_VIEW (scroll), NULL);
+  
+  priv = scroll->priv;
+  
+  return priv->child;
+}
diff --git a/tidy/tidy-scroll-view.h b/tidy/tidy-scroll-view.h
new file mode 100644 (file)
index 0000000..e01a72b
--- /dev/null
@@ -0,0 +1,65 @@
+/* tidy-scroll-view.h: Container with scroll-bars
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>
+ */
+
+#ifndef __TIDY_SCROLL_VIEW_H__
+#define __TIDY_SCROLL_VIEW_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-actor.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_SCROLL_VIEW            (tidy_scroll_view_get_type())
+#define TIDY_SCROLL_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_SCROLL_VIEW, TidyScrollView))
+#define TIDY_IS_SCROLL_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_SCROLL_VIEW))
+#define TIDY_SCROLL_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_SCROLL_VIEW, TidyScrollViewClass))
+#define TIDY_IS_SCROLL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_SCROLL_VIEW))
+#define TIDY_SCROLL_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_SCROLL_VIEW, TidyScrollViewClass))
+
+typedef struct _TidyScrollView          TidyScrollView;
+typedef struct _TidyScrollViewPrivate   TidyScrollViewPrivate;
+typedef struct _TidyScrollViewClass     TidyScrollViewClass;
+
+struct _TidyScrollView
+{
+  /*< private >*/
+  ClutterActor parent;
+  
+  TidyScrollViewPrivate *priv;
+};
+
+struct _TidyScrollViewClass
+{
+  ClutterActorClass parent_class;
+};
+
+GType tidy_scroll_view_get_type (void) G_GNUC_CONST;
+
+ClutterActor *tidy_scroll_view_new             (void);
+
+ClutterActor *tidy_scroll_view_get_hscroll_bar (TidyScrollView *scroll);
+ClutterActor *tidy_scroll_view_get_vscroll_bar (TidyScrollView *scroll);
+ClutterActor *tidy_scroll_view_get_child       (TidyScrollView *scroll);
+
+G_END_DECLS
+
+#endif /* __TIDY_SCROLL_VIEW_H__ */
diff --git a/tidy/tidy-scrollable.c b/tidy/tidy-scrollable.c
new file mode 100644 (file)
index 0000000..6f6545f
--- /dev/null
@@ -0,0 +1,87 @@
+/* tidy-scrollable.c: Scrollable interface
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>
+ */
+
+#include "tidy-scrollable.h"
+
+static void
+tidy_scrollable_base_init (gpointer g_iface)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      g_object_interface_install_property (g_iface,
+                                   g_param_spec_object ("hadjustment",
+                                                        "TidyAdjustment",
+                                                        "Horizontal adjustment",
+                                                        TIDY_TYPE_ADJUSTMENT,
+                                                        G_PARAM_READWRITE));
+
+      g_object_interface_install_property (g_iface,
+                                   g_param_spec_object ("vadjustment",
+                                                        "TidyAdjustment",
+                                                        "Vertical adjustment",
+                                                        TIDY_TYPE_ADJUSTMENT,
+                                                        G_PARAM_READWRITE));
+
+      initialized = TRUE;
+    }
+}
+
+GType
+tidy_scrollable_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0)
+    {
+      static const GTypeInfo info =
+        {
+          sizeof (TidyScrollableInterface),
+          tidy_scrollable_base_init,        /* base_init */
+          NULL,
+        };
+      type = g_type_register_static (G_TYPE_INTERFACE,
+                                     "TidyScrollable", &info, 0);
+    }
+  return type;
+}
+
+void
+tidy_scrollable_set_adjustments (TidyScrollable *scrollable,
+                                 TidyAdjustment *hadjustment,
+                                 TidyAdjustment *vadjustment)
+{
+  TIDY_SCROLLABLE_GET_INTERFACE (scrollable)->set_adjustments (scrollable,
+                                                               hadjustment,
+                                                               vadjustment);
+}
+
+void
+tidy_scrollable_get_adjustments (TidyScrollable *scrollable,
+                                 TidyAdjustment **hadjustment,
+                                 TidyAdjustment **vadjustment)
+{
+  TIDY_SCROLLABLE_GET_INTERFACE (scrollable)->get_adjustments (scrollable,
+                                                               hadjustment,
+                                                               vadjustment);
+}
+
diff --git a/tidy/tidy-scrollable.h b/tidy/tidy-scrollable.h
new file mode 100644 (file)
index 0000000..4710897
--- /dev/null
@@ -0,0 +1,63 @@
+/* tidy-scrollable.h: Scrollable interface
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>
+ */
+
+#ifndef __TIDY_SCROLLABLE_H__
+#define __TIDY_SCROLLABLE_H__
+
+#include <glib-object.h>
+#include <tidy/tidy-adjustment.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_SCROLLABLE                (tidy_scrollable_get_type ())
+#define TIDY_SCROLLABLE(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_SCROLLABLE, TidyScrollable))
+#define TIDY_IS_SCROLLABLE(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_SCROLLABLE))
+#define TIDY_SCROLLABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TIDY_TYPE_SCROLLABLE, TidyScrollableInterface))
+
+typedef struct _TidyScrollable TidyScrollable; /* Dummy object */
+typedef struct _TidyScrollableInterface TidyScrollableInterface;
+
+struct _TidyScrollableInterface
+{
+  GTypeInterface parent;
+  
+  void (* set_adjustments) (TidyScrollable  *scrollable,
+                            TidyAdjustment  *hadjustment,
+                            TidyAdjustment  *vadjustment);
+  void (* get_adjustments) (TidyScrollable  *scrollable,
+                            TidyAdjustment **hadjustment,
+                            TidyAdjustment **vadjustment);
+};
+
+GType tidy_scrollable_get_type (void) G_GNUC_CONST;
+
+void tidy_scrollable_set_adjustments (TidyScrollable  *scrollable,
+                                      TidyAdjustment  *hadjustment,
+                                      TidyAdjustment  *vadjustment);
+void tidy_scrollable_get_adjustments (TidyScrollable  *scrollable,
+                                      TidyAdjustment **hadjustment,
+                                      TidyAdjustment **vadjustment);
+
+G_END_DECLS
+
+#endif /* __TIDY_SCROLLABLE_H__ */
+
diff --git a/tidy/tidy-viewport.c b/tidy/tidy-viewport.c
new file mode 100644 (file)
index 0000000..33602e0
--- /dev/null
@@ -0,0 +1,621 @@
+/* tidy-viewport.c: Viewport actor
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <clutter/clutter.h>
+
+#include "tidy-viewport.h"
+#include "tidy-adjustment.h"
+#include "tidy-scrollable.h"
+#include "tidy-private.h"
+
+static void scrollable_interface_init (TidyScrollableInterface *iface);
+
+static void scrollable_set_adjustments (TidyScrollable *scrollable,
+                                        TidyAdjustment *hadjustment,
+                                        TidyAdjustment *vadjustment);
+
+static void scrollable_get_adjustments (TidyScrollable  *scrollable,
+                                        TidyAdjustment **hadjustment,
+                                        TidyAdjustment **vadjustment);
+
+G_DEFINE_TYPE_WITH_CODE (TidyViewport, tidy_viewport, CLUTTER_TYPE_GROUP,
+                         G_IMPLEMENT_INTERFACE (TIDY_TYPE_SCROLLABLE,
+                                                scrollable_interface_init))
+
+#define VIEWPORT_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), TIDY_TYPE_VIEWPORT, \
+  TidyViewportPrivate))
+
+struct _TidyViewportPrivate
+{
+  ClutterUnit x;
+  ClutterUnit y;
+  ClutterUnit z;
+  
+  TidyAdjustment *hadjustment;
+  TidyAdjustment *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
+tidy_viewport_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  TidyAdjustment *adjustment;
+  
+  TidyViewportPrivate *priv = TIDY_VIEWPORT (object)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_X_ORIGIN:
+      g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (priv->x));
+      break;
+
+    case PROP_Y_ORIGIN:
+      g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (priv->y));
+      break;
+
+    case PROP_Z_ORIGIN:
+      g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (priv->z));
+      break;
+
+    case PROP_HADJUST :
+      scrollable_get_adjustments (TIDY_SCROLLABLE (object), &adjustment, NULL);
+      g_value_set_object (value, adjustment);
+      break;
+
+    case PROP_VADJUST :
+      scrollable_get_adjustments (TIDY_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
+tidy_viewport_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  TidyViewport *viewport = TIDY_VIEWPORT (object);
+  TidyViewportPrivate *priv = viewport->priv;
+
+  switch (prop_id)
+    {
+    case PROP_X_ORIGIN:
+      tidy_viewport_set_originu (viewport,
+                                 g_value_get_int (value),
+                                 priv->y,
+                                 priv->z);
+      break;
+
+    case PROP_Y_ORIGIN:
+      tidy_viewport_set_originu (viewport,
+                                 priv->x,
+                                 g_value_get_int (value),
+                                 priv->z);
+      break;
+
+    case PROP_Z_ORIGIN:
+      tidy_viewport_set_originu (viewport,
+                                 priv->x,
+                                 priv->y,
+                                 g_value_get_int (value));
+      break;
+
+    case PROP_HADJUST :
+      scrollable_set_adjustments (TIDY_SCROLLABLE (object),
+                                  g_value_get_object (value),
+                                  priv->vadjustment);
+      break;
+
+    case PROP_VADJUST :
+      scrollable_set_adjustments (TIDY_SCROLLABLE (object),
+                                  priv->hadjustment,
+                                  g_value_get_object (value));
+      break;
+    
+    case PROP_SYNC_ADJUST :
+      priv->sync_adjustments = g_value_get_boolean (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tidy_viewport_dispose (GObject *gobject)
+{
+  TidyViewportPrivate *priv = TIDY_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 (tidy_viewport_parent_class)->dispose (gobject);
+}
+
+static void
+tidy_viewport_paint (ClutterActor *self)
+{
+  TidyViewportPrivate *priv = TIDY_VIEWPORT (self)->priv;
+  
+  cogl_push_matrix ();
+  
+  cogl_translatex (CLUTTER_UNITS_TO_FIXED (priv->x) * -1,
+                   CLUTTER_UNITS_TO_FIXED (priv->y) * -1,
+                   CLUTTER_UNITS_TO_FIXED (priv->z) * -1);
+  
+  CLUTTER_ACTOR_CLASS (tidy_viewport_parent_class)->paint (self);
+  
+  cogl_pop_matrix ();
+}
+
+static void
+tidy_viewport_pick (ClutterActor       *self,
+                    const ClutterColor *color)
+{
+  tidy_viewport_paint (self);
+}
+
+static void
+tidy_viewport_allocate (ClutterActor          *self,
+                        const ClutterActorBox *box,
+                        gboolean               absolute_origin_changed)
+{
+  ClutterFixed prev_value;
+  
+  TidyViewportPrivate *priv = TIDY_VIEWPORT (self)->priv;
+
+  /* Chain up */
+  CLUTTER_ACTOR_CLASS (tidy_viewport_parent_class)->
+    allocate (self, box, absolute_origin_changed);
+
+  /* Refresh adjustments */
+  if (priv->sync_adjustments)
+    {
+      if (priv->hadjustment)
+        {
+          g_object_set (G_OBJECT (priv->hadjustment),
+                       "lower", 0.0,
+                       "upper", CLUTTER_UNITS_TO_FLOAT (box->x2 - box->x1),
+                       NULL);
+          
+          /* Make sure value is clamped */
+          prev_value = tidy_adjustment_get_valuex (priv->hadjustment);
+          tidy_adjustment_set_valuex (priv->hadjustment, prev_value);
+        }
+      
+      if (priv->vadjustment)
+        {
+          g_object_set (G_OBJECT (priv->vadjustment),
+                       "lower", 0.0,
+                       "upper", CLUTTER_UNITS_TO_FLOAT (box->y2 - box->y1),
+                       NULL);
+          
+          prev_value = tidy_adjustment_get_valuex (priv->vadjustment);
+          tidy_adjustment_set_valuex (priv->vadjustment, prev_value);
+        }
+    }
+}
+
+static void
+tidy_viewport_class_init (TidyViewportClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (TidyViewportPrivate));
+
+  gobject_class->get_property = tidy_viewport_get_property;
+  gobject_class->set_property = tidy_viewport_set_property;
+  gobject_class->dispose = tidy_viewport_dispose;
+  
+  actor_class->paint = tidy_viewport_paint;
+  actor_class->pick = tidy_viewport_pick;
+  actor_class->allocate = tidy_viewport_allocate;
+  
+  g_object_class_install_property (gobject_class,
+                                   PROP_X_ORIGIN,
+                                   g_param_spec_int ("x-origin",
+                                                     "X Origin",
+                                                     "Origin's X coordinate in pixels",
+                                                     -G_MAXINT, G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_Y_ORIGIN,
+                                   g_param_spec_int ("y-origin",
+                                                     "Y Origin",
+                                                     "Origin's Y coordinate in pixels",
+                                                     -G_MAXINT, G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_Z_ORIGIN,
+                                   g_param_spec_int ("z-origin",
+                                                     "Z Origin",
+                                                     "Origin's Z coordinate in pixels",
+                                                     -G_MAXINT, G_MAXINT,
+                                                     0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_SYNC_ADJUST,
+                                   g_param_spec_boolean ("sync-adjustments",
+                                                         "Synchronise "
+                                                         "adjustments",
+                                                         "Whether to "
+                                                         "synchronise "
+                                                         "adjustments with "
+                                                         "viewport size",
+                                                         TRUE,
+                                                         G_PARAM_READWRITE));
+  
+  g_object_class_override_property (gobject_class,
+                                    PROP_HADJUST,
+                                    "hadjustment");
+
+  g_object_class_override_property (gobject_class,
+                                    PROP_VADJUST,
+                                    "vadjustment");
+}
+
+static void
+hadjustment_value_notify_cb (TidyAdjustment *adjustment,
+                             GParamSpec     *pspec,
+                             TidyViewport   *viewport)
+{
+  TidyViewportPrivate *priv = viewport->priv;
+  ClutterFixed value;
+
+  value = tidy_adjustment_get_valuex (adjustment);
+  
+  tidy_viewport_set_originu (viewport,
+                             CLUTTER_UNITS_FROM_FIXED (value),
+                             priv->y,
+                             priv->z);
+}
+
+static void
+vadjustment_value_notify_cb (TidyAdjustment *adjustment, GParamSpec *arg1,
+                             TidyViewport *viewport)
+{
+  TidyViewportPrivate *priv = viewport->priv;
+  ClutterFixed value;
+
+  value = tidy_adjustment_get_valuex (adjustment);
+  
+  tidy_viewport_set_originu (viewport,
+                             priv->x,
+                             CLUTTER_UNITS_FROM_FIXED (value),
+                             priv->z);
+}
+
+static void
+scrollable_set_adjustments (TidyScrollable *scrollable,
+                            TidyAdjustment *hadjustment,
+                            TidyAdjustment *vadjustment)
+{
+  TidyViewportPrivate *priv = TIDY_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 (TidyScrollable *scrollable,
+                            TidyAdjustment **hadjustment,
+                            TidyAdjustment **vadjustment)
+{
+  TidyViewportPrivate *priv;
+  
+  g_return_if_fail (TIDY_IS_VIEWPORT (scrollable));
+  
+  priv = ((TidyViewport *)scrollable)->priv;
+  
+  if (hadjustment)
+    {
+      if (priv->hadjustment)
+        *hadjustment = priv->hadjustment;
+      else
+        {
+          TidyAdjustment *adjustment;
+          ClutterFixed width, stage_width, increment;
+          
+          width = CLUTTER_UNITS_TO_FIXED(clutter_actor_get_widthu (CLUTTER_ACTOR(scrollable)));
+          stage_width = CLUTTER_UNITS_TO_FIXED(clutter_actor_get_widthu (clutter_stage_get_default ()));
+          increment = MAX (CFX_ONE, MIN(stage_width, width));
+          
+          adjustment = tidy_adjustment_newx (CLUTTER_UNITS_TO_FIXED(priv->x),
+                                             0,
+                                             width,
+                                             CFX_ONE,
+                                             increment,
+                                             increment);
+          scrollable_set_adjustments (scrollable,
+                                      adjustment,
+                                      priv->vadjustment);
+          *hadjustment = adjustment;
+        }
+    }
+  
+  if (vadjustment)
+    {
+      if (priv->vadjustment)
+        *vadjustment = priv->vadjustment;
+      else
+        {
+          TidyAdjustment *adjustment;
+          ClutterFixed height, stage_height, increment;
+          
+          height = CLUTTER_UNITS_TO_FIXED(clutter_actor_get_heightu (CLUTTER_ACTOR(scrollable)));
+          stage_height = CLUTTER_UNITS_TO_FIXED(clutter_actor_get_heightu (clutter_stage_get_default ()));
+          increment = MAX (CFX_ONE, MIN(stage_height, height));
+          
+          adjustment = tidy_adjustment_newx (CLUTTER_UNITS_TO_FIXED(priv->y),
+                                             0,
+                                             height,
+                                             CFX_ONE,
+                                             increment,
+                                             increment);
+          scrollable_set_adjustments (scrollable,
+                                      priv->hadjustment,
+                                      adjustment);
+          *vadjustment = adjustment;
+        }
+    }
+}
+
+static void
+scrollable_interface_init (TidyScrollableInterface *iface)
+{
+  iface->set_adjustments = scrollable_set_adjustments;
+  iface->get_adjustments = scrollable_get_adjustments;
+}
+
+static void
+clip_notify_cb (ClutterActor *actor,
+                GParamSpec   *pspec,
+                TidyViewport *self)
+{
+  gint width, height;
+  TidyViewportPrivate *priv = self->priv;
+  
+  if (!priv->sync_adjustments)
+    return;
+  
+  if (!clutter_actor_has_clip (actor))
+    {
+      if (priv->hadjustment)
+        g_object_set (priv->hadjustment, "page-size", (gdouble)1.0, NULL);
+      if (priv->vadjustment)
+        g_object_set (priv->vadjustment, "page-size", (gdouble)1.0, NULL);
+      return;
+    }
+  
+  clutter_actor_get_clip (actor, NULL, NULL, &width, &height);
+
+  if (priv->hadjustment)
+    g_object_set (priv->hadjustment, "page-size", (gdouble)width, NULL);
+  
+  if (priv->vadjustment)
+    g_object_set (priv->vadjustment, "page-size", (gdouble)height, NULL);
+}
+
+static void
+tidy_viewport_init (TidyViewport *self)
+{
+  self->priv = VIEWPORT_PRIVATE (self);
+  
+  self->priv->sync_adjustments = TRUE;
+  
+  g_signal_connect (self, "notify::clip",
+                    G_CALLBACK (clip_notify_cb), self);
+}
+
+ClutterActor *
+tidy_viewport_new (void)
+{
+  return g_object_new (TIDY_TYPE_VIEWPORT, NULL);
+}
+
+void
+tidy_viewport_set_originu (TidyViewport *viewport,
+                           ClutterUnit   x,
+                           ClutterUnit   y,
+                           ClutterUnit   z)
+{
+  TidyViewportPrivate *priv;
+  
+  g_return_if_fail (TIDY_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)
+        tidy_adjustment_set_valuex (priv->hadjustment,
+                                    CLUTTER_UNITS_TO_FIXED (x));
+    }
+
+  if (y != priv->y)
+    {
+      priv->y = y;
+      g_object_notify (G_OBJECT (viewport), "y-origin");
+
+      if (priv->vadjustment)
+        tidy_adjustment_set_valuex (priv->vadjustment,
+                                    CLUTTER_UNITS_TO_FIXED (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
+tidy_viewport_set_origin (TidyViewport *viewport,
+                          gint          x,
+                          gint          y,
+                          gint          z)
+{
+  g_return_if_fail (TIDY_IS_VIEWPORT (viewport));
+  
+  tidy_viewport_set_originu (viewport,
+                             CLUTTER_UNITS_FROM_DEVICE (x),
+                             CLUTTER_UNITS_FROM_DEVICE (y),
+                             CLUTTER_UNITS_FROM_DEVICE (z));
+}
+
+void
+tidy_viewport_get_originu (TidyViewport *viewport,
+                           ClutterUnit  *x,
+                           ClutterUnit  *y,
+                           ClutterUnit  *z)
+{
+  TidyViewportPrivate *priv;
+  
+  g_return_if_fail (TIDY_IS_VIEWPORT (viewport));
+  
+  priv = viewport->priv;
+  
+  if (x)
+    *x = priv->x;
+
+  if (y)
+    *y = priv->y;
+
+  if (z)
+    *z = priv->z;
+}
+
+void
+tidy_viewport_get_origin (TidyViewport *viewport,
+                          gint         *x,
+                          gint         *y,
+                          gint         *z)
+{
+  TidyViewportPrivate *priv;
+  
+  g_return_if_fail (TIDY_IS_VIEWPORT (viewport));
+  
+  priv = viewport->priv;
+  
+  if (x)
+    *x = CLUTTER_UNITS_TO_DEVICE (priv->x);
+
+  if (y)
+    *y = CLUTTER_UNITS_TO_DEVICE (priv->y);
+
+  if (z)
+    *z = CLUTTER_UNITS_TO_DEVICE (priv->z);
+}
diff --git a/tidy/tidy-viewport.h b/tidy/tidy-viewport.h
new file mode 100644 (file)
index 0000000..eb457bf
--- /dev/null
@@ -0,0 +1,81 @@
+/* tidy-viewport.h: Viewport actor
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Chris Lord <chris@openedhand.com>
+ */
+
+#ifndef __TIDY_VIEWPORT_H__
+#define __TIDY_VIEWPORT_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-group.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_VIEWPORT            (tidy_viewport_get_type())
+#define TIDY_VIEWPORT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_VIEWPORT, TidyViewport))
+#define TIDY_IS_VIEWPORT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_VIEWPORT))
+#define TIDY_VIEWPORT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_VIEWPORT, TidyViewportClass))
+#define TIDY_IS_VIEWPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_VIEWPORT))
+#define TIDY_VIEWPORT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_VIEWPORT, TidyViewportClass))
+
+typedef struct _TidyViewport          TidyViewport;
+typedef struct _TidyViewportPrivate   TidyViewportPrivate;
+typedef struct _TidyViewportClass     TidyViewportClass;
+
+struct _TidyViewport
+{
+  ClutterGroup parent;
+  
+  TidyViewportPrivate *priv;
+};
+
+struct _TidyViewportClass
+{
+  ClutterGroupClass parent_class;
+};
+
+GType tidy_viewport_get_type (void) G_GNUC_CONST;
+
+ClutterActor * tidy_viewport_new         (void);
+
+void           tidy_viewport_set_originu (TidyViewport *viewport,
+                                          ClutterUnit   x,
+                                          ClutterUnit   y,
+                                          ClutterUnit   z);
+
+void           tidy_viewport_set_origin  (TidyViewport *viewport,
+                                          gint          x,
+                                          gint          y,
+                                          gint          z);
+
+void           tidy_viewport_get_originu (TidyViewport *viewport,
+                                          ClutterUnit  *x,
+                                          ClutterUnit  *y,
+                                          ClutterUnit  *z);
+
+void           tidy_viewport_get_origin  (TidyViewport *viewport,
+                                          gint         *x,
+                                          gint         *y,
+                                          gint         *z);
+
+G_END_DECLS
+
+#endif /* __TIDY_VIEWPORT_H__ */
+