[clutter/wip/actor-content: 25/25] Add ClutterDrawingArea



commit 351bf8500c258dd1cc4c24cf587217ae3e02350f
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Wed Apr 13 18:39:44 2011 +0100

    Add ClutterDrawingArea

 clutter/Makefile.am                   |    2 +
 clutter/clutter-cairo-texture.c       |   27 +---
 clutter/clutter-drawing-area.c        |  317 +++++++++++++++++++++++++++++++++
 clutter/clutter-drawing-area.h        |   61 +++++++
 clutter/clutter-main.c                |   16 ++-
 clutter/clutter-marshal.list          |    2 +
 clutter/clutter-private.h             |   13 ++
 clutter/clutter.h                     |    1 +
 tests/interactive/Makefile.am         |    3 +-
 tests/interactive/test-drawing-area.c |  104 +++++++++++
 10 files changed, 520 insertions(+), 26 deletions(-)
---
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 024b018..c9cffda 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -108,6 +108,7 @@ source_h =					\
 	$(srcdir)/clutter-desaturate-effect.h	\
 	$(srcdir)/clutter-device-manager.h	\
 	$(srcdir)/clutter-drag-action.h		\
+	$(srcdir)/clutter-drawing-area.h	\
 	$(srcdir)/clutter-effect.h		\
 	$(srcdir)/clutter-event.h 		\
 	$(srcdir)/clutter-feature.h 		\
@@ -195,6 +196,7 @@ source_c = \
 	$(srcdir)/clutter-desaturate-effect.c	\
 	$(srcdir)/clutter-device-manager.c	\
 	$(srcdir)/clutter-drag-action.c		\
+	$(srcdir)/clutter-drawing-area.c	\
 	$(srcdir)/clutter-effect.c		\
 	$(srcdir)/clutter-event.c 		\
 	$(srcdir)/clutter-feature.c 		\
diff --git a/clutter/clutter-cairo-texture.c b/clutter/clutter-cairo-texture.c
index 7931c05..2168abf 100644
--- a/clutter/clutter-cairo-texture.c
+++ b/clutter/clutter-cairo-texture.c
@@ -125,15 +125,6 @@ static guint cairo_signals[LAST_SIGNAL] = { 0, };
 
 #define CLUTTER_CAIRO_TEXTURE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_CAIRO_TEXTURE, ClutterCairoTexturePrivate))
 
-/* Cairo stores the data in native byte order as ARGB but Cogl's pixel
-   formats specify the actual byte order. Therefore we need to use a
-   different format depending on the architecture */
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-#define CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT COGL_PIXEL_FORMAT_BGRA_8888_PRE
-#else
-#define CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT COGL_PIXEL_FORMAT_ARGB_8888_PRE
-#endif
-
 struct _ClutterCairoTexturePrivate
 {
   cairo_surface_t *cr_surface;
@@ -356,7 +347,7 @@ clutter_cairo_texture_create_surface (ClutterCairoTexture *self,
   /* create a backing Cogl texture */
   cogl_texture = cogl_texture_new_from_data (width, height,
                                              COGL_TEXTURE_NONE,
-                                             CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
+                                             CLUTTER_CAIRO_PIXEL_FORMAT,
                                              COGL_PIXEL_FORMAT_ANY,
                                              cairo_stride,
                                              cairo_data);
@@ -366,18 +357,6 @@ clutter_cairo_texture_create_surface (ClutterCairoTexture *self,
   return surface;
 }
 
-static gboolean
-create_surface_accum (GSignalInvocationHint *ihint,
-                      GValue                *return_accu,
-                      const GValue          *handler_return,
-                      gpointer               data)
-{
-  g_value_copy (handler_return, return_accu);
-
-  /* stop on the first non-NULL return value */
-  return g_value_get_boxed (handler_return) == NULL;
-}
-
 static void
 clutter_cairo_texture_class_init (ClutterCairoTextureClass *klass)
 {
@@ -460,7 +439,7 @@ clutter_cairo_texture_class_init (ClutterCairoTextureClass *klass)
                   G_TYPE_FROM_CLASS (klass),
                   G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (ClutterCairoTextureClass, create_surface),
-                  create_surface_accum, NULL,
+                  _clutter_create_surface_accumulator, NULL,
                   _clutter_marshal_BOXED__UINT_UINT,
                   CAIRO_GOBJECT_TYPE_SURFACE, 2,
                   G_TYPE_UINT,
@@ -560,7 +539,7 @@ clutter_cairo_texture_context_destroy (void *data)
                            ctxt->rect.x, ctxt->rect.y,
                            cairo_width, cairo_height,
                            cairo_width, cairo_height,
-                           CLUTTER_CAIRO_TEXTURE_PIXEL_FORMAT,
+                           CLUTTER_CAIRO_PIXEL_FORMAT,
                            cairo_stride,
                            cairo_data);
 
diff --git a/clutter/clutter-drawing-area.c b/clutter/clutter-drawing-area.c
new file mode 100644
index 0000000..3d5264d
--- /dev/null
+++ b/clutter/clutter-drawing-area.c
@@ -0,0 +1,317 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+
+#include <cairo-gobject.h>
+
+#include "clutter-drawing-area.h"
+
+#include "clutter-debug.h"
+#include "clutter-marshal.h"
+#include "clutter-private.h"
+
+struct _ClutterDrawingAreaPrivate
+{
+  CoglMaterial *material;
+  CoglHandle texture;
+
+  cairo_t *context;
+
+  guint needs_repaint : 1;
+  guint in_repaint    : 1;
+};
+
+enum
+{
+  CREATE_SURFACE,
+  DRAW,
+
+  LAST_SIGNAL
+};
+
+static guint area_signals[LAST_SIGNAL] = { 0, };
+static ClutterContentIface *clutter_content_parent_iface = NULL;
+
+static void clutter_content_iface_init (ClutterContentIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ClutterDrawingArea,
+                         clutter_drawing_area,
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
+                                                clutter_content_iface_init));
+
+static cairo_surface_t *
+clutter_drawing_area_real_create_surface (ClutterDrawingArea *area,
+                                          ClutterActor       *actor,
+                                          guint               width,
+                                          guint               height)
+{
+  g_debug (G_STRLOC ": creating default image surface (%u x %u)", width, height);
+
+  return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+}
+
+static cairo_surface_t *
+clutter_drawing_area_create_surface (ClutterDrawingArea *area,
+                                     ClutterActor       *actor,
+                                     guint               width,
+                                     guint               height)
+{
+  cairo_surface_t *retval;
+
+  g_signal_emit (area, area_signals[CREATE_SURFACE], 0,
+                 actor,
+                 width,
+                 height,
+                 &retval);
+
+  return retval;
+}
+
+static gboolean
+clutter_drawing_area_real_draw (ClutterDrawingArea *area,
+                                ClutterActor       *actor,
+                                cairo_t            *cr)
+{
+  return TRUE;
+}
+
+static gboolean
+clutter_drawing_area_setup_material (ClutterContent *content,
+                                     ClutterActor   *actor)
+{
+  ClutterDrawingArea *area = CLUTTER_DRAWING_AREA (content);
+  ClutterDrawingAreaPrivate *priv = area->priv;
+  ClutterActorBox box;
+  gfloat width, height;
+
+  clutter_actor_get_allocation_box (actor, &box);
+
+  width = ceilf (clutter_actor_box_get_width (&box));
+  height = ceilf (clutter_actor_box_get_height (&box));
+
+  if (width == 0 || height == 0)
+    return FALSE;
+
+  if (priv->texture != NULL)
+    {
+      guint tex_width, tex_height;
+
+      tex_width = cogl_texture_get_width (priv->texture);
+      tex_height = cogl_texture_get_height (priv->texture);
+
+      if (tex_width != width || tex_height != height)
+        {
+          cogl_object_unref (priv->texture);
+          priv->texture = NULL;
+        }
+    }
+
+  if (priv->material == NULL)
+    priv->material = cogl_material_new ();
+
+  if (priv->texture == NULL)
+    {
+      g_debug (G_STRLOC ": creating backing texture...");
+      priv->texture = cogl_texture_new_with_size (width, height,
+                                                  COGL_TEXTURE_NONE,
+                                                  CLUTTER_CAIRO_PIXEL_FORMAT);
+      priv->needs_repaint = TRUE;
+    }
+
+  if (priv->needs_repaint)
+    {
+      cairo_surface_t *surface;
+      gboolean retval;
+
+      g_debug (G_STRLOC ": creating surface...");
+      surface = clutter_drawing_area_create_surface (area, actor,
+                                                     width,
+                                                     height);
+      if (surface == NULL)
+        return FALSE;
+
+      priv->context = cairo_create (surface);
+      priv->in_repaint = TRUE;
+      priv->needs_repaint = FALSE;
+
+      /* help out Cairo discard geometry that goes outside the allocation */
+      cairo_rectangle (priv->context, 0, 0, width, height);
+      cairo_clip (priv->context);
+
+      g_debug (G_STRLOC ": emitting draw...");
+      g_signal_emit (area, area_signals[DRAW], 0,
+                     actor,
+                     priv->context,
+                     &retval);
+      g_debug (G_STRLOC ": draw completed (res: %s)", retval ? "<true>" : "<false>");
+
+      cairo_destroy (priv->context);
+      priv->context = NULL;
+      priv->in_repaint = FALSE;
+
+      if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE)
+        {
+          g_debug (G_STRLOC ": setting backing texture region with image surface data");
+          cogl_texture_set_region (priv->texture,
+                                   0, 0, 0, 0,
+                                   width, height,
+                                   width, height,
+                                   CLUTTER_CAIRO_PIXEL_FORMAT,
+                                   cairo_image_surface_get_stride (surface),
+                                   cairo_image_surface_get_data (surface));
+        }
+
+      cairo_surface_destroy (surface);
+    }
+
+  g_debug (G_STRLOC ": setting material layer[0]");
+  cogl_material_set_layer (priv->material, 0, priv->texture);
+
+  if (priv->texture != NULL)
+    {
+      guint8 paint_opacity = clutter_actor_get_paint_opacity (actor);
+      CoglColor *color = cogl_color_new ();
+
+      cogl_color_init_from_4ub (color,
+                                paint_opacity,
+                                paint_opacity,
+                                paint_opacity,
+                                paint_opacity);
+
+      cogl_material_set_color (priv->material, color);
+
+      g_debug (G_STRLOC ": setting source");
+      cogl_set_source (priv->material);
+
+      cogl_color_free (color);
+    }
+
+  return TRUE;
+}
+
+static void
+clutter_drawing_area_invalidate (ClutterContent *content)
+{
+  g_debug (G_STRLOC ": invalidating DrawingArea");
+  /* invalidate() should recreate the contents */
+  CLUTTER_DRAWING_AREA (content)->priv->needs_repaint = TRUE;
+
+  /* chain up for the default implementation */
+  clutter_content_parent_iface->invalidate (content);
+}
+
+static void
+clutter_drawing_area_finalize (GObject *gobject)
+{
+  ClutterDrawingAreaPrivate *priv = CLUTTER_DRAWING_AREA (gobject)->priv;
+
+  if (priv->texture)
+    cogl_object_unref (priv->texture);
+
+  if (priv->material)
+    cogl_object_unref (priv->material);
+
+  G_OBJECT_CLASS (clutter_drawing_area_parent_class)->finalize (gobject);
+}
+
+static void
+clutter_content_iface_init (ClutterContentIface *iface)
+{
+  clutter_content_parent_iface =
+    g_type_default_interface_peek (CLUTTER_TYPE_CONTENT);
+
+  iface->setup_material = clutter_drawing_area_setup_material;
+  iface->invalidate = clutter_drawing_area_invalidate;
+}
+
+static void
+clutter_safe_draw_marshaller (GClosure     *closure,
+                              GValue       *return_value,
+                              guint         n_param_values,
+                              const GValue *param_values,
+                              gpointer      invocation_hint,
+                              gpointer      marshal_data)
+{
+  cairo_t *cr = g_value_get_boxed (&param_values[2]);
+
+  cairo_save (cr);
+
+  _clutter_marshal_BOOLEAN__OBJECT_BOXED (closure,
+                                          return_value,
+                                          n_param_values,
+                                          param_values,
+                                          invocation_hint,
+                                          marshal_data);
+
+  cairo_restore (cr);
+}
+
+static void
+clutter_drawing_area_class_init (ClutterDrawingAreaClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ClutterDrawingAreaPrivate));
+
+  gobject_class->finalize = clutter_drawing_area_finalize;
+
+  area_signals[DRAW] =
+    g_signal_new (I_("draw"),
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterDrawingAreaClass, draw),
+                  _clutter_boolean_handled_accumulator, NULL,
+                  clutter_safe_draw_marshaller,
+                  G_TYPE_BOOLEAN, 2,
+                  CLUTTER_TYPE_ACTOR,
+                  CAIRO_GOBJECT_TYPE_CONTEXT);
+
+  area_signals[CREATE_SURFACE] =
+    g_signal_new (I_("create-surface"),
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterDrawingAreaClass, create_surface),
+                  _clutter_create_surface_accumulator, NULL,
+                  _clutter_marshal_BOXED__OBJECT_UINT_UINT,
+                  CAIRO_GOBJECT_TYPE_SURFACE, 3,
+                  CLUTTER_TYPE_ACTOR,
+                  G_TYPE_UINT,
+                  G_TYPE_UINT);
+
+  klass->create_surface = clutter_drawing_area_real_create_surface;
+  klass->draw = clutter_drawing_area_real_draw;
+}
+
+static void
+clutter_drawing_area_init (ClutterDrawingArea *area)
+{
+  area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, CLUTTER_TYPE_DRAWING_AREA,
+                                            ClutterDrawingAreaPrivate);
+
+  area->priv->needs_repaint = TRUE;
+}
+
+/**
+ * clutter_drawing_area_new:
+ *
+ * Creates a new #ClutterDrawingArea instance.
+ *
+ * Drawing on the returned #ClutterDrawingArea can be performed by
+ * connecting to the #ClutterDrawingArea::draw signal.
+ *
+ * The returned #ClutterDrawingArea can be assigned to any #ClutterActor
+ * using clutter_actor_set_content().
+ *
+ * Return value: (transfer full): the newly created #ClutterDrawingArea.
+ *   Use g_object_unref() when done.
+ *
+ * Since: 1.8
+ */
+ClutterContent *
+clutter_drawing_area_new (void)
+{
+  return g_object_new (CLUTTER_TYPE_DRAWING_AREA, NULL);
+}
diff --git a/clutter/clutter-drawing-area.h b/clutter/clutter-drawing-area.h
new file mode 100644
index 0000000..7c3f73f
--- /dev/null
+++ b/clutter/clutter-drawing-area.h
@@ -0,0 +1,61 @@
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <clutter/clutter.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_DRAWING_AREA_H__
+#define __CLUTTER_DRAWING_AREA_H__
+
+#include <cairo.h>
+#include <clutter/clutter-actor.h>
+#include <clutter/clutter-content.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DRAWING_AREA               (clutter_drawing_area_get_type ())
+#define CLUTTER_DRAWING_AREA(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DRAWING_AREA, ClutterDrawingArea))
+#define CLUTTER_IS_DRAWING_AREA(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DRAWING_AREA))
+#define CLUTTER_DRAWING_AREA_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DRAWING_AREA, ClutterDrawingAreaClass))
+#define CLUTTER_IS_DRAWING_AREA_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DRAWING_AREA))
+#define CLUTTER_DRAWING_AREA_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DRAWING_AREA, ClutterDrawingAreaClass))
+
+typedef struct _ClutterDrawingArea              ClutterDrawingArea;
+typedef struct _ClutterDrawingAreaPrivate       ClutterDrawingAreaPrivate;
+typedef struct _ClutterDrawingAreaClass         ClutterDrawingAreaClass;
+
+struct _ClutterDrawingArea
+{
+  GObject parent_instance;
+
+  ClutterDrawingAreaPrivate *priv;
+};
+
+struct _ClutterDrawingAreaClass
+{
+  GObjectClass parent_class;
+
+  cairo_surface_t *(* create_surface) (ClutterDrawingArea *area,
+                                       ClutterActor       *actor,
+                                       guint               width,
+                                       guint               height);
+
+  gboolean         (* draw)           (ClutterDrawingArea *area,
+                                       ClutterActor       *actor,
+                                       cairo_t            *cr);
+
+  void (*_clutter_drawing_area_0) (void);
+  void (*_clutter_drawing_area_1) (void);
+  void (*_clutter_drawing_area_2) (void);
+  void (*_clutter_drawing_area_3) (void);
+  void (*_clutter_drawing_area_4) (void);
+  void (*_clutter_drawing_area_5) (void);
+  void (*_clutter_drawing_area_6) (void);
+  void (*_clutter_drawing_area_7) (void);
+};
+
+GType clutter_drawing_area_get_type (void) G_GNUC_CONST;
+
+ClutterContent *clutter_drawing_area_new (void);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DRAWING_AREA_H__ */
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index 7e22edc..b37ab8f 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -91,9 +91,11 @@
 #endif
 
 #include <stdlib.h>
+#include <locale.h>
+
 #include <glib/gi18n-lib.h>
+
 #include <gio/gio.h>
-#include <locale.h>
 
 #include "clutter-actor.h"
 #include "clutter-backend-private.h"
@@ -1776,6 +1778,18 @@ _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
   return continue_emission;
 }
 
+gboolean
+_clutter_create_surface_accumulator (GSignalInvocationHint *ihint,
+                                     GValue                *return_accu,
+                                     const GValue          *handler_return,
+                                     gpointer               data)
+{
+  g_value_copy (handler_return, return_accu);
+
+  /* stop on the first non-NULL return value */
+  return g_value_get_boxed (handler_return) == NULL;
+}
+
 static void
 event_click_count_generate (ClutterEvent *event)
 {
diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list
index 49745ef..aa5c041 100644
--- a/clutter/clutter-marshal.list
+++ b/clutter/clutter-marshal.list
@@ -1,5 +1,7 @@
 BOOLEAN:BOXED
+BOOLEAN:OBJECT,BOXED
 BOOLEAN:STRING,UINT,FLAGS
+BOXED:OBJECT,UINT,UINT
 BOXED:UINT,UINT
 DOUBLE:VOID
 UINT:VOID
diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h
index 610e017..2e05f5e 100644
--- a/clutter/clutter-private.h
+++ b/clutter/clutter-private.h
@@ -88,6 +88,15 @@ typedef struct _ClutterMainContext      ClutterMainContext;
 #define P_(String) (String)
 #endif
 
+/* Cairo stores the data in native byte order as ARGB but Cogl's pixel
+   formats specify the actual byte order. Therefore we need to use a
+   different format depending on the architecture */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define CLUTTER_CAIRO_PIXEL_FORMAT      (COGL_PIXEL_FORMAT_BGRA_8888_PRE)
+#else
+#define CLUTTER_CAIRO_PIXEL_FORMAT      (COGL_PIXEL_FORMAT_ARGB_8888_PRE)
+#endif
+
 typedef enum {
   CLUTTER_ACTOR_UNUSED_FLAG = 0,
 
@@ -211,6 +220,10 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
                                                GValue                *return_accu,
                                                const GValue          *handler_return,
                                                gpointer               dummy);
+gboolean _clutter_create_surface_accumulator (GSignalInvocationHint *ihint,
+                                              GValue                *return_accu,
+                                              const GValue          *handler_return,
+                                              gpointer               dummy);
 
 void _clutter_run_repaint_functions (void);
 
diff --git a/clutter/clutter.h b/clutter/clutter.h
index 5029be4..4140ec3 100644
--- a/clutter/clutter.h
+++ b/clutter/clutter.h
@@ -69,6 +69,7 @@
 #include "clutter-desaturate-effect.h"
 #include "clutter-device-manager.h"
 #include "clutter-drag-action.h"
+#include "clutter-drawing-area.h"
 #include "clutter-effect.h"
 #include "clutter-event.h"
 #include "clutter-feature.h"
diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am
index b7d7598..a0dbb89 100644
--- a/tests/interactive/Makefile.am
+++ b/tests/interactive/Makefile.am
@@ -58,7 +58,8 @@ UNIT_TESTS = \
 	test-snap-constraint.c \
 	test-rgba-content.c \
 	test-image-content.c \
-	test-border-image.c
+	test-border-image.c \
+	test-drawing-area.c
 
 if X11_TESTS
 UNIT_TESTS += test-pixmap.c test-devices.c
diff --git a/tests/interactive/test-drawing-area.c b/tests/interactive/test-drawing-area.c
new file mode 100644
index 0000000..6d3fb2f
--- /dev/null
+++ b/tests/interactive/test-drawing-area.c
@@ -0,0 +1,104 @@
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <cairo.h>
+#include <clutter/clutter.h>
+
+#define PADDING         18.0f
+
+static gboolean
+on_area_draw (ClutterDrawingArea *area,
+              ClutterActor       *actor,
+              cairo_t            *cr)
+{
+  GDateTime *now = g_date_time_new_now_local ();
+  double hours = g_date_time_get_hour (now) * G_PI / 6.0;
+  double minutes = g_date_time_get_minute (now) * G_PI / 30;
+  double seconds = g_date_time_get_seconds (now) * G_PI / 30;
+
+  g_print ("Time: %02d:%02d:%02.1f\n",
+           g_date_time_get_hour (now),
+           g_date_time_get_minute (now),
+           g_date_time_get_seconds (now));
+
+  g_date_time_unref (now);
+
+  /* clear the current contents */
+  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+  cairo_paint (cr);
+
+  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+  /* who doesn't want all those new line settings? :-) */
+  cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+  cairo_set_line_width (cr, 0.1);
+
+  /* translate to the center of the rendering context */
+  cairo_translate (cr, 0.5, 0.5);
+
+  /* clock outline */
+  cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
+  cairo_arc (cr, 0, 0, 0.4, 0, G_PI * 2);
+  cairo_stroke (cr);
+
+  /* draw a white dot on the current second */
+  cairo_set_source_rgba (cr, 1, 1, 1, 0.6);
+  cairo_arc (cr, sin (seconds) * 0.4, -cos (seconds) * 0.4, 0.05, 0, G_PI * 2);
+  cairo_fill (cr);
+
+  /* minutes hand */
+  cairo_set_source_rgba (cr, 0.2, 0.2, 1, 0.6);
+  cairo_move_to (cr, 0, 0);
+  cairo_line_to (cr, sin (minutes) * 0.4, -cos (minutes) * 0.4);
+  cairo_stroke (cr);
+
+  /* hours hand */
+  cairo_move_to (cr, 0, 0);
+  cairo_line_to (cr, sin (hours) * 0.2, -cos (hours) * 0.2);
+  cairo_stroke (cr);
+
+  return TRUE;
+}
+
+static gboolean
+on_timeout (gpointer data)
+{
+  ClutterContent *content = data;
+
+  /* invalidate the content on timeout */
+  clutter_content_invalidate (content);
+
+  return TRUE;
+}
+
+G_MODULE_EXPORT int
+test_drawing_area_main (int argc, char *argv[])
+{
+  ClutterActor *stage, *actor;
+  ClutterContent *area;
+
+  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+    return EXIT_FAILURE;
+
+  stage = clutter_stage_new ();
+  clutter_stage_set_title (CLUTTER_STAGE (stage), "2D Drawing");
+  clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Aluminium5);
+  clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
+  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+  clutter_actor_show (stage);
+
+  area = clutter_drawing_area_new ();
+  g_signal_connect (area, "draw", G_CALLBACK (on_area_draw), NULL);
+
+  actor = clutter_actor_new ();
+  clutter_actor_set_content (actor, area);
+  clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_POSITION, PADDING));
+  clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 2 * PADDING));
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
+
+//  clutter_threads_add_timeout (1000, on_timeout, area);
+
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}



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