[gnome-control-center] wacom: Re-write gui_gtk in Clutter to introduce animations



commit d78bc9772a3109ed75e80d6adc0d691a0a15c6d3
Author: Joaquim Rocha <jrocha redhat com>
Date:   Mon Apr 8 18:44:12 2013 +0200

    wacom: Re-write gui_gtk in Clutter to introduce animations
    
    The name of the file was also changed to calibratorgui.c/h to avoid
    it being inconsistent, this way it is no longer dependent on the
    the technology.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=667797

 configure.ac                                       |   12 +-
 panels/wacom/calibrator/Makefile.am                |   16 +-
 panels/wacom/calibrator/calibrator-gui.c           |  787 ++++++++++++++++++++
 .../calibrator/{gui_gtk.h => calibrator-gui.h}     |   10 +-
 panels/wacom/calibrator/calibrator.h               |    2 +-
 panels/wacom/calibrator/cc-clock-actor.c           |  186 +++++
 panels/wacom/calibrator/cc-clock-actor.h           |   56 ++
 panels/wacom/calibrator/cc-target-actor.c          |  229 ++++++
 panels/wacom/calibrator/cc-target-actor.h          |   60 ++
 panels/wacom/calibrator/gui_gtk.c                  |  591 ---------------
 panels/wacom/calibrator/main.c                     |    9 +-
 panels/wacom/cc-wacom-page.c                       |    2 +-
 panels/wacom/test-wacom.c                          |    7 +-
 shell/Makefile.am                                  |    1 +
 shell/cc-application.c                             |    9 +-
 15 files changed, 1366 insertions(+), 611 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index db54ee0..83e27a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -292,16 +292,20 @@ case $host_os in
       PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES
                         gnome-settings-daemon >= $GSD_REQUIRED_VERSION
                         xi >= 1.2 x11 libwacom >= $LIBWACOM_REQUIRED_VERSION
-                        gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
-      AC_DEFINE(BUILD_WACOM, 1, [Define to 1 to build the Wacom panel])
-      have_wacom=yes
+                        gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION
+                        clutter-gtk-1.0
+                        clutter-1.0 >= $CLUTTER_REQUIRED_VERSION, [have_wacom=yes], [have_wacom=no])
+      if test x${have_wacom} = xyes; then
+        AC_DEFINE(BUILD_WACOM, 1, [Define to 1 to build the Wacom panel])
+        AC_DEFINE(HAVE_WACOM, 1, [Define to 1 is Wacom is supportted])
+      fi
     fi
     ;;
   *)
     have_wacom=no
     ;;
 esac
-AM_CONDITIONAL(BUILD_WACOM, [test x"$have_wacom" = x"yes"])
+AM_CONDITIONAL(BUILD_WACOM, [test x${have_wacom} = xyes])
 
 # Kerberos kerberos support
 AC_PATH_PROG(KRB5_CONFIG, krb5-config, no)
diff --git a/panels/wacom/calibrator/Makefile.am b/panels/wacom/calibrator/Makefile.am
index 74d4385..72d7552 100644
--- a/panels/wacom/calibrator/Makefile.am
+++ b/panels/wacom/calibrator/Makefile.am
@@ -13,8 +13,12 @@ noinst_LTLIBRARIES = libwacom-calibrator.la libwacom-calibrator-test.la
 libwacom_calibrator_la_SOURCES =       \
        calibrator.c                    \
        calibrator.h                    \
-       gui_gtk.c                       \
-       gui_gtk.h
+       calibrator-gui.c                \
+       calibrator-gui.h                \
+       cc-clock-actor.c                \
+       cc-clock-actor.h                \
+       cc-target-actor.c               \
+       cc-target-actor.h
 
 libwacom_calibrator_la_LIBADD = $(PANEL_LIBS) $(WACOM_PANEL_LIBS)
 libwacom_calibrator_la_LDFLAGS = $(PANEL_LDFLAGS)
@@ -31,8 +35,12 @@ test_calibrator_SOURCES =            \
        main.c                          \
        calibrator.c                    \
        calibrator.h                    \
-       gui_gtk.c                       \
-       gui_gtk.h
+       calibrator-gui.c                \
+       calibrator-gui.h                \
+       cc-clock-actor.c                \
+       cc-clock-actor.h                \
+       cc-target-actor.c               \
+       cc-target-actor.h
 
 test_calibrator_CPPFLAGS = $(INCLUDES)
 test_calibrator_LDADD = $(PANEL_LIBS) $(WACOM_PANEL_LIBS)
diff --git a/panels/wacom/calibrator/calibrator-gui.c b/panels/wacom/calibrator/calibrator-gui.c
new file mode 100644
index 0000000..eab8ef2
--- /dev/null
+++ b/panels/wacom/calibrator/calibrator-gui.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Joaquim Rocha <jrocha redhat com>
+ *         (based on previous work by Tias Guns and Soren Hauberg)
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <cairo.h>
+#include <clutter-gtk/clutter-gtk.h>
+#include <clutter/clutter.h>
+
+#include "calibrator.h"
+#include "calibrator-gui.h"
+#include "cc-clock-actor.h"
+#include "cc-target-actor.h"
+
+struct CalibArea
+{
+  struct Calib calibrator;
+  XYinfo       axis;
+  gboolean     swap;
+  gboolean     success;
+  int          device_id;
+
+  double X[4], Y[4];
+  int display_width, display_height;
+
+  GtkWidget         *window;
+  ClutterActor      *stage;
+  ClutterActor      *action_layer;
+  ClutterActor      *clock;
+  ClutterActor      *target;
+  ClutterActor      *success_image;
+  ClutterActor      *text_title_holder;
+  ClutterActor      *helper_text_title;
+  ClutterActor      *text_body_holder;
+  ClutterActor      *helper_text_body;
+  ClutterActor      *error_text;
+  ClutterTransition *clock_timeline;
+  GdkPixbuf         *icon_success;
+
+  FinishCallback callback;
+  gpointer       user_data;
+};
+
+#define TARGET_SHOW_ANIMATION_DURATION 500
+#define TARGET_HIDE_ANIMATION_DURATION 200
+
+#define COLOR_GRAY 127
+
+/* Window parameters */
+#define WINDOW_OPACITY          0.9
+
+/* Timeout parameters */
+#define MAX_TIME                15000 /* 5000 = 5 sec */
+#define END_TIME                750   /*  750 = 0.75 sec */
+
+/* Text printed on screen */
+#define HELP_TEXT_TITLE            N_("Screen Calibration")
+#define HELP_TEXT_MAIN             N_("Please tap the target markers as they " \
+                                      "appear on screen to calibrate the tablet.")
+#define HELP_TEXT_ANIMATION_DURATION 300
+
+#define ERROR_MESSAGE                    N_("Mis-click detected, restarting...")
+#define ERROR_MESSAGE_ANIMATION_DURATION 500
+
+#define ICON_SUCCESS    "emblem-ok-symbolic"
+#define ICON_SIZE       300
+
+static void
+set_display_size(CalibArea *calib_area,
+                 int        width,
+                 int        height)
+{
+  int delta_x;
+  int delta_y;
+
+  calib_area->display_width = width;
+  calib_area->display_height = height;
+
+  /* Compute absolute circle centers */
+  delta_x = calib_area->display_width/NUM_BLOCKS;
+  delta_y = calib_area->display_height/NUM_BLOCKS;
+
+  calib_area->X[UL] = delta_x;
+  calib_area->Y[UL] = delta_y;
+
+  calib_area->X[UR] = calib_area->display_width - delta_x - 1;
+  calib_area->Y[UR] = delta_y;
+
+  calib_area->X[LL] = delta_x;
+  calib_area->Y[LL] = calib_area->display_height - delta_y - 1;
+
+  calib_area->X[LR] = calib_area->display_width - delta_x - 1;
+  calib_area->Y[LR] = calib_area->display_height - delta_y - 1;
+
+  /* reset calibration if already started */
+  reset(&calib_area->calibrator);
+}
+
+static void
+resize_display(CalibArea *calib_area)
+{
+  gfloat width, height;
+
+  clutter_actor_get_size (calib_area->stage, &width, &height);
+  if (calib_area->display_width != width ||
+      calib_area->display_height != height)
+    {
+      gint i = calib_area->calibrator.num_clicks;
+      set_display_size(calib_area, width, height);
+      cc_target_actor_move (CC_TARGET_ACTOR (calib_area->target),
+                            calib_area->X[i],
+                            calib_area->Y[i]);
+    }
+}
+
+static void
+on_allocation_changed (ClutterActor          *actor,
+                       ClutterActorBox       *box,
+                       ClutterAllocationFlags flags,
+                       CalibArea             *area)
+{
+  resize_display (area);
+}
+
+static gboolean
+on_delete_event (GtkWidget *widget,
+                 GdkEvent  *event,
+                 CalibArea *area)
+{
+  clutter_timeline_stop (CLUTTER_TIMELINE (area->clock_timeline));
+
+  gtk_widget_hide (area->window);
+
+  (*area->callback) (area, area->user_data);
+
+  return TRUE;
+}
+
+static gboolean
+draw_success_end_wait_callback (CalibArea *area)
+{
+  on_delete_event (NULL, NULL, area);
+
+  return FALSE;
+}
+
+static void
+set_success (CalibArea *area)
+{
+  ClutterImage *image;
+  GdkPixbuf *icon = area->icon_success;
+
+  if (icon == NULL)
+    return;
+
+  image = CLUTTER_IMAGE (clutter_actor_get_content (area->success_image));
+  clutter_image_set_data (image,
+                          gdk_pixbuf_get_pixels (icon),
+                          gdk_pixbuf_get_has_alpha (icon)
+                          ? COGL_PIXEL_FORMAT_RGBA_8888
+                          : COGL_PIXEL_FORMAT_RGB_888,
+                          gdk_pixbuf_get_width (icon),
+                          gdk_pixbuf_get_height (icon),
+                          gdk_pixbuf_get_rowstride (icon),
+                          NULL);
+  clutter_actor_set_size (area->success_image,
+                          gdk_pixbuf_get_width (icon),
+                          gdk_pixbuf_get_height (icon));
+
+  clutter_actor_show (area->success_image);
+  clutter_actor_hide (area->action_layer);
+}
+
+static void
+set_calibration_status (CalibArea *area)
+{
+  GtkIconTheme *icon_theme;
+  GtkIconInfo  *icon_info;
+  GdkRGBA       white;
+
+  icon_theme = gtk_icon_theme_get_default ();
+  icon_info = gtk_icon_theme_lookup_icon (icon_theme,
+                                          ICON_SUCCESS,
+                                          ICON_SIZE,
+                                          GTK_ICON_LOOKUP_USE_BUILTIN);
+  if (icon_info == NULL)
+    {
+      g_warning ("Failed to find icon \"%s\"", ICON_SUCCESS);
+      goto out;
+    }
+
+  gdk_rgba_parse (&white, "White");
+  area->icon_success = gtk_icon_info_load_symbolic (icon_info,
+                                                    &white,
+                                                    NULL,
+                                                    NULL,
+                                                    NULL,
+                                                    NULL,
+                                                    NULL);
+  g_object_unref (icon_info);
+
+  if (!area->icon_success)
+    g_warning ("Failed to load icon \"%s\"", ICON_SUCCESS);
+
+ out:
+  area->success = finish (&area->calibrator, &area->axis, &area->swap);
+  if (area->success && area->icon_success)
+    {
+      set_success (area);
+      g_timeout_add (END_TIME,
+                     (GSourceFunc) draw_success_end_wait_callback,
+                     area);
+    }
+  else
+    {
+      on_delete_event (NULL, NULL, area);
+    }
+}
+
+static ClutterTransition *
+get_error_message_transition (CalibArea *area)
+{
+  ClutterTransition *transition;
+
+  clutter_actor_show (area->error_text);
+  transition = clutter_property_transition_new ("opacity");
+  clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
+                                      CLUTTER_EASE_OUT);
+  clutter_timeline_set_duration (CLUTTER_TIMELINE (transition),
+                                 ERROR_MESSAGE_ANIMATION_DURATION);
+  clutter_transition_set_animatable (transition,
+                                     CLUTTER_ANIMATABLE (area->error_text));
+  clutter_transition_set_from (transition, G_TYPE_UINT, 0);
+  clutter_transition_set_to (transition, G_TYPE_UINT, 255);
+
+  return transition;
+}
+
+static void
+show_error_message (CalibArea *area)
+{
+  ClutterTransition *transition;
+  clutter_actor_show (area->error_text);
+  transition = get_error_message_transition (area);
+  clutter_timeline_start (CLUTTER_TIMELINE (transition));
+}
+
+static void
+on_error_message_transparent (ClutterTimeline *timeline,
+                              CalibArea       *area)
+{
+  clutter_actor_hide (area->error_text);
+}
+
+static void
+hide_error_message (CalibArea *area)
+{
+  ClutterTransition *transition;
+  transition = get_error_message_transition (area);
+  clutter_transition_set_from (transition, G_TYPE_UINT, 255);
+  clutter_transition_set_to (transition, G_TYPE_UINT, 0);
+  g_signal_connect (CLUTTER_TIMELINE (transition),
+                    "completed",
+                    G_CALLBACK (on_error_message_transparent),
+                    area);
+  clutter_timeline_start (CLUTTER_TIMELINE (transition));
+}
+
+static gboolean
+on_button_press_event(ClutterActor       *actor,
+                      ClutterButtonEvent *event,
+                      CalibArea          *area)
+{
+  gint num_clicks;
+  gboolean success;
+
+  if (area->success)
+    return FALSE;
+
+  /* Check matching device ID if a device ID was provided */
+  if (area->device_id > -1)
+    {
+      GdkDevice *device;
+
+      device = gdk_event_get_source_device ((GdkEvent *) event);
+      if (device != NULL && gdk_x11_device_get_id (device) != area->device_id)
+        return FALSE;
+    }
+
+  /* Handle click */
+  clutter_timeline_stop (CLUTTER_TIMELINE (area->clock_timeline));
+  clutter_timeline_start (CLUTTER_TIMELINE (area->clock_timeline));
+  success = add_click(&area->calibrator,
+                      (int) event->x,
+                      (int) event->y);
+
+  num_clicks = area->calibrator.num_clicks;
+
+  if (!success && num_clicks == 0)
+    show_error_message (area);
+  else
+    {
+      gboolean visible;
+      g_object_get (area->error_text, "visible", &visible, NULL);
+
+      if (visible)
+        hide_error_message (area);
+    }
+
+  /* Are we done yet? */
+  if (num_clicks >= 4)
+    {
+      set_calibration_status (area);
+      return FALSE;
+    }
+
+  cc_target_actor_move (CC_TARGET_ACTOR (area->target),
+                        area->X[num_clicks],
+                        area->Y[num_clicks]);
+
+
+  return FALSE;
+}
+
+static gboolean
+on_key_release_event(ClutterActor    *actor,
+                     ClutterKeyEvent *event,
+                     CalibArea       *area)
+{
+  if (area->success ||
+      event->type != CLUTTER_KEY_RELEASE ||
+      event->keyval != CLUTTER_KEY_Escape)
+    {
+      return FALSE;
+    }
+
+  on_delete_event (area->window, NULL, area);
+
+  return FALSE;
+}
+
+static gboolean
+on_focus_out_event (GtkWidget *widget,
+                    GdkEvent  *event,
+                    CalibArea *area)
+{
+  if (area->success)
+    return FALSE;
+
+  /* If the calibrator window loses focus, simply bail out... */
+  on_delete_event (widget, NULL, area);
+
+  return FALSE;
+}
+
+static void
+on_timeout (ClutterTimeline *timeline,
+            CalibArea       *area)
+{
+  set_calibration_status (area);
+}
+
+static void
+show_helper_text_body (CalibArea *area)
+{
+  ClutterTransition *transition;
+  gfloat height;
+
+  height = clutter_actor_get_height (area->helper_text_body);
+  clutter_actor_show (area->helper_text_body);
+
+  transition = clutter_property_transition_new ("y");
+  clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
+                                      CLUTTER_EASE_OUT);
+  clutter_timeline_set_duration (CLUTTER_TIMELINE (transition),
+                                 HELP_TEXT_ANIMATION_DURATION);
+  clutter_transition_set_animatable (transition,
+                                     CLUTTER_ANIMATABLE (area->helper_text_body));
+  clutter_transition_set_from (transition, G_TYPE_FLOAT, -height);
+  clutter_transition_set_to (transition, G_TYPE_FLOAT, 0.0);
+  clutter_timeline_start (CLUTTER_TIMELINE (transition));
+}
+
+static void
+on_helper_text_title_shown (ClutterTimeline *timelines,
+                            CalibArea       *area)
+{
+  show_helper_text_body (area);
+}
+
+static void
+show_helper_text_title (CalibArea *area)
+{
+  ClutterTransition *transition;
+
+  gfloat height = clutter_actor_get_height (area->helper_text_title);
+  clutter_actor_set_y (area->helper_text_title,
+                       - clutter_actor_get_height (area->helper_text_title));
+  clutter_actor_show (area->helper_text_title);
+
+  transition = clutter_property_transition_new ("y");
+  clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
+                                      CLUTTER_EASE_OUT);
+  clutter_timeline_set_duration (CLUTTER_TIMELINE (transition),
+                                 HELP_TEXT_ANIMATION_DURATION);
+  clutter_transition_set_animatable (transition,
+                                     CLUTTER_ANIMATABLE (area->helper_text_title));
+  clutter_transition_set_from (transition, G_TYPE_FLOAT, -height);
+  clutter_transition_set_to (transition, G_TYPE_FLOAT, 0.0);
+
+  g_signal_connect (CLUTTER_TIMELINE (transition),
+                    "completed",
+                    G_CALLBACK (on_helper_text_title_shown),
+                    area);
+
+  clutter_timeline_start (CLUTTER_TIMELINE (transition));
+}
+
+static void
+on_fullscreen (GtkWindow           *window,
+               GdkEventWindowState *event,
+               CalibArea           *area)
+{
+  ClutterRect rect;
+
+  if ((event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) == 0)
+    return;
+
+  clutter_actor_show (area->action_layer);
+  clutter_actor_show (area->clock);
+
+  rect.origin.x = 0;
+  rect.origin.y = 0;
+  clutter_actor_get_size (area->helper_text_title,
+                          &rect.size.width,
+                          &rect.size.height);
+  g_object_set (area->text_title_holder, "clip-rect", &rect, NULL);
+
+  clutter_actor_get_size (area->helper_text_body,
+                          &rect.size.width,
+                          &rect.size.height);
+  g_object_set (area->text_body_holder, "clip-rect", &rect, NULL);
+  clutter_actor_set_y (area->helper_text_body,
+                       - clutter_actor_get_height (area->helper_text_body));
+
+  show_helper_text_title (area);
+}
+
+static void
+set_up_stage (CalibArea *calib_area, ClutterActor *stage)
+{
+  ClutterPoint anchor;
+  ClutterColor color;
+  ClutterContent *success_content;
+  gfloat height;
+  gchar *markup;
+
+  calib_area->stage = stage;
+  calib_area->action_layer = clutter_actor_new ();
+  calib_area->clock = cc_clock_actor_new ();
+  calib_area->target = cc_target_actor_new ();
+  calib_area->text_title_holder = clutter_actor_new ();
+  calib_area->helper_text_title = clutter_text_new ();
+  calib_area->text_body_holder = clutter_actor_new ();
+  calib_area->helper_text_body = clutter_text_new ();
+  calib_area->error_text = clutter_text_new ();
+  calib_area->success_image = clutter_actor_new ();
+
+  clutter_stage_set_use_alpha (CLUTTER_STAGE (stage), TRUE);
+
+  /* bind the action layer's geometry to the stage's */
+  clutter_actor_add_constraint (calib_area->action_layer,
+                                clutter_bind_constraint_new (stage,
+                                                             CLUTTER_BIND_SIZE,
+                                                             0));
+  clutter_actor_add_child (stage, calib_area->action_layer);
+
+  g_signal_connect (stage,
+                    "allocation-changed",
+                    G_CALLBACK (on_allocation_changed),
+                    calib_area);
+
+  calib_area->calibrator.geometry.x = clutter_actor_get_x (stage);
+  calib_area->calibrator.geometry.y = clutter_actor_get_y (stage);
+  calib_area->calibrator.geometry.width = clutter_actor_get_width (stage);
+  calib_area->calibrator.geometry.height = clutter_actor_get_height (stage);
+
+  clutter_color_from_string (&color, "#000");
+  color.alpha = WINDOW_OPACITY * 255;
+  clutter_actor_set_background_color (stage, &color);
+
+  clutter_actor_add_child (calib_area->action_layer, calib_area->clock);
+  clutter_actor_add_constraint (calib_area->clock,
+                                clutter_align_constraint_new (stage,
+                                                              CLUTTER_ALIGN_BOTH,
+                                                              0.5));
+
+  clutter_actor_add_child (calib_area->action_layer, calib_area->target);
+
+  /* set the helper text */
+  anchor.x =  0;
+  g_object_set (calib_area->text_title_holder, "pivot-point", &anchor, NULL);
+
+  clutter_actor_add_child (calib_area->action_layer,
+                           calib_area->text_title_holder);
+  clutter_actor_add_child (calib_area->text_title_holder,
+                           calib_area->helper_text_title);
+  height = clutter_actor_get_height (calib_area->clock);
+  clutter_actor_add_constraint (calib_area->text_title_holder,
+                                clutter_bind_constraint_new (calib_area->clock,
+                                                             CLUTTER_BIND_Y,
+                                                             height * 1.5));
+  clutter_actor_add_constraint (calib_area->text_title_holder,
+                                clutter_align_constraint_new (stage,
+                                                              CLUTTER_ALIGN_X_AXIS,
+                                                              .5));
+
+  clutter_text_set_line_alignment (CLUTTER_TEXT (calib_area->helper_text_title),
+                                   PANGO_ALIGN_CENTER);
+
+  color.red = COLOR_GRAY;
+  color.green = COLOR_GRAY;
+  color.blue = COLOR_GRAY;
+  color.alpha = 255;
+
+  markup = g_strdup_printf ("<big><b>%s</b></big>",
+                            _(HELP_TEXT_TITLE));
+  clutter_text_set_markup (CLUTTER_TEXT (calib_area->helper_text_title), markup);
+  clutter_text_set_color (CLUTTER_TEXT (calib_area->helper_text_title), &color);
+  g_free (markup);
+
+  g_object_set (calib_area->text_body_holder, "pivot-point", &anchor, NULL);
+
+  clutter_actor_add_child (calib_area->action_layer,
+                           calib_area->text_body_holder);
+  clutter_actor_add_child (calib_area->text_body_holder,
+                           calib_area->helper_text_body);
+  height = clutter_actor_get_height (calib_area->helper_text_title);
+  clutter_actor_add_constraint (calib_area->text_body_holder,
+                                clutter_bind_constraint_new (calib_area->text_title_holder,
+                                                             CLUTTER_BIND_Y,
+                                                             height * 1.2));
+  clutter_actor_add_constraint (calib_area->text_body_holder,
+                                clutter_align_constraint_new (stage,
+                                                              CLUTTER_ALIGN_X_AXIS,
+                                                              .5));
+
+  clutter_text_set_line_alignment (CLUTTER_TEXT (calib_area->helper_text_body),
+                                   PANGO_ALIGN_CENTER);
+  markup = g_strdup_printf ("<span foreground=\"white\"><big>%s</big></span>",
+                            _(HELP_TEXT_MAIN));
+  clutter_text_set_markup (CLUTTER_TEXT (calib_area->helper_text_body), markup);
+  g_free (markup);
+
+  /* set the error text */
+  g_object_set (calib_area->error_text, "pivot-point", &anchor, NULL);
+
+  clutter_actor_add_child (calib_area->action_layer, calib_area->error_text);
+  height = clutter_actor_get_height (calib_area->helper_text_body);
+  clutter_actor_add_constraint (calib_area->error_text,
+                                clutter_bind_constraint_new (calib_area->text_title_holder,
+                                                             CLUTTER_BIND_Y,
+                                                             height * 3));
+  clutter_actor_add_constraint (calib_area->error_text,
+                                clutter_align_constraint_new (stage,
+                                                              CLUTTER_ALIGN_X_AXIS,
+                                                              .5));
+
+  clutter_text_set_line_alignment (CLUTTER_TEXT (calib_area->error_text),
+                                   PANGO_ALIGN_CENTER);
+  markup = g_strdup_printf ("<span foreground=\"white\"><big>"
+                            "<b>%s</b></big></span>",
+                            ERROR_MESSAGE);
+  clutter_text_set_markup (CLUTTER_TEXT (calib_area->error_text), markup);
+  g_free (markup);
+
+  clutter_actor_hide (calib_area->error_text);
+
+  /* configure success image */
+  success_content = clutter_image_new ();
+  clutter_actor_set_content (calib_area->success_image,
+                             success_content);
+  g_object_unref (success_content);
+  clutter_actor_add_child (stage, calib_area->success_image);
+  clutter_actor_add_constraint (calib_area->success_image,
+                                clutter_align_constraint_new (stage,
+                                                              CLUTTER_ALIGN_BOTH,
+                                                              .5));
+
+  /* animate clock */
+  calib_area->clock_timeline = clutter_property_transition_new ("angle");
+  clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (calib_area->clock_timeline),
+                                      CLUTTER_LINEAR);
+  clutter_timeline_set_duration (CLUTTER_TIMELINE (calib_area->clock_timeline),
+                                 MAX_TIME);
+  clutter_transition_set_animatable (calib_area->clock_timeline,
+                                     CLUTTER_ANIMATABLE (calib_area->clock));
+  clutter_transition_set_from (calib_area->clock_timeline, G_TYPE_FLOAT, .0);
+  clutter_transition_set_to (calib_area->clock_timeline, G_TYPE_FLOAT, 360.0);
+  clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (calib_area->clock_timeline),
+                                     -1);
+  clutter_timeline_start (CLUTTER_TIMELINE (calib_area->clock_timeline));
+  g_signal_connect (CLUTTER_TIMELINE (calib_area->clock_timeline),
+                    "completed",
+                    G_CALLBACK (on_timeout),
+                    calib_area);
+
+  g_signal_connect (stage,
+                    "button-press-event",
+                    G_CALLBACK (on_button_press_event),
+                    calib_area);
+  g_signal_connect (stage,
+                    "key-release-event",
+                    G_CALLBACK (on_key_release_event),
+                    calib_area);
+}
+
+/**
+ * Creates the windows and other objects required to do calibration
+ * under GTK. When the window is closed (timed out, calibration finished
+ * or user cancellation), callback will be called, where you should call
+ * calib_area_finish().
+ */
+CalibArea *
+calib_area_new (GdkScreen      *screen,
+                int             monitor,
+                int             device_id,
+                FinishCallback  callback,
+                gpointer        user_data,
+                XYinfo         *old_axis,
+                int             threshold_doubleclick,
+                int             threshold_misclick)
+{
+  CalibArea *calib_area;
+  GdkRectangle rect;
+  GdkVisual *visual;
+#ifndef FAKE_AREA
+  GdkWindow *window;
+  GdkCursor *cursor;
+#endif /* FAKE_AREA */
+  GtkWidget *clutter_embed;
+  ClutterActor *stage;
+
+  g_return_val_if_fail (old_axis, NULL);
+  g_return_val_if_fail (callback, NULL);
+
+  g_debug ("Current calibration: %d, %d, %d, %d\n",
+           old_axis->x_min,
+           old_axis->y_min,
+           old_axis->x_max,
+           old_axis->y_max);
+
+  calib_area = g_new0 (CalibArea, 1);
+  calib_area->callback = callback;
+  calib_area->user_data = user_data;
+  calib_area->device_id = device_id;
+  calib_area->calibrator.old_axis.x_min = old_axis->x_min;
+  calib_area->calibrator.old_axis.x_max = old_axis->x_max;
+  calib_area->calibrator.old_axis.y_min = old_axis->y_min;
+  calib_area->calibrator.old_axis.y_max = old_axis->y_max;
+  calib_area->calibrator.threshold_doubleclick = threshold_doubleclick;
+  calib_area->calibrator.threshold_misclick = threshold_misclick;
+
+  calib_area->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+#ifndef FAKE_AREA
+  /* No cursor */
+  gtk_widget_realize (calib_area->window);
+  window = gtk_widget_get_window (calib_area->window);
+  cursor = gdk_cursor_new (GDK_BLANK_CURSOR);
+  gdk_window_set_cursor (window, cursor);
+  g_object_unref (cursor);
+
+  gtk_widget_set_can_focus (calib_area->window, TRUE);
+  gtk_window_set_keep_above (GTK_WINDOW (calib_area->window), TRUE);
+#endif /* FAKE_AREA */
+
+  /* Set up the embedded stage */
+  clutter_embed = gtk_clutter_embed_new ();
+  gtk_container_add (GTK_CONTAINER (calib_area->window),
+                     clutter_embed);
+
+  stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (clutter_embed));
+
+  /* Move to correct screen */
+  if (screen == NULL)
+    screen = gdk_screen_get_default ();
+  gdk_screen_get_monitor_geometry (screen, monitor, &rect);
+  gtk_window_move (GTK_WINDOW (calib_area->window), rect.x, rect.y);
+  gtk_window_set_default_size (GTK_WINDOW (calib_area->window),
+                               rect.width,
+                               rect.height);
+
+  set_up_stage (calib_area, stage);
+
+  g_signal_connect (calib_area->window,
+                    "delete-event",
+                    G_CALLBACK (on_delete_event),
+                    calib_area);
+  g_signal_connect (calib_area->window,
+                    "focus-out-event",
+                    G_CALLBACK(on_focus_out_event),
+                    calib_area);
+  g_signal_connect (calib_area->window,
+                    "window-state-event",
+                    G_CALLBACK (on_fullscreen),
+                    calib_area);
+
+  gtk_window_fullscreen (GTK_WINDOW (calib_area->window));
+
+  visual = gdk_screen_get_rgba_visual (screen);
+  if (visual != NULL)
+    gtk_widget_set_visual (GTK_WIDGET (calib_area->window), visual);
+
+  gtk_widget_show_all (calib_area->window);
+  clutter_actor_hide (calib_area->action_layer);
+
+  return calib_area;
+}
+
+/* Finishes the calibration. Note that CalibArea
+ * needs to be destroyed with calib_area_free() afterwards */
+gboolean
+calib_area_finish (CalibArea *area,
+                   XYinfo    *new_axis,
+                   gboolean  *swap_xy)
+{
+  g_return_val_if_fail (area != NULL, FALSE);
+
+  *new_axis = area->axis;
+  *swap_xy  = area->swap;
+
+  if (area->success)
+    g_debug ("Final calibration: %d, %d, %d, %d\n",
+             new_axis->x_min,
+             new_axis->y_min,
+             new_axis->x_max,
+             new_axis->y_max);
+  else
+    g_debug ("Calibration was aborted or timed out");
+
+  return area->success;
+}
+
+void
+calib_area_free (CalibArea *area)
+{
+  g_return_if_fail (area != NULL);
+
+  g_clear_object (&area->icon_success);
+
+  gtk_widget_destroy (area->window);
+  g_free (area);
+}
+
+void
+calib_area_get_display_size (CalibArea *area, gint *width, gint *height)
+{
+  g_return_if_fail (area != NULL);
+
+  *width = area->display_width;
+  *height = area->display_height;
+}
diff --git a/panels/wacom/calibrator/gui_gtk.h b/panels/wacom/calibrator/calibrator-gui.h
similarity index 90%
rename from panels/wacom/calibrator/gui_gtk.h
rename to panels/wacom/calibrator/calibrator-gui.h
index d2d3bd2..6741215 100644
--- a/panels/wacom/calibrator/gui_gtk.h
+++ b/panels/wacom/calibrator/calibrator-gui.h
@@ -21,8 +21,8 @@
  * THE SOFTWARE.
  */
 
-#ifndef _gui_gtk_h
-#define _gui_gtk_h
+#ifndef __CALIBRATOR_GUI_H__
+#define __CALIBRATOR_GUI_H__
 
 #include <gtk/gtk.h>
 
@@ -53,6 +53,8 @@ gboolean calib_area_finish (CalibArea *area,
 
 void calib_area_free (CalibArea *area);
 
-void calib_area_get_display_size (CalibArea *area, gint *width, gint *height);
+void calib_area_get_display_size (CalibArea *area,
+                                 gint      *width,
+                                 gint      *height);
 
-#endif /* _gui_gtk_h */
+#endif /* __CALIBRATOR_GUI_H__ */
diff --git a/panels/wacom/calibrator/calibrator.h b/panels/wacom/calibrator/calibrator.h
index 75d72d7..659232f 100644
--- a/panels/wacom/calibrator/calibrator.h
+++ b/panels/wacom/calibrator/calibrator.h
@@ -25,7 +25,7 @@
 #define _calibrator_h
 
 #include <glib.h>
-#include "gui_gtk.h"
+#include "calibrator-gui.h"
 
 /*
  * Number of blocks. We partition the screen into 'num_blocks' x 'num_blocks'
diff --git a/panels/wacom/calibrator/cc-clock-actor.c b/panels/wacom/calibrator/cc-clock-actor.c
new file mode 100644
index 0000000..1039d74
--- /dev/null
+++ b/panels/wacom/calibrator/cc-clock-actor.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Joaquim Rocha <jrocha redhat com>
+ */
+
+#include <math.h>
+#include "cc-clock-actor.h"
+
+#define CLOCK_RADIUS                   50
+#define CLOCK_LINE_WIDTH               10
+#define CLOCK_LINE_PADDING             10
+#define CLOCK_SIZE_EXTRA
+#define ANGLE                          "angle"
+#define EXTRA_SPACE                    2
+
+G_DEFINE_TYPE (CcClockActor, cc_clock_actor, CLUTTER_TYPE_ACTOR);
+
+enum {
+  PROP_0,
+  PROP_ANGLE,
+  N_PROPERTIES
+};
+
+static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
+
+static void
+draw_clock (ClutterCairoTexture *texture,
+            cairo_t             *cr,
+            gint                 width,
+            gint                 height,
+            CcClockActor        *self)
+{
+  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+  cairo_paint (cr);
+  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+  /* Draw the clock background */
+  cairo_arc (cr, width / 2, height / 2, CLOCK_RADIUS / 2, 0.0, 2.0 * M_PI);
+  cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
+  cairo_fill_preserve (cr);
+  cairo_stroke (cr);
+
+  cairo_set_line_width (cr, CLOCK_LINE_WIDTH);
+
+  cairo_arc (cr,
+             width / 2,
+             height / 2,
+             (CLOCK_RADIUS - CLOCK_LINE_WIDTH - CLOCK_LINE_PADDING) / 2,
+             3 * M_PI_2,
+             3 * M_PI_2 + self->angle * M_PI / 180.0);
+  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+  cairo_stroke (cr);
+}
+
+static void
+cc_clock_actor_set_property (GObject      *object,
+                             guint         property_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  CcClockActor *self = CC_CLOCK_ACTOR (object);
+  ClutterContent *content;
+  content = clutter_actor_get_content (CLUTTER_ACTOR (self));
+
+  switch (property_id)
+    {
+    case PROP_ANGLE:
+      self->angle = g_value_get_float (value);
+      if (content)
+        clutter_content_invalidate (content);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+cc_clock_actor_get_property (GObject      *object,
+                             guint         property_id,
+                             GValue       *value,
+                             GParamSpec   *pspec)
+{
+  CcClockActor *self = CC_CLOCK_ACTOR (object);
+
+  switch (property_id)
+    {
+    case PROP_ANGLE:
+      g_value_set_float (value, self->angle);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+cc_clock_actor_init (CcClockActor *self)
+{
+  self->angle = 0;
+
+  ClutterContent *content;
+  content = clutter_canvas_new ();
+  /* Extra space is needed because when drawing without it,
+     it will miss 1 pixel in each of the edges */
+  clutter_canvas_set_size (CLUTTER_CANVAS (content),
+                           CLOCK_RADIUS + EXTRA_SPACE,
+                           CLOCK_RADIUS + EXTRA_SPACE);
+  clutter_actor_set_content (CLUTTER_ACTOR (self), content);
+  g_signal_connect (CLUTTER_CANVAS (content),
+                    "draw",
+                    G_CALLBACK (draw_clock),
+                    self);
+  g_object_unref (content);
+}
+
+static void
+cc_clock_actor_get_preferred_width (ClutterActor *actor,
+                                    gfloat        for_height,
+                                    gfloat       *min_width_p,
+                                    gfloat       *natural_width_p)
+{
+  *min_width_p = CLOCK_RADIUS + EXTRA_SPACE;
+  *natural_width_p = CLOCK_RADIUS + EXTRA_SPACE;
+}
+
+static void
+cc_clock_actor_get_preferred_height (ClutterActor *actor,
+                                     gfloat        for_width,
+                                     gfloat       *min_height_p,
+                                     gfloat       *natural_height_p)
+{
+  *min_height_p = CLOCK_RADIUS + EXTRA_SPACE;
+  *natural_height_p = CLOCK_RADIUS + EXTRA_SPACE;
+}
+
+
+static void
+cc_clock_actor_class_init (CcClockActorClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *clutter_actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  gobject_class->set_property = cc_clock_actor_set_property;
+  gobject_class->get_property = cc_clock_actor_get_property;
+
+  clutter_actor_class->get_preferred_width = cc_clock_actor_get_preferred_width;
+  clutter_actor_class->get_preferred_height = cc_clock_actor_get_preferred_height;
+
+  obj_properties[PROP_ANGLE] =
+    g_param_spec_float (ANGLE,
+                        "The angle of the clock's progress",
+                        "Set the angle of the clock's progress",
+                        .0,
+                        360.0,
+                        .0,
+                        G_PARAM_READWRITE |
+                        G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class,
+                                     N_PROPERTIES,
+                                     obj_properties);
+}
+
+ClutterActor *
+cc_clock_actor_new (void)
+{
+  return g_object_new (CC_CLOCK_ACTOR_TYPE, NULL);
+}
diff --git a/panels/wacom/calibrator/cc-clock-actor.h b/panels/wacom/calibrator/cc-clock-actor.h
new file mode 100644
index 0000000..6a2b147
--- /dev/null
+++ b/panels/wacom/calibrator/cc-clock-actor.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Joaquim Rocha <jrocha redhat com>
+ */
+
+#ifndef __CC_CLOCK_ACTOR_H__
+#define __CC_CLOCK_ACTOR_H__
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CC_CLOCK_ACTOR_TYPE            (cc_clock_actor_get_type ())
+#define CC_CLOCK_ACTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_CLOCK_ACTOR_TYPE, 
CcClockActor))
+#define CC_IS_CLOCK_ACTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_CLOCK_ACTOR_TYPE))
+#define CC_CLOCK_ACTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CC_CLOCK_ACTOR_TYPE, 
CcClockActorClass))
+#define CC_IS_CLOCK_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_CLOCK_ACTOR_TYPE))
+#define CC_CLOCK_ACTOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_CLOCK_ACTOR_TYPE, 
CcClockActorClass))
+
+typedef struct _CcClockActor      CcClockActor;
+typedef struct _CcClockActorClass CcClockActorClass;
+
+struct _CcClockActor
+{
+  ClutterActor parent_instance;
+
+  /*< private >*/
+  gfloat angle;
+};
+
+struct _CcClockActorClass
+{
+  ClutterActorClass parent_class;
+};
+
+ClutterActor * cc_clock_actor_new      (void);
+
+GType          cc_clock_actor_get_type (void);
+
+#endif /* __CC_CLOCK_ACTOR_H__ */
diff --git a/panels/wacom/calibrator/cc-target-actor.c b/panels/wacom/calibrator/cc-target-actor.c
new file mode 100644
index 0000000..69f4012
--- /dev/null
+++ b/panels/wacom/calibrator/cc-target-actor.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Joaquim Rocha <jrocha redhat com>
+ */
+
+#include <math.h>
+#include "cc-target-actor.h"
+
+#define CC_TARGET_ACTOR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CC_TARGET_ACTOR_TYPE, 
CcTargetActorPrivate))
+
+#define CROSS_LINES                    47
+#define CROSS_CIRCLE                   7
+#define CROSS_CIRCLE2                  27
+#define TARGET_SHOW_ANIMATION_DURATION 500
+#define TARGET_HIDE_ANIMATION_DURATION 200
+
+struct _CcTargetActorPrivate
+{
+  gdouble pos_x;
+  gdouble pos_y;
+};
+
+G_DEFINE_TYPE (CcTargetActor, cc_target_actor, CLUTTER_TYPE_ACTOR);
+
+static ClutterTransition *
+get_target_show_animation (ClutterActor *target, const gchar *property)
+{
+  ClutterTransition *transition;
+
+  transition = clutter_property_transition_new (property);
+  clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
+                                      CLUTTER_EASE_OUT_BACK);
+  clutter_timeline_set_duration (CLUTTER_TIMELINE (transition),
+                                 TARGET_SHOW_ANIMATION_DURATION);
+  clutter_transition_set_animatable (transition,
+                                     CLUTTER_ANIMATABLE (target));
+  clutter_transition_set_from (transition, G_TYPE_FLOAT, 0.0);
+  clutter_transition_set_to (transition, G_TYPE_FLOAT, 1.0);
+
+  return transition;
+}
+
+static ClutterTransition *
+get_target_hide_animation (ClutterActor *target, const gchar *property)
+{
+  ClutterTransition *transition;
+
+  transition = get_target_show_animation (target, property);
+  clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
+                                      CLUTTER_EASE_OUT);
+  clutter_timeline_set_duration (CLUTTER_TIMELINE (transition),
+                                 TARGET_HIDE_ANIMATION_DURATION);
+  clutter_transition_set_from (transition, G_TYPE_FLOAT, 1.0);
+  clutter_transition_set_to (transition, G_TYPE_FLOAT, 0.0);
+
+  return transition;
+}
+
+static void
+show_target (CcTargetActor *self)
+{
+  ClutterTransition *transition;
+
+  transition = get_target_show_animation (CLUTTER_ACTOR (self), "scale-x");
+  clutter_timeline_start (CLUTTER_TIMELINE (transition));
+
+  transition = get_target_show_animation (CLUTTER_ACTOR (self), "scale-y");
+  clutter_timeline_start (CLUTTER_TIMELINE (transition));
+}
+
+static void
+on_target_animation_complete (ClutterTimeline *timeline,
+                              CcTargetActor   *self)
+{
+  CcTargetActorPrivate *priv;
+  priv = CC_TARGET_ACTOR_GET_PRIVATE (self);
+
+  clutter_actor_show (CLUTTER_ACTOR (self));
+  clutter_actor_set_position (CLUTTER_ACTOR (self),
+                              priv->pos_x,
+                              priv->pos_y);
+
+  show_target (self);
+}
+
+static void
+draw_target (ClutterCairoTexture *texture,
+             cairo_t             *cr,
+             gint                 width,
+             gint                 height,
+             gpointer             data)
+{
+  cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+
+  cairo_set_line_width(cr, 1);
+  cairo_move_to(cr, 0, height / 2.0);
+  cairo_rel_line_to(cr, width, 0);
+  cairo_move_to(cr, width / 2.0, 0);
+  cairo_rel_line_to(cr, 0, height * 2);
+  cairo_stroke(cr);
+
+  cairo_set_line_width(cr, 2);
+  cairo_arc(cr, width / 2.0, height / 2.0, CROSS_CIRCLE, 0.0, 2.0 * M_PI);
+  cairo_stroke(cr);
+
+  cairo_set_line_width(cr, 5);
+  cairo_arc(cr, width / 2.0, height / 2.0, CROSS_CIRCLE2, 0.0, 2.0 * M_PI);
+  cairo_stroke(cr);
+}
+
+static void
+cc_target_actor_init (CcTargetActor *self)
+{
+  ClutterContent *content;
+  ClutterPoint anchor;
+  CcTargetActorPrivate *priv;
+
+  priv = CC_TARGET_ACTOR_GET_PRIVATE (self);
+  priv->pos_x = .0;
+  priv->pos_y = .0;
+
+  content = clutter_canvas_new ();
+  clutter_actor_set_content (CLUTTER_ACTOR (self), content);
+  g_object_unref (content);
+
+  clutter_canvas_set_size (CLUTTER_CANVAS (content),
+                           CROSS_LINES * 2,
+                           CROSS_LINES * 2);
+  g_signal_connect (CLUTTER_CANVAS (content),
+                    "draw",
+                    G_CALLBACK (draw_target),
+                    self);
+  clutter_content_invalidate (content);
+
+  anchor.x = .5;
+  anchor.y = .5;
+
+  g_object_set (self, "pivot-point", &anchor, NULL);
+}
+
+static void
+cc_target_actor_get_preferred_width (ClutterActor *actor,
+                           gfloat        for_height,
+                           gfloat       *min_width_p,
+                           gfloat       *natural_width_p)
+{
+  *min_width_p = CROSS_LINES * 2;
+  *natural_width_p = CROSS_LINES * 2;
+}
+
+static void
+cc_target_actor_get_preferred_height (ClutterActor *actor,
+                            gfloat        for_width,
+                            gfloat       *min_height_p,
+                            gfloat       *natural_height_p)
+{
+  *min_height_p = CROSS_LINES * 2;
+  *natural_height_p = CROSS_LINES * 2;
+}
+
+
+static void
+cc_target_actor_class_init (CcTargetActorClass *klass)
+{
+  ClutterActorClass *clutter_actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  clutter_actor_class->get_preferred_width = cc_target_actor_get_preferred_width;
+  clutter_actor_class->get_preferred_height = cc_target_actor_get_preferred_height;
+
+  g_type_class_add_private (klass, sizeof (CcTargetActorPrivate));
+}
+
+void
+cc_target_actor_move (CcTargetActor *self, gdouble x, gdouble y)
+{
+  g_return_if_fail (CC_IS_TARGET_ACTOR (self));
+
+  CcTargetActorPrivate *priv;
+  ClutterTransition *transition;
+  gboolean target_visible;
+
+  priv = CC_TARGET_ACTOR_GET_PRIVATE (self);
+  priv->pos_x = x;
+  priv->pos_y = y;
+
+  g_object_get (self, "visible", &target_visible, NULL);
+
+  if (target_visible)
+    {
+      transition = get_target_hide_animation (CLUTTER_ACTOR (self), "scale-x");
+      clutter_timeline_start (CLUTTER_TIMELINE (transition));
+      transition = get_target_hide_animation (CLUTTER_ACTOR (self), "scale-y");
+      clutter_timeline_start (CLUTTER_TIMELINE (transition));
+
+      g_signal_connect (CLUTTER_TIMELINE (transition),
+                        "completed",
+                        G_CALLBACK (on_target_animation_complete),
+                        self);
+    }
+  else
+    {
+      clutter_actor_show (CLUTTER_ACTOR (self));
+
+      clutter_actor_set_position (CLUTTER_ACTOR (self), x, y);
+
+      show_target (self);
+    }
+}
+
+ClutterActor *
+cc_target_actor_new (void)
+{
+  return g_object_new (CC_TARGET_ACTOR_TYPE, NULL);
+}
diff --git a/panels/wacom/calibrator/cc-target-actor.h b/panels/wacom/calibrator/cc-target-actor.h
new file mode 100644
index 0000000..c7d63f8
--- /dev/null
+++ b/panels/wacom/calibrator/cc-target-actor.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Joaquim Rocha <jrocha redhat com>
+ */
+
+#ifndef __CC_TARGET_ACTOR_H__
+#define __CC_TARGET_ACTOR_H__
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CC_TARGET_ACTOR_TYPE            (cc_target_actor_get_type ())
+#define CC_TARGET_ACTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TARGET_ACTOR_TYPE, 
CcTargetActor))
+#define CC_IS_TARGET_ACTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TARGET_ACTOR_TYPE))
+#define CC_TARGET_ACTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CC_TARGET_ACTOR_TYPE, 
CcTargetActorClass))
+#define CC_IS_TARGET_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_TARGET_ACTOR_TYPE))
+#define CC_TARGET_ACTOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_TARGET_ACTOR_TYPE, 
CcTargetActorClass))
+
+typedef struct _CcTargetActor        CcTargetActor;
+typedef struct _CcTargetActorClass   CcTargetActorClass;
+typedef struct _CcTargetActorPrivate CcTargetActorPrivate;
+
+struct _CcTargetActor
+{
+  ClutterActor parent_instance;
+
+  /*< private >*/
+  CcTargetActorPrivate *priv;
+};
+
+struct _CcTargetActorClass
+{
+  ClutterActorClass parent_class;
+};
+
+ClutterActor * cc_target_actor_new      (void);
+void           cc_target_actor_move     (CcTargetActor *target,
+                                         gdouble        x,
+                                         gdouble        y);
+
+GType          cc_target_actor_get_type (void);
+
+#endif /* __CC_TARGET_ACTOR_H__ */
diff --git a/panels/wacom/calibrator/main.c b/panels/wacom/calibrator/main.c
index 2368a10..7758713 100644
--- a/panels/wacom/calibrator/main.c
+++ b/panels/wacom/calibrator/main.c
@@ -28,10 +28,11 @@
 #include <string.h>
 #include <dirent.h>
 #include <glib/gi18n.h>
+#include <clutter-gtk/clutter-gtk.h>
 
 #include <X11/extensions/XInput.h>
 
-#include "gui_gtk.h"
+#include "calibrator-gui.h"
 #include "calibrator.h"
 
 /**
@@ -397,7 +398,11 @@ int main(int argc, char** argv)
     g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
 
     /* GTK setup */
-    gtk_init(&argc, &argv);
+    if (gtk_clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+    {
+      g_critical ("Unable to initialize Clutter");
+      return 1;
+    }
 
     calib_area = calib_area_new (NULL,
                                 0,  /* monitor */
diff --git a/panels/wacom/cc-wacom-page.c b/panels/wacom/cc-wacom-page.c
index 5e10c5b..72111c8 100644
--- a/panels/wacom/cc-wacom-page.c
+++ b/panels/wacom/cc-wacom-page.c
@@ -34,7 +34,7 @@
 #include "cc-wacom-mapping-panel.h"
 #include "cc-wacom-stylus-page.h"
 #include "gsd-enums.h"
-#include "gui_gtk.h"
+#include "calibrator-gui.h"
 
 #include <string.h>
 
diff --git a/panels/wacom/test-wacom.c b/panels/wacom/test-wacom.c
index f286071..68dd238 100644
--- a/panels/wacom/test-wacom.c
+++ b/panels/wacom/test-wacom.c
@@ -2,9 +2,11 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#include <clutter-gtk/clutter-gtk.h>
 
 #include "cc-wacom-page.h"
 #include "gsd-wacom-device.h"
+#include "clutter/clutter.h"
 
 #define FIXED_WIDTH 675
 
@@ -69,7 +71,10 @@ int main (int argc, char **argv)
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
        textdomain (GETTEXT_PACKAGE);
 
-       gtk_init (&argc, &argv);
+       if (gtk_clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) {
+               g_critical ("Unable to initialize Clutter");
+               return 1;
+        }
 
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 68b70e9..ad7a68f 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -2,6 +2,7 @@ INCLUDES =                                      \
        -I$(top_srcdir)                         \
        $(SHELL_CFLAGS)                         \
        $(CHEESE_CFLAGS)                        \
+       $(WACOM_PANEL_CFLAGS)                   \
        -I$(top_srcdir)/panels/common/          \
        -I$(top_srcdir)/libgd
 
diff --git a/shell/cc-application.c b/shell/cc-application.c
index 72a6143..e7de6f7 100644
--- a/shell/cc-application.c
+++ b/shell/cc-application.c
@@ -30,9 +30,12 @@
 #include "cc-shell-log.h"
 #include "cc-window.h"
 
+#if defined(HAVE_CHEESE) || defined(HAVE_WACOM)
+#include <clutter-gtk/clutter-gtk.h>
+#endif /* HAVE_CHEESE || HAVE_WACOM */
+
 #ifdef HAVE_CHEESE
 #include <cheese-gtk.h>
-#include <clutter-gtk/clutter-gtk.h>
 #endif /* HAVE_CHEESE */
 
 struct _CcApplicationPrivate
@@ -277,13 +280,13 @@ cc_application_startup (GApplication *application)
 
   G_APPLICATION_CLASS (cc_application_parent_class)->startup (application);
 
-#ifdef HAVE_CHEESE
+#if defined(HAVE_CHEESE) || defined(HAVE_WACOM)
   if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
     {
       g_critical ("Unable to initialize Clutter");
       return;
     }
-#endif /* HAVE_CHEESE */
+#endif /* HAVE_CHEESE || HAVE_WACOM */
 
   /* register a symbolic icon size for use in sidebar lists */
   gtk_icon_size_register ("cc-sidebar-list", 24, 24);


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