gnome-settings-daemon r57 - in trunk: . plugins/mouse



Author: carlosg
Date: Tue Jan 22 16:15:41 2008
New Revision: 57
URL: http://svn.gnome.org/viewvc/gnome-settings-daemon?rev=57&view=rev

Log:
2008-01-22  Carlos Garnacho  <carlosg gnome org>

        * plugins/mouse/gsd-locate-pointer.c: Reworked, add a more appealing
        animation if there's a composite manager present, also use a similar
        animation for the non-composite case, so most of the code is shared.
        * plugins/mouse/gsd-timeline.[ch]: New files, object to control the
        "locate pointer" animation.
        * plugins/mouse/Makefile.am: Added these files to build.


Added:
   trunk/plugins/mouse/gsd-timeline.c
   trunk/plugins/mouse/gsd-timeline.h
Modified:
   trunk/ChangeLog
   trunk/plugins/mouse/Makefile.am
   trunk/plugins/mouse/gsd-locate-pointer.c

Modified: trunk/plugins/mouse/Makefile.am
==============================================================================
--- trunk/plugins/mouse/Makefile.am	(original)
+++ trunk/plugins/mouse/Makefile.am	Tue Jan 22 16:15:41 2008
@@ -21,6 +21,8 @@
 	gsd-mouse-manager.c	\
 	gsd-locate-pointer.h	\
 	gsd-locate-pointer.c	\
+	gsd-timeline.h		\
+	gsd-timeline.c		\
 	$(NULL)
 
 libmouse_la_LDFLAGS = 		\

Modified: trunk/plugins/mouse/gsd-locate-pointer.c
==============================================================================
--- trunk/plugins/mouse/gsd-locate-pointer.c	(original)
+++ trunk/plugins/mouse/gsd-locate-pointer.c	Tue Jan 22 16:15:41 2008
@@ -1,243 +1,293 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* gsd-locate-pointer.c
  *
- * Copyright  2001 Jonathan Blandford <jrb gnome org>
+ * Copyright (C) 2008 Carlos Garnacho  <carlos imendio com>
  *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Red Hat not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  Red Hat makes no representations about the
- * suitability of this software for any purpose.  It is provided "as is"
- * without express or implied warranty.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Authors:  Jonathan Blandford
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  */
 
 #include <gtk/gtk.h>
-
+#include "gsd-timeline.h"
 #include "gsd-locate-pointer.h"
 
-#define LARGE_SIZE 101
-#define SMALL_SIZE 51
+#define ANIMATION_LENGTH 750
+#define WINDOW_SIZE 101
+#define N_CIRCLES 4
+
+/* All circles are supposed to be moving when progress
+ * reaches 0.5, and each of them are supposed to long
+ * for half of the progress, hence the need of 0.5 to
+ * get the circles interval, and the multiplication
+ * by 2 to know a circle progress */
+#define CIRCLES_PROGRESS_INTERVAL (0.5 / N_CIRCLES)
+#define CIRCLE_PROGRESS(p) (MIN (1., ((gdouble) (p) * 2.)))
+
+typedef struct GsdLocatePointerData GsdLocatePointerData;
 
-typedef enum {
-  STAGE_ONE,
-  STAGE_TWO,
-  STAGE_THREE,
-  STAGE_FOUR,
-  STAGE_DONE
-} LocatePointerStage;
-
-static LocatePointerStage stage;
-static GdkWindow *window = NULL;
-static gint cursor_x, cursor_y;
-static guint locate_pointer_id = 0;
-
-static gint
-locate_pointer_expose (GtkWidget      *widget,
-                       GdkEventExpose *event,
-                       gpointer        data)
+struct GsdLocatePointerData
 {
-  gint size;
-  GdkPoint points[4];
+  GsdTimeline *timeline;
+  GtkWidget *widget; 
+  GdkWindow *window;
+
+  gdouble progress;
+};
+
+static GsdLocatePointerData *data = NULL;
+
+static void
+locate_pointer_paint (GsdLocatePointerData *data,
+		      cairo_t              *cr,
+		      gboolean              composite)
+{
+  GdkColor color;
+  gdouble progress, circle_progress;
+  gint width, height, i;
+
+  progress = data->progress;
+  gdk_drawable_get_size (data->window, &width, &height);
+  color = data->widget->style->bg[GTK_STATE_SELECTED];
+
+  cairo_set_source_rgba (cr, 1., 1., 1., 0.);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  cairo_paint (cr);
+
+  for (i = 0; i <= N_CIRCLES; i++)
+    {
+      if (progress < 0.)
+	break;
+
+      circle_progress = MIN (1., (progress * 2));
+      progress -= CIRCLES_PROGRESS_INTERVAL;
+
+      if (circle_progress >= 1.)
+	continue;
 
-  if (event->window != window)
+      if (composite)
+	{
+	  cairo_set_source_rgba (cr,
+				 color.red / 65535.,
+				 color.green / 65535.,
+				 color.blue / 65535.,
+				 1 - circle_progress);
+	  cairo_arc (cr,
+		     width / 2,
+		     height / 2,
+		     circle_progress * width / 2,
+		     0, 2 * G_PI);
+
+	  cairo_fill (cr);
+	  cairo_stroke (cr);
+	}
+      else
+	{
+	  cairo_set_source_rgb (cr, 0., 0., 0.);
+	  cairo_set_line_width (cr, 3.);
+	  cairo_arc (cr,
+		     width / 2,
+		     height / 2,
+		     circle_progress * width / 2,
+		     0, 2 * G_PI);
+	  cairo_stroke (cr);
+
+	  cairo_set_source_rgb (cr, 1., 1., 1.);
+	  cairo_set_line_width (cr, 1.);
+	  cairo_arc (cr,
+		     width / 2,
+		     height / 2,
+		     circle_progress * width / 2,
+		     0, 2 * G_PI);
+	  cairo_stroke (cr);
+	}
+    }
+}
+
+static gboolean
+locate_pointer_expose (GtkWidget *widget,
+		       GdkEventExpose *event,
+		       gpointer        user_data)
+{
+  GsdLocatePointerData *data = (GsdLocatePointerData *) user_data;
+  cairo_t *cr;
+  GdkBitmap *mask;
+
+  if (event->window != data->window)
     return FALSE;
 
-  switch (stage)
+  cr = gdk_cairo_create (data->window);
+
+  if (gtk_widget_is_composited (data->widget))
+    locate_pointer_paint (data, cr, TRUE);
+  else
     {
-    case STAGE_ONE:
-    case STAGE_TWO:
-      size = LARGE_SIZE;
-      break;
-    case STAGE_THREE:
-    case STAGE_FOUR:
-      size = SMALL_SIZE;
-      break;
-    default:
-      return FALSE;
-    }
-
-  gdk_draw_rectangle (event->window,
-                      widget->style->black_gc,
-                      TRUE,
-                      0, 0, size, size);
-  switch (stage)
-    {
-    case STAGE_ONE:
-    case STAGE_THREE:
-      gdk_draw_rectangle (event->window,
-                          widget->style->white_gc,
-                          FALSE,
-                          1, 1, size - 3, size - 3);
-      break;
-    case STAGE_TWO:
-    case STAGE_FOUR:
-      points[0].x = size/2;
-      points[0].y = 0 + 1;
-      points[1].x = size - 2;
-      points[1].y = size/2;
-      points[2].x = size/2;
-      points[2].y = size - 2;
-      points[3].x = 0 + 1;
-      points[3].y = size/2;
-      gdk_draw_polygon (event->window,
-                        widget->style->white_gc,
-                        FALSE, points, 4);
-      break;
-    default:
-      g_assert_not_reached ();
+      locate_pointer_paint (data, cr, FALSE);
+      cairo_destroy (cr);
+
+      /* create a bitmap for the shape, reuse the cairo_t to paint on it */
+      mask = gdk_pixmap_new (data->window, WINDOW_SIZE, WINDOW_SIZE, 1);
+      cr = gdk_cairo_create (mask);
+      locate_pointer_paint (data, cr, FALSE);
+      gdk_window_shape_combine_mask (data->window, mask, 0, 0);
     }
 
+  cairo_destroy (cr);
+
   return TRUE;
 }
 
 static void
-setup_window (void)
+timeline_frame_cb (GtkTimeline *timeline,
+		   gdouble      progress,
+		   gpointer     user_data)
 {
-  gint size;
-  GdkBitmap *mask;
-  GdkGC *gc;
-  GdkColor col;
-  GdkPoint points[4];
+  GsdLocatePointerData *data = (GsdLocatePointerData *) user_data;
 
-  gdk_window_hide (window);
-  switch (stage)
+  if (gtk_widget_is_composited (data->widget))
     {
-    case STAGE_ONE:
-    case STAGE_TWO:
-      size = LARGE_SIZE;
-      break;
-    case STAGE_THREE:
-    case STAGE_FOUR:
-      size = SMALL_SIZE;
-      break;
-    default:
-      return;
-    }
-
-  gdk_window_move_resize (window,
-                          cursor_x - size/2,
-                          cursor_y - size/2,
-                          size, size);
-  mask = gdk_pixmap_new (window, size, size, 1);
-  gc = gdk_gc_new (mask);
-  switch (stage)
+      gdk_window_invalidate_rect (data->window, NULL, FALSE);
+      data->progress = progress;
+    }
+  else if (progress >= data->progress + CIRCLES_PROGRESS_INTERVAL)
     {
-    case STAGE_ONE:
-    case STAGE_THREE:
-      col.pixel = 1;
-      gdk_gc_set_foreground (gc, &col);
-      gdk_draw_rectangle (mask, gc, TRUE, 0, 0, size, size);
-      col.pixel = 0;
-      gdk_gc_set_foreground (gc, &col);
-      gdk_draw_rectangle (mask, gc, TRUE, 3, 3, size - 6, size - 6);
-      break;
-    case STAGE_TWO:
-    case STAGE_FOUR:
-      col.pixel = 0;
-      gdk_gc_set_foreground (gc, &col);
-      gdk_draw_rectangle (mask, gc, TRUE, 0, 0, size, size);
-      col.pixel = 1;
-      gdk_gc_set_foreground (gc, &col);
-      points[0].x = size/2;
-      points[0].y = 0;
-      points[1].x = size - 1;
-      points[1].y = size/2;
-      points[2].x = size/2;
-      points[2].y = size - 1;
-      points[3].x = 0;
-      points[3].y = size/2;
-      gdk_draw_polygon (mask, gc, FALSE, points, 4);
-      points[0].x = size/2;
-      points[0].y = 0 + 1;
-      points[1].x = size - 2;
-      points[1].y = size/2;
-      points[2].x = size/2;
-      points[2].y = size - 2;
-      points[3].x = 0 + 1;
-      points[3].y = size/2;
-      gdk_draw_polygon (mask, gc, FALSE, points, 4);
-      points[0].x = size/2;
-      points[0].y = 0 + 2;
-      points[1].x = size - 3;
-      points[1].y = size/2;
-      points[2].x = size/2;
-      points[2].y = size - 3;
-      points[3].x = 0 + 2;
-      points[3].y = size/2;
-      gdk_draw_polygon (mask, gc, FALSE, points, 4);
-      break;
-    default:
-      g_assert_not_reached ();
-    }
-
-  gdk_window_shape_combine_mask (window, mask, 0, 0);
-  g_object_unref (G_OBJECT (gc));
-  g_object_unref (G_OBJECT (mask));
-  gdk_window_show (window);
+      /* only invalidate window each circle interval */
+      gdk_window_invalidate_rect (data->window, NULL, FALSE);
+      data->progress += CIRCLES_PROGRESS_INTERVAL;
+    }
+}
+
+static void
+timeline_finished_cb (GtkTimeline *timeline,
+		      gpointer     user_data)
+{
+  GsdLocatePointerData *data = (GsdLocatePointerData *) user_data;
+
+  /* hide window and unset shape */
+  gdk_window_hide (data->window);
+  gdk_window_shape_combine_mask (data->window, NULL, 0, 0);
 }
 
 static void
-create_window (GdkScreen *screen)
+create_window (GsdLocatePointerData *data,
+	       GdkScreen            *screen)
 {
+  GdkColormap *colormap;
+  GdkVisual *visual;
   GdkWindowAttr attributes;
-  GtkWidget *invisible;
 
-  invisible = gtk_invisible_new_for_screen (screen);
+  colormap = gdk_screen_get_rgba_colormap (screen);
+  visual = gdk_screen_get_rgba_visual (screen);
+
+  if (!colormap)
+    {
+      colormap = gdk_screen_get_rgb_colormap (screen);
+      visual = gdk_screen_get_rgb_visual (screen);
+    }
 
   attributes.window_type = GDK_WINDOW_TEMP;
   attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.visual = gtk_widget_get_visual (invisible);
-  attributes.colormap = gtk_widget_get_colormap (invisible);
+  attributes.visual = visual;
+  attributes.colormap = colormap;
   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
   attributes.width = 1;
   attributes.height = 1;
-  window = gdk_window_new (gdk_screen_get_root_window (screen),
-                           &attributes,
-                           GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP);
-  gdk_window_set_user_data (window, invisible);
-  g_signal_connect (G_OBJECT (invisible),
-                    "expose_event",
-                    (GCallback) locate_pointer_expose,
-                    NULL);
+
+  data->window = gdk_window_new (gdk_screen_get_root_window (screen),
+				 &attributes,
+				 GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP);
+
+  gdk_window_set_user_data (data->window, data->widget);
 }
 
-static gboolean
-locate_pointer_timeout (gpointer data)
+static GsdLocatePointerData *
+gsd_locate_pointer_data_new (GdkScreen *screen)
 {
-  stage++;
-  if (stage == STAGE_DONE)
-    {
-      gdk_window_hide (window);
-      locate_pointer_id = 0;
-      return FALSE;
-    }
-  setup_window ();
-  return TRUE;
+  GsdLocatePointerData *data;
+
+  data = g_new0 (GsdLocatePointerData, 1);
+
+  /* this widget will never be shown, it's
+   * mainly used to get signals/events from
+   */
+  data->widget = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_widget_realize (data->widget);
+
+  g_signal_connect (G_OBJECT (data->widget), "expose_event",
+                    G_CALLBACK (locate_pointer_expose),
+                    data);
+
+  data->timeline = gsd_timeline_new (ANIMATION_LENGTH);
+  g_signal_connect (data->timeline, "frame",
+		    G_CALLBACK (timeline_frame_cb), data);
+  g_signal_connect (data->timeline, "finished",
+		    G_CALLBACK (timeline_finished_cb), data);
+
+  create_window (data, screen);
+
+  return data;
+}
+
+static void
+move_locate_pointer_window (GsdLocatePointerData *data,
+			    GdkScreen            *screen)
+{
+  gint cursor_x, cursor_y;
+  GdkBitmap *mask;
+  GdkColor col;
+  GdkGC *gc;
+
+  gdk_window_get_pointer (gdk_screen_get_root_window (screen), &cursor_x, &cursor_y, NULL);
+
+  gdk_window_move_resize (data->window,
+                          cursor_x - WINDOW_SIZE / 2,
+                          cursor_y - WINDOW_SIZE / 2,
+                          WINDOW_SIZE, WINDOW_SIZE);
+
+  col.pixel = 0;
+  mask = gdk_pixmap_new (data->window, WINDOW_SIZE, WINDOW_SIZE, 1);
+
+  gc = gdk_gc_new (mask);
+  gdk_gc_set_foreground (gc, &col);
+  gdk_draw_rectangle (mask, gc, TRUE, 0, 0, WINDOW_SIZE, WINDOW_SIZE);
+
+  /* allow events to happen through the window */
+  gdk_window_input_shape_combine_mask (data->window, mask, 0, 0);
+
+  g_object_unref (mask);
+  g_object_unref (gc);
 }
 
 void
 gsd_locate_pointer (GdkScreen *screen)
 {
-  gdk_window_get_pointer (gdk_screen_get_root_window (screen), &cursor_x, &cursor_y, NULL);
+  if (!data)
+    data = gsd_locate_pointer_data_new (screen);
 
-  if (locate_pointer_id)
-    gtk_timeout_remove (locate_pointer_id);
+  gsd_timeline_pause (data->timeline);
+  gsd_timeline_rewind (data->timeline);
 
-  /* Create the window if it is not created OR if it is not for the
-   * current screen.
-   */
+  /* Create again the window if it is not for the current screen */
+  if (gdk_screen_get_number (screen) != gdk_screen_get_number (gdk_drawable_get_screen (data->window)))
+    {
+      gdk_window_set_user_data (data->window, NULL);
+      gdk_window_destroy (data->window);
+
+      create_window (data, screen);
+    }
+
+  data->progress = 0.;
+  gdk_window_show (data->window);
+  move_locate_pointer_window (data, screen);
 
-  if (window == NULL)
-    create_window (screen);
-  else if( gdk_screen_get_number (screen) != gdk_screen_get_number (gdk_drawable_get_screen (window)))
-    create_window (screen);
-
-  stage = STAGE_ONE;
-  setup_window ();
-  gdk_window_show (window);
-  locate_pointer_id = gtk_timeout_add (100, locate_pointer_timeout, NULL);
+  gsd_timeline_start (data->timeline);
 }

Added: trunk/plugins/mouse/gsd-timeline.c
==============================================================================
--- (empty file)
+++ trunk/plugins/mouse/gsd-timeline.c	Tue Jan 22 16:15:41 2008
@@ -0,0 +1,848 @@
+/* gsd-timeline.c
+ *
+ * Copyright (C) 2008 Carlos Garnacho  <carlos imendio com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <math.h>
+#include "gsd-timeline.h"
+
+#define GSD_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSD_TYPE_TIMELINE, GsdTimelinePriv))
+#define MSECS_PER_SEC 1000
+#define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes)
+#define DEFAULT_FPS 30
+
+typedef struct GsdTimelinePriv GsdTimelinePriv;
+
+struct GsdTimelinePriv
+{
+  guint duration;
+  guint fps;
+  guint source_id;
+
+  GTimer *timer;
+
+  GdkScreen *screen;
+  GsdTimelineProgressType progress_type;
+  GsdTimelineProgressFunc progress_func;
+
+  guint loop      : 1;
+  guint direction : 1;
+};
+
+enum {
+  PROP_0,
+  PROP_FPS,
+  PROP_DURATION,
+  PROP_LOOP,
+  PROP_DIRECTION,
+  PROP_SCREEN,
+  PROP_PROGRESS_TYPE,
+};
+
+enum {
+  STARTED,
+  PAUSED,
+  FINISHED,
+  FRAME,
+  LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+
+static void  gsd_timeline_set_property  (GObject         *object,
+					 guint            prop_id,
+					 const GValue    *value,
+					 GParamSpec      *pspec);
+static void  gsd_timeline_get_property  (GObject         *object,
+					 guint            prop_id,
+					 GValue          *value,
+					 GParamSpec      *pspec);
+static void  gsd_timeline_finalize      (GObject *object);
+
+
+G_DEFINE_TYPE (GsdTimeline, gsd_timeline, G_TYPE_OBJECT)
+
+
+GType
+gsd_timeline_direction_get_type (void)
+{
+  static GType type = 0;
+
+  if (G_UNLIKELY (type == 0))
+    {
+      static const GEnumValue values[] = {
+	{ GSD_TIMELINE_DIRECTION_FORWARD,  "GSD_TIMELINE_DIRECTION_FORWARD",  "forward" },
+	{ GSD_TIMELINE_DIRECTION_BACKWARD, "GSD_TIMELINE_DIRECTION_BACKWARD", "backward" },
+	{ 0, NULL, NULL }
+      };
+
+      type = g_enum_register_static (g_intern_static_string ("GsdTimelineDirection"), values);
+    }
+
+  return type;
+}
+
+GType
+gsd_timeline_progress_type_get_type (void)
+{
+  static GType type = 0;
+
+  if (G_UNLIKELY (type == 0))
+    {
+      static const GEnumValue values[] = {
+	{ GSD_TIMELINE_PROGRESS_LINEAR,      "GSD_TIMELINE_PROGRESS_LINEAR",      "linear" },
+	{ GSD_TIMELINE_PROGRESS_SINUSOIDAL,  "GSD_TIMELINE_PROGRESS_SINUSOIDAL",  "sinusoidal" },
+	{ GSD_TIMELINE_PROGRESS_EXPONENTIAL, "GSD_TIMELINE_PROGRESS_EXPONENTIAL", "exponential" },
+	{ 0, NULL, NULL }
+      };
+
+      type = g_enum_register_static (g_intern_static_string ("GsdTimelineProgressType"), values);
+    }
+
+  return type;
+}
+
+static void
+gsd_timeline_class_init (GsdTimelineClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->set_property = gsd_timeline_set_property;
+  object_class->get_property = gsd_timeline_get_property;
+  object_class->finalize = gsd_timeline_finalize;
+
+  g_object_class_install_property (object_class,
+				   PROP_FPS,
+				   g_param_spec_uint ("fps",
+						      "FPS",
+						      "Frames per second for the timeline",
+						      1,
+						      G_MAXUINT,
+						      DEFAULT_FPS,
+						      G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+				   PROP_DURATION,
+				   g_param_spec_uint ("duration",
+						      "Animation Duration",
+						      "Animation Duration",
+						      0,
+						      G_MAXUINT,
+						      0,
+						      G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+				   PROP_LOOP,
+				   g_param_spec_boolean ("loop",
+							 "Loop",
+							 "Whether the timeline loops or not",
+							 FALSE,
+							 G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+				   PROP_DIRECTION,
+				   g_param_spec_enum ("direction",
+						      "Direction",
+						      "Whether the timeline moves forward or backward in time",
+						      GSD_TYPE_TIMELINE_DIRECTION,
+						      GSD_TIMELINE_DIRECTION_FORWARD,
+						      G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+				   PROP_DIRECTION,
+				   g_param_spec_enum ("progress-type",
+						      "Progress type",
+						      "Type of progress through the timeline",
+						      GSD_TYPE_TIMELINE_PROGRESS_TYPE,
+						      GSD_TIMELINE_PROGRESS_LINEAR,
+						      G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+				   PROP_SCREEN,
+				   g_param_spec_object ("screen",
+							"Screen",
+							"Screen to get the settings from",
+							GDK_TYPE_SCREEN,
+							G_PARAM_READWRITE));
+
+  signals[STARTED] =
+    g_signal_new ("started",
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GsdTimelineClass, started),
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  signals[PAUSED] =
+    g_signal_new ("paused",
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GsdTimelineClass, paused),
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  signals[FINISHED] =
+    g_signal_new ("finished",
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GsdTimelineClass, finished),
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  signals[FRAME] =
+    g_signal_new ("frame",
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GsdTimelineClass, frame),
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__DOUBLE,
+		  G_TYPE_NONE, 1,
+		  G_TYPE_DOUBLE);
+
+  g_type_class_add_private (class, sizeof (GsdTimelinePriv));
+}
+
+static void
+gsd_timeline_init (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  priv->fps = DEFAULT_FPS;
+  priv->duration = 0;
+  priv->direction = GSD_TIMELINE_DIRECTION_FORWARD;
+  priv->screen = gdk_screen_get_default ();
+}
+
+static void
+gsd_timeline_set_property (GObject      *object,
+			   guint         prop_id,
+			   const GValue *value,
+			   GParamSpec   *pspec)
+{
+  GsdTimeline *timeline;
+  GsdTimelinePriv *priv;
+
+  timeline = GSD_TIMELINE (object);
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  switch (prop_id)
+    {
+    case PROP_FPS:
+      gsd_timeline_set_fps (timeline, g_value_get_uint (value));
+      break;
+    case PROP_DURATION:
+      gsd_timeline_set_duration (timeline, g_value_get_uint (value));
+      break;
+    case PROP_LOOP:
+      gsd_timeline_set_loop (timeline, g_value_get_boolean (value));
+      break;
+    case PROP_DIRECTION:
+      gsd_timeline_set_direction (timeline, g_value_get_enum (value));
+      break;
+    case PROP_SCREEN:
+      gsd_timeline_set_screen (timeline,
+			       GDK_SCREEN (g_value_get_object (value)));
+      break;
+    case PROP_PROGRESS_TYPE:
+      gsd_timeline_set_progress_type (timeline, g_value_get_enum (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gsd_timeline_get_property (GObject    *object,
+			   guint       prop_id,
+			   GValue     *value,
+			   GParamSpec *pspec)
+{
+  GsdTimeline *timeline;
+  GsdTimelinePriv *priv;
+
+  timeline = GSD_TIMELINE (object);
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  switch (prop_id)
+    {
+    case PROP_FPS:
+      g_value_set_uint (value, priv->fps);
+      break;
+    case PROP_DURATION:
+      g_value_set_uint (value, priv->duration);
+      break;
+    case PROP_LOOP:
+      g_value_set_boolean (value, priv->loop);
+      break;
+    case PROP_DIRECTION:
+      g_value_set_enum (value, priv->direction);
+      break;
+    case PROP_SCREEN:
+      g_value_set_object (value, priv->screen);
+      break;
+    case PROP_PROGRESS_TYPE:
+      g_value_set_enum (value, priv->progress_type);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gsd_timeline_finalize (GObject *object)
+{
+  GsdTimelinePriv *priv;
+
+  priv = GSD_TIMELINE_GET_PRIV (object);
+
+  if (priv->source_id)
+    {
+      g_source_remove (priv->source_id);
+      priv->source_id = 0;
+    }
+
+  if (priv->timer)
+      g_timer_destroy (priv->timer);
+
+  G_OBJECT_CLASS (gsd_timeline_parent_class)->finalize (object);
+}
+
+/* Sinusoidal progress */
+static gdouble
+sinusoidal_progress (gdouble progress)
+{
+  return (sinf ((progress * G_PI) / 2));
+}
+
+static gdouble
+exponential_progress (gdouble progress)
+{
+  return progress * progress;
+}
+
+static GsdTimelineProgressFunc
+progress_type_to_func (GsdTimelineProgressType type)
+{
+  if (type == GSD_TIMELINE_PROGRESS_SINUSOIDAL)
+    return sinusoidal_progress;
+  else if (type == GSD_TIMELINE_PROGRESS_EXPONENTIAL)
+    return exponential_progress;
+
+  return NULL;
+}
+
+static gboolean
+gsd_timeline_run_frame (GsdTimeline *timeline,
+			gboolean     enable_animations)
+{
+  GsdTimelinePriv *priv;
+  gdouble linear_progress, progress;
+  guint elapsed_time;
+  GsdTimelineProgressFunc progress_func = NULL;
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  if (enable_animations)
+    {
+      elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
+
+      linear_progress = (gdouble) elapsed_time / priv->duration;
+
+      if (priv->direction == GSD_TIMELINE_DIRECTION_BACKWARD)
+	linear_progress = 1 - linear_progress;
+
+      linear_progress = CLAMP (linear_progress, 0., 1.);
+
+      if (priv->progress_func)
+	progress_func = priv->progress_func;
+      else if (priv->progress_type)
+	progress_func = progress_type_to_func (priv->progress_type);
+
+      if (progress_func)
+	progress = (progress_func) (linear_progress);
+      else
+	progress = linear_progress;
+    }
+  else
+    progress = (priv->direction == GSD_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0;
+
+  g_signal_emit (timeline, signals [FRAME], 0,
+		 CLAMP (progress, 0.0, 1.0));
+
+  if ((priv->direction == GSD_TIMELINE_DIRECTION_FORWARD && progress >= 1.0) ||
+      (priv->direction == GSD_TIMELINE_DIRECTION_BACKWARD && progress <= 0.0))
+    {
+      if (!priv->loop)
+	{
+	  if (priv->source_id)
+	    {
+	      g_source_remove (priv->source_id);
+	      priv->source_id = 0;
+	    }
+
+	  g_signal_emit (timeline, signals [FINISHED], 0);
+	  return FALSE;
+	}
+      else
+	gsd_timeline_rewind (timeline);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+gsd_timeline_frame_idle_func (GsdTimeline *timeline)
+{
+  return gsd_timeline_run_frame (timeline, TRUE);
+}
+
+/**
+ * gsd_timeline_new:
+ * @duration: duration in milliseconds for the timeline
+ *
+ * Creates a new #GsdTimeline with the specified number of frames.
+ *
+ * Return Value: the newly created #GsdTimeline
+ **/
+GsdTimeline *
+gsd_timeline_new (guint duration)
+{
+  return g_object_new (GSD_TYPE_TIMELINE,
+		       "duration", duration,
+		       NULL);
+}
+
+GsdTimeline *
+gsd_timeline_new_for_screen (guint      duration,
+			     GdkScreen *screen)
+{
+  return g_object_new (GSD_TYPE_TIMELINE,
+		       "duration", duration,
+		       "screen", screen,
+		       NULL);
+}
+
+/**
+ * gsd_timeline_start:
+ * @timeline: A #GsdTimeline
+ *
+ * Runs the timeline from the current frame.
+ **/
+void
+gsd_timeline_start (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+  GtkSettings *settings;
+  gboolean enable_animations = FALSE;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  if (priv->screen)
+    {
+      settings = gtk_settings_get_for_screen (priv->screen);
+      g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL);
+    }
+
+  if (enable_animations)
+    {
+      if (!priv->source_id)
+	{
+	  if (priv->timer)
+	    g_timer_continue (priv->timer);
+	  else
+	    priv->timer = g_timer_new ();
+
+	  /* sanity check */
+	  g_assert (priv->fps > 0);
+
+	  g_signal_emit (timeline, signals [STARTED], 0);
+
+	  priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps),
+						     (GSourceFunc) gsd_timeline_frame_idle_func,
+						     timeline);
+	}
+    }
+  else
+    {
+      /* If animations are not enabled, only run the last frame,
+       * it take us instantaneously to the last state of the animation.
+       * The only potential flaw happens when people use the ::finished
+       * signal to trigger another animation, or even worse, finally
+       * loop into this animation again.
+       */
+      g_signal_emit (timeline, signals [STARTED], 0);
+      gsd_timeline_run_frame (timeline, FALSE);
+    }
+}
+
+/**
+ * gsd_timeline_pause:
+ * @timeline: A #GsdTimeline
+ *
+ * Pauses the timeline.
+ **/
+void
+gsd_timeline_pause (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  if (priv->source_id)
+    {
+      g_source_remove (priv->source_id);
+      priv->source_id = 0;
+      g_timer_stop (priv->timer);
+      g_signal_emit (timeline, signals [PAUSED], 0);
+    }
+}
+
+/**
+ * gsd_timeline_rewind:
+ * @timeline: A #GsdTimeline
+ *
+ * Rewinds the timeline.
+ **/
+void
+gsd_timeline_rewind (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  /* destroy and re-create timer if neccesary  */
+  if (priv->timer)
+    {
+      g_timer_destroy (priv->timer);
+
+      if (gsd_timeline_is_running (timeline))
+	priv->timer = g_timer_new ();
+      else
+	priv->timer = NULL;
+    }
+}
+
+/**
+ * gsd_timeline_is_running:
+ * @timeline: A #GsdTimeline
+ *
+ * Returns whether the timeline is running or not.
+ *
+ * Return Value: %TRUE if the timeline is running
+ **/
+gboolean
+gsd_timeline_is_running (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_val_if_fail (GSD_IS_TIMELINE (timeline), FALSE);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  return (priv->source_id != 0);
+}
+
+/**
+ * gsd_timeline_get_fps:
+ * @timeline: A #GsdTimeline
+ *
+ * Returns the number of frames per second.
+ *
+ * Return Value: frames per second
+ **/
+guint
+gsd_timeline_get_fps (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_val_if_fail (GSD_IS_TIMELINE (timeline), 1);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+  return priv->fps;
+}
+
+/**
+ * gsd_timeline_set_fps:
+ * @timeline: A #GsdTimeline
+ * @fps: frames per second
+ *
+ * Sets the number of frames per second that
+ * the timeline will play.
+ **/
+void
+gsd_timeline_set_fps (GsdTimeline *timeline,
+		      guint        fps)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+  g_return_if_fail (fps > 0);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  priv->fps = fps;
+
+  if (gsd_timeline_is_running (timeline))
+    {
+      g_source_remove (priv->source_id);
+      priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps),
+						 (GSourceFunc) gsd_timeline_run_frame,
+						 timeline);
+    }
+
+  g_object_notify (G_OBJECT (timeline), "fps");
+}
+
+/**
+ * gsd_timeline_get_loop:
+ * @timeline: A #GsdTimeline
+ *
+ * Returns whether the timeline loops to the
+ * beginning when it has reached the end.
+ *
+ * Return Value: %TRUE if the timeline loops
+ **/
+gboolean
+gsd_timeline_get_loop (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_val_if_fail (GSD_IS_TIMELINE (timeline), FALSE);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+  return priv->loop;
+}
+
+/**
+ * gsd_timeline_set_loop:
+ * @timeline: A #GsdTimeline
+ * @loop: %TRUE to make the timeline loop
+ *
+ * Sets whether the timeline loops to the beginning
+ * when it has reached the end.
+ **/
+void
+gsd_timeline_set_loop (GsdTimeline *timeline,
+		       gboolean     loop)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+  priv->loop = loop;
+
+  g_object_notify (G_OBJECT (timeline), "loop");
+}
+
+void
+gsd_timeline_set_duration (GsdTimeline *timeline,
+			   guint        duration)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  priv->duration = duration;
+
+  g_object_notify (G_OBJECT (timeline), "duration");
+}
+
+guint
+gsd_timeline_get_duration (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_val_if_fail (GSD_IS_TIMELINE (timeline), 0);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  return priv->duration;
+}
+
+/**
+ * gsd_timeline_get_direction:
+ * @timeline: A #GsdTimeline
+ *
+ * Returns the direction of the timeline.
+ *
+ * Return Value: direction
+ **/
+GsdTimelineDirection
+gsd_timeline_get_direction (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_val_if_fail (GSD_IS_TIMELINE (timeline), GSD_TIMELINE_DIRECTION_FORWARD);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+  return priv->direction;
+}
+
+/**
+ * gsd_timeline_set_direction:
+ * @timeline: A #GsdTimeline
+ * @direction: direction
+ *
+ * Sets the direction of the timeline.
+ **/
+void
+gsd_timeline_set_direction (GsdTimeline          *timeline,
+			    GsdTimelineDirection  direction)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+  priv->direction = direction;
+
+  g_object_notify (G_OBJECT (timeline), "direction");
+}
+
+GdkScreen *
+gsd_timeline_get_screen (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_val_if_fail (GSD_IS_TIMELINE (timeline), NULL);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+  return priv->screen;
+}
+
+void
+gsd_timeline_set_screen (GsdTimeline *timeline,
+			 GdkScreen   *screen)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  if (priv->screen)
+    g_object_unref (priv->screen);
+
+  priv->screen = g_object_ref (screen);
+
+  g_object_notify (G_OBJECT (timeline), "screen");
+}
+
+void
+gsd_timeline_set_progress_type (GsdTimeline             *timeline,
+				GsdTimelineProgressType  type)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  priv->progress_type = type;
+
+  g_object_notify (G_OBJECT (timeline), "progress-type");
+}
+
+GsdTimelineProgressType
+gsd_timeline_get_progress_type (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_val_if_fail (GSD_IS_TIMELINE (timeline), GSD_TIMELINE_PROGRESS_LINEAR);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  if (priv->progress_func)
+    return GSD_TIMELINE_PROGRESS_LINEAR;
+
+  return priv->progress_type;
+}
+
+/**
+ * gsd_timeline_set_progress_func:
+ * @timeline: A #GsdTimeline
+ * @progress_func: progress function
+ *
+ * Sets the progress function. This function will be used to calculate
+ * a different progress to pass to the ::frame signal based on the
+ * linear progress through the timeline. Setting progress_func
+ * to %NULL will make the timeline use the default function,
+ * which is just a linear progress.
+ *
+ * All progresses are in the [0.0, 1.0] range.
+ **/
+void
+gsd_timeline_set_progress_func (GsdTimeline             *timeline,
+				GsdTimelineProgressFunc  progress_func)
+{
+  GsdTimelinePriv *priv;
+
+  g_return_if_fail (GSD_IS_TIMELINE (timeline));
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+  priv->progress_func = progress_func;
+}
+
+gdouble
+gsd_timeline_get_progress (GsdTimeline *timeline)
+{
+  GsdTimelinePriv *priv;
+  GsdTimelineProgressFunc progress_func = NULL;
+  gdouble linear_progress, progress;
+  guint elapsed_time;
+
+  g_return_val_if_fail (GSD_IS_TIMELINE (timeline), 0.0);
+
+  priv = GSD_TIMELINE_GET_PRIV (timeline);
+
+  if (!priv->timer)
+    return 0.;
+
+  elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
+
+  linear_progress = (gdouble) elapsed_time / priv->duration;
+
+  if (priv->direction == GSD_TIMELINE_DIRECTION_BACKWARD)
+    linear_progress = 1 - linear_progress;
+
+  linear_progress = CLAMP (linear_progress, 0., 1.);
+
+  if (priv->progress_func)
+    progress_func = priv->progress_func;
+  else if (priv->progress_type)
+    progress_func = progress_type_to_func (priv->progress_type);
+
+  if (progress_func)
+    progress = (progress_func) (linear_progress);
+  else
+    progress = linear_progress;
+
+  return CLAMP (progress, 0., 1.);
+}

Added: trunk/plugins/mouse/gsd-timeline.h
==============================================================================
--- (empty file)
+++ trunk/plugins/mouse/gsd-timeline.h	Tue Jan 22 16:15:41 2008
@@ -0,0 +1,123 @@
+/* gsdtimeline.c
+ *
+ * Copyright (C) 2008 Carlos Garnacho  <carlos imendio com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GSD_TIMELINE_H__
+#define __GSD_TIMELINE_H__
+
+#include <glib-object.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_TIMELINE_DIRECTION       (gsd_timeline_direction_get_type ())
+#define GSD_TYPE_TIMELINE_PROGRESS_TYPE   (gsd_timeline_progress_type_get_type ())
+#define GSD_TYPE_TIMELINE                 (gsd_timeline_get_type ())
+#define GSD_TIMELINE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_TIMELINE, GsdTimeline))
+#define GSD_TIMELINE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass),  GSD_TYPE_TIMELINE, GsdTimelineClass))
+#define GSD_IS_TIMELINE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSD_TYPE_TIMELINE))
+#define GSD_IS_TIMELINE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass),  GSD_TYPE_TIMELINE))
+#define GSD_TIMELINE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj),  GSD_TYPE_TIMELINE, GsdTimelineClass))
+
+typedef enum {
+  GSD_TIMELINE_DIRECTION_FORWARD,
+  GSD_TIMELINE_DIRECTION_BACKWARD
+} GsdTimelineDirection;
+
+typedef enum {
+  GSD_TIMELINE_PROGRESS_LINEAR,
+  GSD_TIMELINE_PROGRESS_SINUSOIDAL,
+  GSD_TIMELINE_PROGRESS_EXPONENTIAL
+} GsdTimelineProgressType;
+
+typedef struct GsdTimeline      GsdTimeline;
+typedef struct GsdTimelineClass GsdTimelineClass;
+
+struct GsdTimeline
+{
+  GObject parent_instance;
+};
+
+struct GsdTimelineClass
+{
+  GObjectClass parent_class;
+
+  void (* started)           (GsdTimeline *timeline);
+  void (* finished)          (GsdTimeline *timeline);
+  void (* paused)            (GsdTimeline *timeline);
+
+  void (* frame)             (GsdTimeline *timeline,
+			      gdouble      progress);
+
+  void (* __gsd_reserved1) (void);
+  void (* __gsd_reserved2) (void);
+  void (* __gsd_reserved3) (void);
+  void (* __gsd_reserved4) (void);
+};
+
+typedef gdouble (*GsdTimelineProgressFunc) (gdouble progress);
+
+
+GType                   gsd_timeline_get_type           (void) G_GNUC_CONST;
+GType                   gsd_timeline_direction_get_type (void) G_GNUC_CONST;
+GType                   gsd_timeline_progress_type_get_type (void) G_GNUC_CONST;
+
+GsdTimeline            *gsd_timeline_new                (guint                    duration);
+GsdTimeline            *gsd_timeline_new_for_screen     (guint                    duration,
+							 GdkScreen               *screen);
+
+void                    gsd_timeline_start              (GsdTimeline             *timeline);
+void                    gsd_timeline_pause              (GsdTimeline             *timeline);
+void                    gsd_timeline_rewind             (GsdTimeline             *timeline);
+
+gboolean                gsd_timeline_is_running         (GsdTimeline             *timeline);
+
+guint                   gsd_timeline_get_fps            (GsdTimeline             *timeline);
+void                    gsd_timeline_set_fps            (GsdTimeline             *timeline,
+							 guint                    fps);
+
+gboolean                gsd_timeline_get_loop           (GsdTimeline             *timeline);
+void                    gsd_timeline_set_loop           (GsdTimeline             *timeline,
+							 gboolean                 loop);
+
+guint                   gsd_timeline_get_duration       (GsdTimeline             *timeline);
+void                    gsd_timeline_set_duration       (GsdTimeline             *timeline,
+							 guint                    duration);
+
+GdkScreen              *gsd_timeline_get_screen         (GsdTimeline             *timeline);
+void                    gsd_timeline_set_screen         (GsdTimeline             *timeline,
+							 GdkScreen               *screen);
+
+GsdTimelineDirection    gsd_timeline_get_direction      (GsdTimeline             *timeline);
+void                    gsd_timeline_set_direction      (GsdTimeline             *timeline,
+							 GsdTimelineDirection     direction);
+
+GsdTimelineProgressType gsd_timeline_get_progress_type  (GsdTimeline             *timeline);
+void                    gsd_timeline_set_progress_type  (GsdTimeline             *timeline,
+							 GsdTimelineProgressType  type);
+void                    gsd_timeline_get_progress_func  (GsdTimeline             *timeline);
+
+void                    gsd_timeline_set_progress_func  (GsdTimeline             *timeline,
+							 GsdTimelineProgressFunc  progress_func);
+
+gdouble                 gsd_timeline_get_progress       (GsdTimeline             *timeline);
+
+
+G_END_DECLS
+
+#endif /* __GSD_TIMELINE_H__ */



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