[gnome-games] aisleriot: Refactor AisleriotBoard



commit 3bc45eef8d1180cefc72cf52a03f3e75b5f4c764
Author: Christian Persch <chpe gnome org>
Date:   Thu Nov 19 20:05:34 2009 +0100

    aisleriot: Refactor AisleriotBoard
    
    Split AisleriotBoard in two parts. The widget part becomes
    ArClutterEmbed; the rest is made into a ClutterActor.
    
    Split the style settings off into the ArStyle object, and make
    ArClutterEmbed synchronise the widget style and GtkSettings properties
    to its style.

 Makefile.am                         |    1 +
 aisleriot/Makefile.am               |   12 +-
 aisleriot/ar-clutter-embed.c        |  550 ++++++++++++
 aisleriot/ar-clutter-embed.h        |   61 ++
 aisleriot/ar-cursor.c               |  109 +++
 aisleriot/ar-cursor.h               |   38 +
 aisleriot/ar-style-private.h        |   69 ++
 aisleriot/ar-style.c                |  621 +++++++++++++
 aisleriot/ar-style.h                |  109 +++
 aisleriot/baize.c                   |   50 +-
 aisleriot/board-noclutter.c         |  124 ++--
 aisleriot/board-noclutter.h         |   83 ++
 aisleriot/board.c                   | 1631 ++++++++++++++++-------------------
 aisleriot/board.h                   |   77 +-
 aisleriot/card.c                    |   21 +-
 aisleriot/game.c                    |   32 +-
 aisleriot/game.h                    |    8 +-
 aisleriot/slot-renderer.c           |  136 ++--
 aisleriot/slot-renderer.h           |   10 +-
 aisleriot/window.c                  |  144 +++-
 libgames-support/games-debug.c      |    7 +-
 libgames-support/games-debug.h      |    7 +-
 libgames-support/games-marshal.list |    1 +
 23 files changed, 2764 insertions(+), 1137 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 29e7cf4..ce4b18a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -45,6 +45,7 @@ MAINTAINERCLEANFILES = \
 	$(srcdir)/aclocal.m4 \
 	$(srcdir)/autoscan.log \
 	$(srcdir)/compile \
+	$(srcdir)/py-compile \
 	$(srcdir)/config.guess \
 	$(srcdir)/config.h.in \
 	$(srcdir)/config.sub \
diff --git a/aisleriot/Makefile.am b/aisleriot/Makefile.am
index f1b33a4..f54fb57 100644
--- a/aisleriot/Makefile.am
+++ b/aisleriot/Makefile.am
@@ -22,8 +22,8 @@ bin_PROGRAMS = sol
 sol_SOURCES = \
 	ar-game-chooser.c \
 	ar-game-chooser.h \
-	board.h		\
 	board-noclutter.c \
+	board-noclutter.h \
 	conf.c		\
 	conf.h		\
 	game.c		\
@@ -99,12 +99,18 @@ if ENABLE_AISLERIOT_CLUTTER
 noinst_PROGRAMS = sol-clutter
 
 sol_clutter_SOURCES = \
+	ar-clutter-embed.c \
+	ar-clutter-embed.h \
+	ar-cursor.c	\
+	ar-cursor.h	\
 	ar-game-chooser.c \
 	ar-game-chooser.h \
-	board.h		\
-	board.c		\
+	ar-style.c	\
+	ar-style.h	\
 	baize.c		\
 	baize.h		\
+	board.c		\
+	board.h		\
 	card.c          \
 	card.h          \
 	conf.c		\
diff --git a/aisleriot/ar-clutter-embed.c b/aisleriot/ar-clutter-embed.c
new file mode 100644
index 0000000..21dc499
--- /dev/null
+++ b/aisleriot/ar-clutter-embed.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright © 1998, 2003 Jonathan Blandford <jrb mit edu>
+ * Copyright © 2007, 2008, 2009 Christian Persch
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "ar-clutter-embed.h"
+
+#include "ar-style.h"
+#include "ar-style-private.h"
+
+/**
+ * SECTION: ar-clutter-embed
+ * @short_description: a #GtkClutterEmbed derivative
+ *
+ * #ArClutterEmbed is a #GtkClutterEmbed derivative that syncs the
+ * properties of a #ArStyle to its style properties and the #GtkSettings
+ * properties of its #GdkScreen.
+ */
+
+G_DEFINE_TYPE (ArClutterEmbed, ar_clutter_embed, GTK_CLUTTER_TYPE_EMBED)
+
+enum
+{
+  PROP_0,
+  PROP_STYLE
+};
+
+struct _ArClutterEmbedPrivate
+{
+  ArStyle *style;
+
+  GdkCursor *cursor[AR_LAST_CURSOR];
+};
+
+#define I_(string) (g_intern_static_string (string))
+
+/* private functions */
+
+static void
+sync_settings (GtkSettings *settings,
+               GParamSpec *pspec,
+               ArClutterEmbed *embed)
+{
+  ArClutterEmbedPrivate *embed_priv = embed->priv;
+  ArStyle *style = embed_priv->style;
+  ArStylePrivate *style_priv = style->priv;
+  GObject *style_object = G_OBJECT (style);
+  const char *pspec_name;
+
+  if (pspec)
+    pspec_name = pspec->name;
+  else
+    pspec_name = NULL;
+
+  g_object_freeze_notify (style_object);
+
+  if (pspec_name == NULL || pspec_name == I_("gtk-dnd-drag-threshold")) {
+    int threshold;
+
+    g_object_get (settings, "gtk-dnd-drag-threshold", &threshold, NULL);
+
+    if (threshold != style_priv->dnd_drag_threshold) {
+      style_priv->dnd_drag_threshold = threshold;
+
+      g_object_notify (style_object, AR_STYLE_PROP_DND_DRAG_THRESHOLD);
+    }
+  }
+
+  if (pspec_name == NULL || pspec_name == I_("gtk-double-click-time")) {
+    int double_click_time;
+
+    g_object_get (settings, "gtk-double-click-time", &double_click_time, NULL);
+
+    if (double_click_time != style_priv->double_click_time) {
+      style_priv->double_click_time = double_click_time;
+
+      g_object_notify (style_object, AR_STYLE_PROP_DOUBLE_CLICK_TIME);
+    }
+  }
+
+  if (pspec_name == NULL || pspec_name == I_("gtk-enable-animations")) {
+    gboolean enable;
+
+    g_object_get (settings, "gtk-enable-animations", &enable, NULL);
+
+    if (enable != style_priv->enable_animations_gtk) {
+      style_priv->enable_animations_gtk = enable;
+
+      /* FIXMEchpe: only notify if the effective setting changed */
+      g_object_notify (style_object, AR_STYLE_PROP_ENABLE_ANIMATIONS);
+    }
+  }
+
+#if GTK_CHECK_VERSION (2, 14, 0)
+  if (pspec_name == NULL || pspec_name == I_("gtk-enable-event-sounds")) {
+    gboolean enable;
+
+    g_object_get (settings, "gtk-enable-event-sounds", &enable, NULL);
+
+    if (enable != style_priv->enable_sound_gtk) {
+      style_priv->enable_sound_gtk = enable;
+
+      /* FIXMEchpe: only notify if the effective setting changed */
+      g_object_notify (style_object, AR_STYLE_PROP_ENABLE_SOUND);
+    }
+  }
+#endif /* GTK+ >= 2.14.0 */
+
+#if GTK_CHECK_VERSION (2, 10, 0)
+  if (pspec_name == NULL || pspec_name == I_("gtk-touchscreen-mode")) {
+    gboolean enable;
+
+    g_object_get (settings, "gtk-touchscreen-mode", &enable, NULL);
+
+    if (enable != style_priv->touchscreen_mode) {
+      style_priv->touchscreen_mode = enable;
+
+      /* FIXMEchpe: only notify if the effective setting changed */
+      g_object_notify (style_object, AR_STYLE_PROP_TOUCHSCREEN_MODE);
+    }
+  }
+#endif /* GTK+ >= 2.10.0 */
+
+  g_object_thaw_notify (style_object);
+}
+
+static void
+sync_direction (ArClutterEmbed *embed,
+                GtkTextDirection previous_direction)
+{
+
+  ArClutterEmbedPrivate *embed_priv = embed->priv;
+  ArStyle *style = embed_priv->style;
+  ArStylePrivate *style_priv = style->priv;
+  GObject *style_object = G_OBJECT (style);
+  GtkTextDirection direction;
+  gboolean rtl;
+
+  direction = gtk_widget_get_direction (GTK_WIDGET (embed));
+  if (direction == previous_direction)
+    return;
+
+  g_object_freeze_notify (style_object);
+
+  rtl = (direction == GTK_TEXT_DIR_RTL);
+
+  if (style_priv->rtl != rtl) {
+    style_priv->rtl = rtl;
+
+    g_object_notify (style_object, AR_STYLE_PROP_RTL);
+  }
+
+  g_object_thaw_notify (style_object);
+}
+
+/* GtkWidgetClass impl */
+
+static void
+ar_clutter_embed_realize (GtkWidget *widget)
+{
+  ArClutterEmbed *embed = AR_CLUTTER_EMBED (widget);
+  ArClutterEmbedPrivate *priv = embed->priv;
+#ifndef HAVE_HILDON
+  GdkDisplay *display;
+#endif
+
+  GTK_WIDGET_CLASS (ar_clutter_embed_parent_class)->realize (widget);
+
+  /* FIXMEchpe: this isn't really HILDON, but don't-support-mouse */
+#ifndef HAVE_HILDON
+  /* Create cursors */
+  display = gtk_widget_get_display (widget);
+
+  priv->cursor[AR_CURSOR_DEFAULT] = gdk_cursor_new_for_display (display, GDK_LEFT_PTR);
+  priv->cursor[AR_CURSOR_OPEN] = ar_cursor_new (widget->window, AR_CURSOR_OPEN);
+  priv->cursor[AR_CURSOR_CLOSED] = ar_cursor_new (widget->window, AR_CURSOR_CLOSED);
+  priv->cursor[AR_CURSOR_DROPPABLE] = gdk_cursor_new_for_display (display, GDK_DOUBLE_ARROW); /* FIXMEchpe: better cursor */
+#endif /* !HAVE_HILDON */
+
+  ar_clutter_embed_set_cursor (embed, AR_CURSOR_DEFAULT);
+}
+
+static void
+ar_clutter_embed_unrealize (GtkWidget *widget)
+{
+  /* FIXMEchpe */
+#ifndef HAVE_HILDON
+  ArClutterEmbed *embed = AR_CLUTTER_EMBED (widget);
+  ArClutterEmbedPrivate *priv = embed->priv;
+  guint i;
+
+  for (i = 0; i < AR_LAST_CURSOR; ++i) {
+    gdk_cursor_unref (priv->cursor[i]);
+    priv->cursor[i] = NULL;
+  }
+#endif /* !HAVE_HILDON*/
+
+  GTK_WIDGET_CLASS (ar_clutter_embed_parent_class)->unrealize (widget);
+}
+
+static void
+ar_clutter_embed_screen_changed (GtkWidget *widget,
+                                  GdkScreen *previous_screen)
+{
+  ArClutterEmbed *embed = AR_CLUTTER_EMBED (widget);
+  ArClutterEmbedPrivate *priv = embed->priv;
+  GdkScreen *screen;
+  GtkSettings *settings;
+  void (* screen_changed) (GtkWidget*, GdkScreen *) =
+    GTK_WIDGET_CLASS (ar_clutter_embed_parent_class)->screen_changed;
+
+  if (screen_changed) {
+    screen_changed (widget, previous_screen);
+  }
+
+  g_assert (priv->style != NULL);
+
+  screen = gtk_widget_get_screen (widget);
+  if (screen == previous_screen)
+    return;
+
+  if (previous_screen != NULL) {
+    g_signal_handlers_disconnect_by_func (gtk_settings_get_for_screen (previous_screen),
+                                          G_CALLBACK (sync_settings),
+                                          embed);
+  }
+
+  if (screen == NULL)
+    return;
+
+  settings = gtk_settings_get_for_screen (screen);
+
+  sync_settings (settings, NULL, embed);
+  g_signal_connect (settings, "notify::gtk-double-click-time",
+                    G_CALLBACK (sync_settings), embed);
+  g_signal_connect (settings, "notify::gtk-enable-animations",
+                    G_CALLBACK (sync_settings), embed);
+#if GTK_CHECK_VERSION (2, 14, 0)
+  g_signal_connect (settings, "notify::gtk-enable-event-sounds",
+                    G_CALLBACK (sync_settings), embed);
+#endif /* GTK+ >= 2.14.0 */
+#if GTK_CHECK_VERSION (2, 10, 0)
+  g_signal_connect (settings, "notify::gtk-touchscreen-mode",
+                    G_CALLBACK (sync_settings), embed);
+#endif /* GTK+ >= 2.10.0 */
+}
+
+static void
+ar_clutter_embed_style_set (GtkWidget *widget,
+                             GtkStyle *previous_style)
+{
+  ArClutterEmbed *embed = AR_CLUTTER_EMBED (widget);
+  ArClutterEmbedPrivate *embed_priv = embed->priv;
+  ArStyle *style = embed_priv->style;
+  ArStylePrivate *style_priv = style->priv;
+  GObject *style_object = G_OBJECT (style);
+  GdkColor *color = NULL;
+  ClutterColor selection_color;
+  int focus_line_width, focus_padding;
+  gboolean interior_focus;
+  double card_slot_ratio;
+
+  GTK_WIDGET_CLASS (ar_clutter_embed_parent_class)->style_set (widget, previous_style);
+
+  g_object_freeze_notify (style_object);
+
+  gtk_widget_style_get (widget,
+                        "interior-focus", &interior_focus,
+                        "focus-line-width", &focus_line_width,
+                        "focus-padding", &focus_padding,
+                        "card-slot-ratio", &card_slot_ratio,
+                        "selection-color", &color,
+                        NULL);
+
+  if (style_priv->interior_focus != interior_focus) {
+    style_priv->interior_focus = interior_focus;
+
+    g_object_notify (style_object, AR_STYLE_PROP_INTERIOR_FOCUS);
+  }
+
+  if (style_priv->focus_line_width != focus_line_width) {
+    style_priv->focus_line_width = focus_line_width;
+
+    g_object_notify (style_object, AR_STYLE_PROP_FOCUS_LINE_WIDTH);
+  }
+
+  if (style_priv->focus_padding != focus_padding) {
+    style_priv->focus_padding = focus_padding;
+
+    g_object_notify (style_object, AR_STYLE_PROP_FOCUS_PADDING);
+  }
+
+  if (style_priv->card_slot_ratio != card_slot_ratio) {
+    style_priv->card_slot_ratio = card_slot_ratio;
+
+    g_object_notify (style_object, AR_STYLE_PROP_CARD_SLOT_RATIO);
+  }
+
+  if (color != NULL) {
+    _ar_clutter_color_from_gdk_color (&selection_color, color);
+    gdk_color_free (color);
+  } else {
+    _ar_clutter_color_from_gdk_color (&selection_color, &default_selection_color);
+  }
+
+  if (!clutter_color_equal (&style_priv->selection_color, &selection_color)) {
+    style_priv->selection_color = selection_color;
+
+    g_object_notify (style_object, AR_STYLE_PROP_SELECTION_COLOR);
+  }
+
+  g_object_thaw_notify (style_object);
+}
+
+static void
+ar_clutter_embed_direction_changed (GtkWidget *widget,
+                                    GtkTextDirection previous_direction)
+{
+  ArClutterEmbed *embed = AR_CLUTTER_EMBED (widget);
+
+  GTK_WIDGET_CLASS (ar_clutter_embed_parent_class)->direction_changed (widget, previous_direction);
+
+  sync_direction (embed, previous_direction);
+}
+
+static gboolean
+ar_clutter_embed_focus_in (GtkWidget *widget,
+                           GdkEventFocus *event)
+{
+  gboolean retval;
+
+  retval = GTK_WIDGET_CLASS (ar_clutter_embed_parent_class)->focus_in_event (widget, event);
+
+#if 0
+  ClutterActor *stage;
+  stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (widget));
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), FIXME board actor);
+#endif
+
+  return retval;
+}
+
+static gboolean
+ar_clutter_embed_focus_out (GtkWidget *widget,
+                            GdkEventFocus *event)
+{
+#ifdef FIXMEchpe
+  clear_state (board);
+#endif
+
+  return GTK_WIDGET_CLASS (ar_clutter_embed_parent_class)->focus_out_event (widget, event);
+}
+
+static gboolean
+ar_clutter_embed_focus (GtkWidget *widget,
+                        GtkDirectionType direction)
+{
+//   ArClutterEmbed *embed = AR_CLUTTER_EMBED (embed);
+//   ArClutterEmbedPrivate *priv = embed->priv;
+  int count;
+  gboolean retval = FALSE;
+
+  switch (direction) {
+    case GTK_DIR_TAB_FORWARD:
+      count = 1;
+      break;
+    case GTK_DIR_TAB_BACKWARD:
+      count = -1;
+      break;
+    default:
+      break;
+  }
+
+#ifdef FIXMEchpe
+  g_signal_emit_by_name (priv->board_actor, "focus", count, &retval);
+#endif
+
+  if (retval)
+    return TRUE;
+
+  return GTK_WIDGET_CLASS (ar_clutter_embed_parent_class)->focus (widget, direction);
+}
+
+/* GObjectClass impl */
+
+static void
+ar_clutter_embed_init (ArClutterEmbed *embed)
+{
+  GtkWidget *widget = GTK_WIDGET (embed);
+
+  embed->priv = G_TYPE_INSTANCE_GET_PRIVATE (embed, AR_TYPE_CLUTTER_EMBED, ArClutterEmbedPrivate);
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+}
+
+static void
+ar_clutter_embed_dispose (GObject *object)
+{
+  ArClutterEmbed *embed = AR_CLUTTER_EMBED (object);
+  GtkWidget *widget = GTK_WIDGET (embed);
+
+  g_signal_handlers_disconnect_by_func (gtk_widget_get_settings (widget),
+                                        G_CALLBACK (sync_settings),
+                                        embed);
+
+  G_OBJECT_CLASS (ar_clutter_embed_parent_class)->dispose (object);
+}
+
+static void
+ar_clutter_embed_finalize (GObject *object)
+{
+  ArClutterEmbed *embed = AR_CLUTTER_EMBED (object);
+  ArClutterEmbedPrivate *priv = embed->priv;
+
+  g_assert (priv->style != NULL);
+  g_object_unref (priv->style);
+
+  G_OBJECT_CLASS (ar_clutter_embed_parent_class)->finalize (object);
+}
+
+static void
+ar_clutter_embed_set_property (GObject      *object,
+                                guint         property_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  ArClutterEmbed *embed = AR_CLUTTER_EMBED (object);
+  ArClutterEmbedPrivate *priv = embed->priv;
+
+  switch (property_id) {
+    case PROP_STYLE:
+      priv->style = g_value_dup_object (value);
+
+      /* This is necessary since we don't get an initial change notification! */
+      sync_direction (embed, GTK_TEXT_DIR_LTR);
+
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+ar_clutter_embed_class_init (ArClutterEmbedClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ArClutterEmbedPrivate));
+
+  object_class->set_property = ar_clutter_embed_set_property;
+  object_class->dispose = ar_clutter_embed_dispose;
+  object_class->finalize = ar_clutter_embed_finalize;
+
+  widget_class->realize = ar_clutter_embed_realize;
+  widget_class->unrealize = ar_clutter_embed_unrealize;
+  widget_class->style_set = ar_clutter_embed_style_set;
+  widget_class->direction_changed = ar_clutter_embed_direction_changed;
+  widget_class->screen_changed = ar_clutter_embed_screen_changed;
+  widget_class->focus_in_event = ar_clutter_embed_focus_in;
+  widget_class->focus_out_event = ar_clutter_embed_focus_out;
+  widget_class->focus = ar_clutter_embed_focus;
+
+  /**
+   * ArClutterEmbed:style:
+   *
+   * An #ArStyle that @embed will update with its widget style properties.
+   */
+  g_object_class_install_property
+    (object_class,
+     PROP_STYLE,
+     g_param_spec_object ("style", NULL, NULL,
+                          AR_TYPE_STYLE,
+                          G_PARAM_WRITABLE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+  gtk_widget_class_install_style_property
+    (widget_class,
+     g_param_spec_boxed ("selection-color", NULL, NULL,
+                         GDK_TYPE_COLOR,
+                         G_PARAM_READWRITE |
+                         G_PARAM_STATIC_STRINGS));
+
+  /**
+   * ArClutterEmbed:card-slot-ratio:
+   *
+   * The ratio of card to slot size. Note that this is the ratio of
+   * card width/slot width and card height/slot height, not of
+   * card area/slot area.
+  */
+  gtk_widget_class_install_style_property
+    (widget_class,
+     g_param_spec_double ("card-slot-ratio", NULL, NULL,
+                          0.1, 1.0, DEFAULT_CARD_SLOT_RATIO,
+                          G_PARAM_READWRITE |
+                          G_PARAM_STATIC_STRINGS));
+}
+
+/* public API */
+
+/**
+ * ar_clutter_embed_new:
+ * @style: an #ArStyle
+ *
+ * Returns: a new #ArClutterEmbed
+ */
+ArClutterEmbed *
+ar_clutter_embed_new (ArStyle *style)
+{
+  return g_object_new (AR_TYPE_CLUTTER_EMBED,
+                       "style", style,
+                       NULL);
+}
+
+/**
+ * ar_clutter_embed_set_cursor:
+ * @embed: an #ArClutterEmbed
+ * @cursor_type: the cursor type
+ *
+ * Sets the cursor on @embed to @cursor_type.
+ */
+void
+ar_clutter_embed_set_cursor (ArClutterEmbed *embed,
+                             ArCursorType cursor)
+{
+  /* FIXMEchpe */
+#ifndef HAVE_HILDON
+  ArClutterEmbedPrivate *priv = embed->priv;
+
+  gdk_window_set_cursor (GTK_WIDGET (embed)->window,
+                         priv->cursor[cursor]);
+#endif /* !HAVE_HILDON */
+}
diff --git a/aisleriot/ar-clutter-embed.h b/aisleriot/ar-clutter-embed.h
new file mode 100644
index 0000000..6bc9e7c
--- /dev/null
+++ b/aisleriot/ar-clutter-embed.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2009 Christian Persch <chpe gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __AR_CLUTTER_EMBED_H__
+#define __AR_CLUTTER_EMBED_H__
+
+#include <clutter-gtk/clutter-gtk.h>
+
+#include "ar-style.h"
+#include "ar-cursor.h"
+
+G_BEGIN_DECLS
+
+#define AR_TYPE_CLUTTER_EMBED            (ar_clutter_embed_get_type())
+#define AR_CLUTTER_EMBED(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), AR_TYPE_CLUTTER_EMBED, ArClutterEmbed))
+#define AR_CLUTTER_EMBED_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  AR_TYPE_CLUTTER_EMBED, ArClutterEmbedClass))
+#define AR_IS_CLUTTER_EMBED(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AR_TYPE_CLUTTER_EMBED))
+#define AR_IS_CLUTTER_EMBED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  AR_TYPE_CLUTTER_EMBED))
+#define AR_CLUTTER_EMBED_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  AR_TYPE_CLUTTER_EMBED, ArClutterEmbedClass))
+
+typedef struct _ArClutterEmbed        ArClutterEmbed;
+typedef struct _ArClutterEmbedClass   ArClutterEmbedClass;
+typedef struct _ArClutterEmbedPrivate ArClutterEmbedPrivate;
+
+struct _ArClutterEmbed
+{
+  GtkClutterEmbed parent;
+
+  /*< private >*/
+  ArClutterEmbedPrivate *priv;
+};
+
+struct _ArClutterEmbedClass
+{
+  GtkClutterEmbedClass parent_class;
+};
+
+GType ar_clutter_embed_get_type (void);
+
+ArClutterEmbed* ar_clutter_embed_new (ArStyle *style);
+
+void ar_clutter_embed_set_cursor (ArClutterEmbed *embed,
+                                  ArCursorType cursor_type);
+
+G_END_DECLS
+
+#endif /* __AR_CLUTTER_EMBED_H__ */
diff --git a/aisleriot/ar-cursor.c b/aisleriot/ar-cursor.c
new file mode 100644
index 0000000..00f7e49
--- /dev/null
+++ b/aisleriot/ar-cursor.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 1998, 2003 Jonathan Blandford <jrb mit edu>
+ * Copyright © 2007, 2008, 2009 Christian Persch
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "ar-cursor.h"
+
+#ifndef HAVE_HILDON
+
+/* These cursors borrowed from EOG */
+/* FIXMEchpe use themeable cursors here! */
+#define hand_closed_data_width 20
+#define hand_closed_data_height 20
+static const char hand_closed_data_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x3f, 0x00,
+  0x80, 0xff, 0x00, 0x80, 0xff, 0x00, 0xb0, 0xff, 0x00, 0xf0, 0xff, 0x00,
+  0xe0, 0xff, 0x00, 0xe0, 0x7f, 0x00, 0xc0, 0x7f, 0x00, 0x80, 0x3f, 0x00,
+  0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define hand_closed_mask_width 20
+#define hand_closed_mask_height 20
+static const char hand_closed_mask_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x3f, 0x00, 0xc0, 0xff, 0x00,
+  0xc0, 0xff, 0x01, 0xf0, 0xff, 0x01, 0xf8, 0xff, 0x01, 0xf8, 0xff, 0x01,
+  0xf0, 0xff, 0x01, 0xf0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xc0, 0x7f, 0x00,
+  0x80, 0x7f, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define hand_open_data_width 20
+#define hand_open_data_height 20
+static const char hand_open_data_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
+  0x60, 0x36, 0x00, 0x60, 0x36, 0x00, 0xc0, 0x36, 0x01, 0xc0, 0xb6, 0x01,
+  0x80, 0xbf, 0x01, 0x98, 0xff, 0x01, 0xb8, 0xff, 0x00, 0xf0, 0xff, 0x00,
+  0xe0, 0xff, 0x00, 0xe0, 0x7f, 0x00, 0xc0, 0x7f, 0x00, 0x80, 0x3f, 0x00,
+  0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define hand_open_mask_width 20
+#define hand_open_mask_height 20
+static const char hand_open_mask_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x3f, 0x00,
+  0xf0, 0x7f, 0x00, 0xf0, 0x7f, 0x01, 0xe0, 0xff, 0x03, 0xe0, 0xff, 0x03,
+  0xd8, 0xff, 0x03, 0xfc, 0xff, 0x03, 0xfc, 0xff, 0x01, 0xf8, 0xff, 0x01,
+  0xf0, 0xff, 0x01, 0xf0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xc0, 0x7f, 0x00,
+  0x80, 0x7f, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static GdkCursor *
+ar_cursor_new_from_data (GdkWindow *window,
+                         const char *data,
+                         const char *mask_data)
+{
+  const GdkColor fg = { 0, 65535, 65535, 65535 };
+  const GdkColor bg = { 0, 0, 0, 0 };
+  GdkPixmap *source;
+  GdkPixmap *mask;
+  GdkCursor *cursor;
+
+  /* Yeah, hard-coded sizes are bad. */
+  source = gdk_bitmap_create_from_data (window, data, 20, 20);
+  mask = gdk_bitmap_create_from_data (window, mask_data, 20, 20);
+
+  cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 10, 10);
+
+  g_object_unref (source);
+  g_object_unref (mask);
+
+  return cursor;
+}
+
+#endif /* !HAVE_HILDON */
+
+GdkCursor *ar_cursor_new (GdkWindow *window,
+                          ArCursorType cursor_type)
+{
+#ifndef HAVE_HILDON
+  switch (cursor_type) {
+    case AR_CURSOR_OPEN:
+      return ar_cursor_new_from_data (window, hand_open_data_bits, hand_open_mask_bits);
+
+    case AR_CURSOR_CLOSED:
+      return ar_cursor_new_from_data (window, hand_closed_data_bits, hand_closed_mask_bits);
+
+    default:
+      g_assert_not_reached ();
+  }
+#else
+  return NULL;
+#endif /* !HAVE_HILDON */
+}
diff --git a/aisleriot/ar-cursor.h b/aisleriot/ar-cursor.h
new file mode 100644
index 0000000..f89d278
--- /dev/null
+++ b/aisleriot/ar-cursor.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2009 Christian Persch <chpe gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __AR_CURSOR_H__
+#define __AR_CURSOR_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  AR_CURSOR_DEFAULT,
+  AR_CURSOR_OPEN,
+  AR_CURSOR_CLOSED,
+  AR_CURSOR_DROPPABLE,
+  AR_LAST_CURSOR
+} ArCursorType;
+
+GdkCursor *ar_cursor_new (GdkWindow *window,
+                          ArCursorType cursor_type);
+
+G_END_DECLS
+
+#endif /* __AR_CURSOR_H__ */
diff --git a/aisleriot/ar-style-private.h b/aisleriot/ar-style-private.h
new file mode 100644
index 0000000..e40b51a
--- /dev/null
+++ b/aisleriot/ar-style-private.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2009 Christian Persch <chpe gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __AR_STYLE_PRIVATE_H__
+#define __AR_STYLE_PRIVATE_H__
+
+G_BEGIN_DECLS
+
+static const GdkColor default_selection_color = { 0, 0 /* red */, 0 /* green */, 0xaa00 /* blue */ };
+
+/* The proportion of a slot dedicated to the card (horiz or vert). */
+#ifndef DEFAULT_CARD_SLOT_RATIO
+#ifdef HAVE_HILDON
+#define DEFAULT_CARD_SLOT_RATIO (0.9)
+#else
+#define DEFAULT_CARD_SLOT_RATIO (0.8)
+#endif
+#endif /* !DEFAULT_CARD_SLOT_RATIO */
+
+struct _ArStylePrivate
+{
+  GamesCardTheme* card_theme;
+
+  ClutterColor selection_color;
+
+  double card_slot_ratio;
+
+  int dnd_drag_threshold;
+  int double_click_time;
+  int focus_line_width;
+  int focus_padding;
+
+  guint enable_animations_gtk   : 1;
+  guint enable_animations       : 1;
+  guint enable_sound_gtk        : 1;
+  guint enable_sound            : 1;
+  guint touchscreen_mode        : 1;
+
+  guint rtl                     : 1;
+  guint interior_focus          : 1;
+
+  guint click_to_move           : 1;
+
+  guint keynav_enabled          : 1;
+  guint show_focus              : 1;
+  guint show_highlight          : 1;
+  guint show_seleccion          : 1;
+};
+
+void _ar_clutter_color_from_gdk_color (ClutterColor *clutter_color,
+                                       const GdkColor *gdk_color);
+
+G_END_DECLS
+
+#endif /* __AR_STYLE_PRIVATE_H__ */
diff --git a/aisleriot/ar-style.c b/aisleriot/ar-style.c
new file mode 100644
index 0000000..182304e
--- /dev/null
+++ b/aisleriot/ar-style.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright © 2009 Christian Persch <chpe gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "ar-style.h"
+#include "ar-style-private.h"
+
+enum
+{
+  PROP_0,
+  PROP_CARD_SLOT_RATIO,
+  PROP_CARD_THEME,
+  PROP_CLICK_TO_MOVE,
+  PROP_DND_DRAG_THRESHOLD,
+  PROP_DOUBLE_CLICK_TIME,
+  PROP_ENABLE_ANIMATIONS,
+  PROP_ENABLE_SOUND,
+  PROP_FOCUS_LINE_WIDTH,
+  PROP_FOCUS_PADDING,
+  PROP_INTERIOR_FOCUS,
+  PROP_RTL,
+  PROP_SELECTION_COLOR,
+  PROP_TOUCHSCREEN_MODE,
+};
+
+/* private functions */
+
+/* GObjectClass impl */
+
+G_DEFINE_TYPE (ArStyle, ar_style, G_TYPE_OBJECT)
+
+static void
+ar_style_init (ArStyle *style)
+{
+  ArStylePrivate *priv;
+
+  priv = style->priv = G_TYPE_INSTANCE_GET_PRIVATE (style, AR_TYPE_STYLE, ArStylePrivate);
+
+  _ar_clutter_color_from_gdk_color (&priv->selection_color, &default_selection_color);
+  priv->card_slot_ratio = DEFAULT_CARD_SLOT_RATIO;
+  priv->dnd_drag_threshold = 8;
+  priv->double_click_time = 250;
+  priv->focus_line_width = 1;
+  priv->focus_padding = 1;
+  priv->enable_animations_gtk = FALSE;
+  priv->enable_animations = FALSE;
+  priv->enable_sound_gtk = FALSE;
+  priv->enable_sound = FALSE;
+  priv->touchscreen_mode = FALSE;
+  priv->rtl = FALSE;
+  priv->interior_focus = FALSE;
+  priv->click_to_move = FALSE;
+}
+
+static void
+ar_style_finalize (GObject *object)
+{
+  ArStyle *style = AR_STYLE (object);
+  ArStylePrivate *priv = style->priv;
+
+  if (priv->card_theme) {
+    g_object_unref (priv->card_theme);
+  }
+
+  G_OBJECT_CLASS (ar_style_parent_class)->finalize (object);
+}
+
+static void
+ar_style_get_property (GObject    *object,
+                       guint       property_id,
+                       GValue     *value,
+                       GParamSpec *pspec)
+{
+  ArStyle *style = AR_STYLE (object);
+  ArStylePrivate *priv = style->priv;
+
+  switch (property_id) {
+    case PROP_CARD_SLOT_RATIO:
+      g_value_set_double (value, ar_style_get_card_slot_ratio (style));
+      break;
+
+    case PROP_CARD_THEME:
+      g_value_set_object (value, ar_style_get_card_theme (style));
+      break;
+
+    case PROP_CLICK_TO_MOVE:
+      g_value_set_boolean (value, ar_style_get_click_to_move (style));
+      break;
+
+    case PROP_DND_DRAG_THRESHOLD:
+      g_value_set_int (value, priv->dnd_drag_threshold);
+      break;
+
+    case PROP_DOUBLE_CLICK_TIME:
+      g_value_set_int (value, ar_style_get_double_click_time (style));
+      break;
+
+    case PROP_ENABLE_ANIMATIONS:
+      g_value_set_boolean (value, ar_style_get_enable_animations (style));
+      break;
+
+    case PROP_ENABLE_SOUND:
+      g_value_set_boolean (value, ar_style_get_enable_sound (style));
+      break;
+
+    case PROP_FOCUS_LINE_WIDTH:
+      g_value_set_int (value, ar_style_get_focus_line_width (style));
+      break;
+
+    case PROP_FOCUS_PADDING:
+      g_value_set_int (value, ar_style_get_focus_padding (style));
+      break;
+
+    case PROP_INTERIOR_FOCUS:
+      g_value_set_boolean (value, ar_style_get_interior_focus (style));
+      break;
+
+    case PROP_RTL:
+      g_value_set_boolean (value, ar_style_get_rtl (style));
+      break;
+
+    case PROP_SELECTION_COLOR:
+      g_value_set_boxed (value, &priv->selection_color);
+      break;
+
+    case PROP_TOUCHSCREEN_MODE:
+      g_value_set_boolean (value, ar_style_get_touchscreen_mode (style));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+ar_style_set_property (GObject      *object,
+                       guint         property_id,
+                       const GValue *value,
+                       GParamSpec   *pspec)
+{
+  ArStyle *style = AR_STYLE (object);
+
+  switch (property_id) {
+    case PROP_CARD_THEME:
+      ar_style_set_card_theme (style, g_value_get_object (value));
+      break;
+
+    case PROP_CLICK_TO_MOVE:
+      ar_style_set_click_to_move (style, g_value_get_boolean (value));
+      break;
+
+    case PROP_ENABLE_ANIMATIONS:
+      ar_style_set_enable_animations (style, g_value_get_boolean (value));
+      break;
+
+    case PROP_ENABLE_SOUND:
+      ar_style_set_enable_sound (style, g_value_get_boolean (value));
+      break;
+
+    case PROP_CARD_SLOT_RATIO:
+    case PROP_DND_DRAG_THRESHOLD:
+    case PROP_DOUBLE_CLICK_TIME:
+    case PROP_FOCUS_LINE_WIDTH:
+    case PROP_FOCUS_PADDING:
+    case PROP_INTERIOR_FOCUS:
+    case PROP_RTL:
+    case PROP_SELECTION_COLOR:
+    case PROP_TOUCHSCREEN_MODE:
+      /* not writable */
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+ar_style_class_init (ArStyleClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ClutterColor color;
+
+  g_type_class_add_private (klass, sizeof (ArStylePrivate));
+
+  object_class->set_property = ar_style_set_property;
+  object_class->get_property = ar_style_get_property;
+  object_class->finalize     = ar_style_finalize;
+
+  g_object_class_install_property
+    (object_class,
+     PROP_CARD_SLOT_RATIO,
+     g_param_spec_double (AR_STYLE_PROP_CARD_SLOT_RATIO, NULL, NULL,
+                          0.1, 1.0, DEFAULT_CARD_SLOT_RATIO,
+                          G_PARAM_READABLE |
+                          G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_CARD_THEME,
+     g_param_spec_object (AR_STYLE_PROP_CARD_THEME, NULL, NULL,
+                          GAMES_TYPE_CARD_THEME,
+                          G_PARAM_READWRITE |
+                          G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_CLICK_TO_MOVE,
+     g_param_spec_boolean (AR_STYLE_PROP_CLICK_TO_MOVE, NULL, NULL,
+                           FALSE,
+                           G_PARAM_READWRITE |
+                           G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_DND_DRAG_THRESHOLD,
+     g_param_spec_int (AR_STYLE_PROP_DND_DRAG_THRESHOLD, NULL, NULL,
+                       1, G_MAXINT, 8,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_DOUBLE_CLICK_TIME,
+     g_param_spec_int (AR_STYLE_PROP_DOUBLE_CLICK_TIME, NULL, NULL,
+                       0, G_MAXINT, 250,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_ENABLE_ANIMATIONS,
+     g_param_spec_boolean (AR_STYLE_PROP_ENABLE_ANIMATIONS, NULL, NULL,
+                           FALSE,
+                           G_PARAM_READWRITE |
+                           G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_ENABLE_SOUND,
+     g_param_spec_boolean (AR_STYLE_PROP_ENABLE_SOUND, NULL, NULL,
+                           FALSE,
+                           G_PARAM_READWRITE |
+                           G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_FOCUS_LINE_WIDTH,
+     g_param_spec_int (AR_STYLE_PROP_FOCUS_LINE_WIDTH, NULL, NULL,
+                       0, G_MAXINT, 1,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_FOCUS_PADDING,
+     g_param_spec_int (AR_STYLE_PROP_FOCUS_PADDING, NULL, NULL,
+                       0, G_MAXINT, 1,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_INTERIOR_FOCUS,
+     g_param_spec_boolean (AR_STYLE_PROP_INTERIOR_FOCUS, NULL, NULL,
+                           FALSE,
+                           G_PARAM_READABLE |
+                           G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_RTL,
+     g_param_spec_boolean (AR_STYLE_PROP_RTL, NULL, NULL,
+                           FALSE,
+                           G_PARAM_READABLE |
+                           G_PARAM_STATIC_STRINGS));
+
+  _ar_clutter_color_from_gdk_color (&color, &default_selection_color);
+  g_object_class_install_property
+    (object_class,
+     PROP_SELECTION_COLOR,
+     clutter_param_spec_color (AR_STYLE_PROP_SELECTION_COLOR, NULL, NULL,
+                               &color,
+                               G_PARAM_READABLE |
+                               G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property
+    (object_class,
+     PROP_TOUCHSCREEN_MODE,
+     g_param_spec_boolean (AR_STYLE_PROP_TOUCHSCREEN_MODE, NULL, NULL,
+                           FALSE,
+                           G_PARAM_READABLE |
+                           G_PARAM_STATIC_STRINGS));
+}
+
+/* private API */
+
+void
+_ar_clutter_color_from_gdk_color (ClutterColor *clutter_color,
+                                  const GdkColor *gdk_color)
+{
+  clutter_color->red   = gdk_color->red   >> 8;
+  clutter_color->green = gdk_color->green >> 8;
+  clutter_color->blue  = gdk_color->blue  >> 8;
+  clutter_color->alpha = 0xff;
+}
+
+/* public API */
+
+/**
+ * ar_style_new:
+ *
+ * Return value:
+ */
+ArStyle*
+ar_style_new (void)
+{
+  return g_object_new (AR_TYPE_STYLE, NULL);
+}
+
+/**
+ * ar_style_get_enable_animations:
+ * @style: an #ArStyle
+ *
+ * Returns: whether animations are enabled
+ */
+gboolean
+ar_style_get_enable_animations (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->enable_animations && priv->enable_animations_gtk;
+}
+
+/**
+ * ar_style_set_enable_animations:
+ * @style: an #ArStyle
+ * @enable: whether to enable animations
+ *
+ * Note that animations are only used when this the
+ * global gtk-enable-animations setting is enabled as well.
+ */
+void
+ar_style_set_enable_animations (ArStyle *style,
+                                gboolean enable)
+{
+  ArStylePrivate *priv = style->priv;
+
+  enable = enable != FALSE;
+  if (priv->enable_animations == enable)
+    return;
+
+  priv->enable_animations = enable;
+  g_object_notify (G_OBJECT (style), AR_STYLE_PROP_ENABLE_ANIMATIONS);
+}
+
+/**
+ * ar_style_get_enable_sound:
+ * @style: an #ArStyle
+ *
+ * Returns: whether sound is enabled
+ */
+gboolean
+ar_style_get_enable_sound (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->enable_sound && priv->enable_sound_gtk;
+}
+
+/**
+ * ar_style_set_enable_sound:
+ * @style: an #ArStyle
+ * @enable: whether to enable sound
+ *
+ * Note that sound is only used when this the
+ * global gtk-enable-event-sounds setting is enabled as well.
+ */
+void
+ar_style_set_enable_sound (ArStyle *style,
+                           gboolean enable)
+{
+  ArStylePrivate *priv = style->priv;
+
+  enable = enable != FALSE;
+  if (priv->enable_sound == enable)
+    return;
+
+  priv->enable_sound = enable;
+  g_object_notify (G_OBJECT (style), AR_STYLE_PROP_ENABLE_SOUND);
+}
+
+/**
+ * ar_style_get_click_to_move:
+ * @style: an #ArStyle
+ *
+ * Returns: whether sound is enabled
+ */
+gboolean
+ar_style_get_click_to_move (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->click_to_move;
+}
+
+/**
+ * ar_style_set_click_to_move:
+ * @style: an #ArStyle
+ * @enable: whether to enable sound
+ *
+ * Note that sound is only used when this the
+ * global gtk-enable-event-sounds setting is enabled as well.
+ */
+void
+ar_style_set_click_to_move (ArStyle *style,
+                           gboolean enable)
+{
+  ArStylePrivate *priv = style->priv;
+
+  enable = enable != FALSE;
+  if (priv->click_to_move == enable)
+    return;
+
+  priv->click_to_move = enable;
+  g_object_notify (G_OBJECT (style), AR_STYLE_PROP_CLICK_TO_MOVE);
+}
+
+/**
+ * ar_style_get_card_theme:
+ * @style: an #ArStyle
+ *
+ * Returns: @style's #GamesCardTheme
+ */
+GamesCardTheme *
+ar_style_get_card_theme (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->card_theme;
+}
+
+/**
+ * ar_style_set_card_theme:
+ * @style: an #ArStyle
+ * @card_theme: a #GamesCardTheme
+ *
+ * Note that animations are only used when this the
+ * global gtk-enable-animations setting is enabled as well.
+ */
+void
+ar_style_set_card_theme (ArStyle *style,
+                         GamesCardTheme *theme)
+{
+  ArStylePrivate *priv = style->priv;
+
+  if (priv->card_theme == theme)
+    return;
+
+  if (priv->card_theme != NULL) {
+    g_object_unref (priv->card_theme);
+  }
+  priv->card_theme = g_object_ref (theme);
+
+  g_object_notify (G_OBJECT (style), AR_STYLE_PROP_CARD_THEME);
+}
+
+/**
+ * ar_style_get_touchscreen_mode:
+ * @style: an #ArStyle
+ *
+ * Returns: whether sound is enabled
+ */
+gboolean
+ar_style_get_touchscreen_mode (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->touchscreen_mode;
+}
+
+/**
+ * ar_style_get_interior_focus:
+ * @style: an #ArStyle
+ *
+ * Returns:
+ */
+gboolean
+ar_style_get_interior_focus (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->interior_focus;
+}
+
+
+/**
+ * ar_style_get_rtl:
+ * @style: an #ArStyle
+ *
+ * Returns:
+ */
+gboolean
+ar_style_get_rtl (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->rtl;
+}
+
+/**
+ * ar_style_get_double_click_time:
+ * @style: an #ArStyle
+ *
+ * Returns: the double click time
+ */
+int
+ar_style_get_double_click_time (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->double_click_time;
+}
+
+/**
+ * ar_style_get_focus_line_width:
+ * @style: an #ArStyle
+ *
+ * Returns:
+ */
+int
+ar_style_get_focus_line_width (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->focus_line_width;
+}
+
+/**
+ * ar_style_get_focus_padding:
+ * @style: an #ArStyle
+ *
+ * Returns:
+ */
+int ar_style_get_focus_padding (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->focus_padding;
+}
+
+/**
+ * ar_style_get_card_slot_ratio:
+ * @style: an #ArStyle
+ *
+ * Returns:
+ */
+double
+ar_style_get_card_slot_ratio (ArStyle *style)
+{
+  ArStylePrivate *priv = style->priv;
+
+  return priv->card_slot_ratio;
+}
+
+/**
+ * ar_style_get_selection_color:
+ * @style: an #ArStyle
+ * @color: location to store the color
+ *
+ */
+void
+ar_style_get_selection_color (ArStyle *style,
+                              ClutterColor * const color)
+{
+  ArStylePrivate *priv = style->priv;
+
+  *color = priv->selection_color;
+}
+
+/**
+ * ar_style_check_dnd_drag_threshold:
+ * @style:
+ * @x1:
+ * @y1:
+ * @x2:
+ * @y2:
+ *
+ * Checks whether the distance between (x1, y1) and (x2, y2) is
+ * greater than the drag threshold.
+ *
+ * Returns: %TRUE if the distance between the points is greater
+ *   than the drag threshold
+ */
+gboolean
+ar_style_check_dnd_drag_threshold (ArStyle *style,
+                                   float x1,
+                                   float y1,
+                                   float x2,
+                                   float y2)
+{
+  ArStylePrivate *priv = style->priv;
+
+  /* FIXMEchpe: are these coordinates pixels, or something else? */
+  /* FIXMEchpe: shouldn't this be (x2 - x1)**2 + (y2 - y1)**2 >= threshold**2 ? */
+  return (ABS (x2 - x1) > priv->dnd_drag_threshold ||
+          ABS (y2 - y1) > priv->dnd_drag_threshold);
+}
diff --git a/aisleriot/ar-style.h b/aisleriot/ar-style.h
new file mode 100644
index 0000000..d1505af
--- /dev/null
+++ b/aisleriot/ar-style.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2009 Christian Persch <chpe gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __AR_STYLE_H__
+#define __AR_STYLE_H__
+
+#include <glib-object.h>
+
+#include <clutter/clutter.h>
+
+#include <libgames-support/games-card-theme.h>
+
+G_BEGIN_DECLS
+
+#define AR_TYPE_STYLE            (ar_style_get_type())
+#define AR_STYLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), AR_TYPE_STYLE, ArStyle))
+#define AR_STYLE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  AR_TYPE_STYLE, ArStyleClass))
+#define AR_IS_STYLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AR_TYPE_STYLE))
+#define AR_IS_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  AR_TYPE_STYLE))
+#define AR_STYLE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  AR_TYPE_STYLE, ArStyleClass))
+
+typedef struct _ArStyle        ArStyle;
+typedef struct _ArStyleClass   ArStyleClass;
+typedef struct _ArStylePrivate ArStylePrivate;
+
+struct _ArStyle
+{
+  GObject parent;
+
+  /*< private >*/
+  ArStylePrivate *priv;
+};
+
+struct _ArStyleClass
+{
+  GObjectClass parent_class;
+};
+
+GType ar_style_get_type (void);
+
+ArStyle* ar_style_new (void);
+
+#define AR_STYLE_PROP_CARD_SLOT_RATIO     "card-slot-prop"
+#define AR_STYLE_PROP_CARD_THEME          "card-theme"
+#define AR_STYLE_PROP_CLICK_TO_MOVE       "click-to-move"
+#define AR_STYLE_PROP_DND_DRAG_THRESHOLD  "dnd-drag-threshold"
+#define AR_STYLE_PROP_DOUBLE_CLICK_TIME   "double-click-time"
+#define AR_STYLE_PROP_ENABLE_ANIMATIONS   "enable-animations"
+#define AR_STYLE_PROP_ENABLE_SOUND        "enable-sound"
+#define AR_STYLE_PROP_FOCUS_LINE_WIDTH    "focus-line-width"
+#define AR_STYLE_PROP_FOCUS_PADDING       "focus-padding"
+#define AR_STYLE_PROP_INTERIOR_FOCUS      "interior-focus"
+#define AR_STYLE_PROP_RTL                 "rtl"
+#define AR_STYLE_PROP_SELECTION_COLOR     "selection-color"
+#define AR_STYLE_PROP_TOUCHSCREEN_MODE    "touchscreen-mode"
+
+gboolean ar_style_get_enable_animations (ArStyle *style);
+void     ar_style_set_enable_animations (ArStyle *style,
+                                         gboolean enable);
+
+gboolean ar_style_get_enable_sound (ArStyle *style);
+void     ar_style_set_enable_sound (ArStyle *style,
+                                    gboolean enable);
+
+gboolean ar_style_get_click_to_move (ArStyle *style);
+void     ar_style_set_click_to_move (ArStyle *style,
+                                     gboolean enable);
+
+GamesCardTheme *ar_style_get_card_theme (ArStyle *style);
+void            ar_style_set_card_theme (ArStyle *style,
+                                         GamesCardTheme *theme);
+
+/* Read-only properties */
+gboolean ar_style_get_touchscreen_mode (ArStyle *style);
+gboolean ar_style_get_interior_focus   (ArStyle *style);
+gboolean ar_style_get_rtl              (ArStyle *style);
+
+int ar_style_get_double_click_time  (ArStyle *style);
+int ar_style_get_focus_line_width   (ArStyle *style);
+int ar_style_get_focus_padding      (ArStyle *style);
+
+double ar_style_get_card_slot_ratio (ArStyle *style);
+
+void ar_style_get_selection_color  (ArStyle *style,
+                                    ClutterColor * const color);
+
+gboolean ar_style_check_dnd_drag_threshold (ArStyle *style,
+                                            float x1,
+                                            float y1,
+                                            float x2,
+                                            float y2);
+
+G_END_DECLS
+
+#endif /* __AR_STYLE_H__ */
diff --git a/aisleriot/baize.c b/aisleriot/baize.c
index 51ec6fa..f298977 100644
--- a/aisleriot/baize.c
+++ b/aisleriot/baize.c
@@ -17,16 +17,55 @@
 
 #include <config.h>
 
-#include <clutter/clutter.h>
+#include "baize.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
 #include <cogl/cogl.h>
 
-#include "baize.h"
+#include <libgames-support/games-runtime.h>
 
 /* Special version of ClutterTexture that repeats the texture to fill
    the entire stage. This is used to paint the baize background */
 
 static void aisleriot_baize_paint (ClutterActor *actor);
 
+static void
+load_background (AisleriotBaize *baize)
+{
+  GError *error = NULL;
+  GdkPixbuf *pixbuf;
+  char *path;
+
+  path = games_runtime_get_file (GAMES_RUNTIME_PIXMAP_DIRECTORY, "baize.png");
+
+  pixbuf = gdk_pixbuf_new_from_file (path, &error);
+  g_free (path);
+  if (error) {
+    g_warning ("Failed to load the baize pixbuf: %s\n", error->message);
+    g_error_free (error);
+    return;
+  }
+
+  g_assert (pixbuf != NULL);
+
+  clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (baize),
+                                     gdk_pixbuf_get_pixels (pixbuf),
+                                     gdk_pixbuf_get_has_alpha (pixbuf),
+                                     gdk_pixbuf_get_width (pixbuf),
+                                     gdk_pixbuf_get_height (pixbuf),
+                                     gdk_pixbuf_get_rowstride (pixbuf),
+                                     gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3,
+                                     0,
+                                     &error);
+  if (error) {
+    g_warning ("Failed to set texture from pixbuf: %s", error->message);
+    g_error_free (error);
+  }
+
+  g_object_unref (pixbuf);
+}
+
 G_DEFINE_TYPE (AisleriotBaize, aisleriot_baize, CLUTTER_TYPE_TEXTURE);
 
 static void
@@ -38,16 +77,15 @@ aisleriot_baize_class_init (AisleriotBaizeClass *klass)
 }
 
 static void
-aisleriot_baize_init (AisleriotBaize *self)
+aisleriot_baize_init (AisleriotBaize *baize)
 {
+  load_background (baize);
 }
 
 ClutterActor *
 aisleriot_baize_new (void)
 {
-  ClutterActor *self = g_object_new (AISLERIOT_TYPE_BAIZE, NULL);
-
-  return self;
+  return g_object_new (AISLERIOT_TYPE_BAIZE, NULL);
 }
 
 static void
diff --git a/aisleriot/board-noclutter.c b/aisleriot/board-noclutter.c
index 3c2f586..b83c11b 100644
--- a/aisleriot/board-noclutter.c
+++ b/aisleriot/board-noclutter.c
@@ -38,7 +38,7 @@
 
 #include "game.h"
 
-#include "board.h"
+#include "board-noclutter.h"
 
 #define AISLERIOT_BOARD_GET_PRIVATE(board)(G_TYPE_INSTANCE_GET_PRIVATE ((board), AISLERIOT_TYPE_BOARD, AisleriotBoardPrivate))
 
@@ -135,7 +135,7 @@ struct _AisleriotBoardPrivate
   /* Cards cache */
   GamesCardImages *images;
 
-  /* Slot */
+  /* ArSlot */
   gpointer slot_image; /* either a GdkPixbuf or GdkPixmap, depending on drawing mode */
 
   /* Button press */
@@ -145,38 +145,38 @@ struct _AisleriotBoardPrivate
   guint32 last_click_time;
 
   /* Moving cards */
-  Slot *moving_cards_origin_slot;
+  ArSlot *moving_cards_origin_slot;
   int moving_cards_origin_card_id; /* The index of the card that was clicked on in hslot->cards; or -1 if the click wasn't on a card */
   GdkWindow *moving_cards_window;
   GByteArray *moving_cards;
 
   /* The 'reveal card' action's slot and card link */
-  Slot *show_card_slot;
+  ArSlot *show_card_slot;
   int show_card_id;
 
   /* Click data */
-  Slot *last_clicked_slot;
+  ArSlot *last_clicked_slot;
   int last_clicked_card_id;
 
   /* Focus handling */
-  Slot *focus_slot;
+  ArSlot *focus_slot;
   int focus_card_id; /* -1 for focused empty slot */
   int focus_line_width;
   int focus_padding;
   GdkRectangle focus_rect;
 
   /* Selection */
-  Slot *selection_slot;
+  ArSlot *selection_slot;
   int selection_start_card_id;
   GdkRectangle selection_rect;
   GdkColor selection_colour;
 
   /* Highlight */
-  Slot *highlight_slot;
+  ArSlot *highlight_slot;
 
 #ifdef HAVE_MAEMO
   /* Tap-and-Hold */
-  Slot *tap_and_hold_slot;
+  ArSlot *tap_and_hold_slot;
   int tap_and_hold_card_id;
 #endif
 
@@ -227,12 +227,12 @@ static guint signals[LAST_SIGNAL];
 static void get_slot_and_card_from_point (AisleriotBoard *board,
                                           int x,
                                           int y,
-                                          Slot **slot,
+                                          ArSlot **slot,
                                           int *_cardid);
 static void slot_update_card_images      (AisleriotBoard *board,
-                                          Slot *slot);
+                                          ArSlot *slot);
 static void slot_update_card_images_full (AisleriotBoard *board,
-                                          Slot *slot,
+                                          ArSlot *slot,
                                           int highlight_start_card_id);
 
 #ifndef HAVE_HILDON 
@@ -334,9 +334,9 @@ set_cursor_by_location (AisleriotBoard *board,
 {
 #ifndef HAVE_HILDON 
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *selection_slot = priv->selection_slot;
+  ArSlot *selection_slot = priv->selection_slot;
   int selection_start_card_id = priv->selection_start_card_id;
-  Slot *slot;
+  ArSlot *slot;
   int card_id;
   gboolean drop_valid = FALSE;
   CursorType cursor = CURSOR_DEFAULT;
@@ -426,7 +426,7 @@ static void
 get_slot_and_card_from_point (AisleriotBoard *board,
                               int x,
                               int y,
-                              Slot **slot,
+                              ArSlot **slot,
                               int *_cardid)
 {
   AisleriotBoardPrivate *priv = board->priv;
@@ -443,7 +443,7 @@ get_slot_and_card_from_point (AisleriotBoard *board,
 
   n_slots = slots->len;
   for (i = n_slots - 1; i >= 0; --i) {
-    Slot *hslot = slots->pdata[i];
+    ArSlot *hslot = slots->pdata[i];
 
     /* if point is within our rectangle */
     if (hslot->rect.x <= x && x <= hslot->rect.x + hslot->rect.width &&
@@ -490,7 +490,7 @@ get_slot_and_card_from_point (AisleriotBoard *board,
 #ifdef ENABLE_KEYNAV
 
 static gboolean
-test_slot_projection_intersects_x (Slot *slot,
+test_slot_projection_intersects_x (ArSlot *slot,
                                    int x_start,
                                    int x_end)
 {
@@ -500,7 +500,7 @@ test_slot_projection_intersects_x (Slot *slot,
 
 static int
 get_slot_index_from_slot (AisleriotBoard *board,
-                          Slot *slot)
+                          ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
   GPtrArray *slots;
@@ -527,7 +527,7 @@ get_slot_index_from_slot (AisleriotBoard *board,
 
 static void
 get_rect_by_slot_and_card (AisleriotBoard *board,
-                           Slot *slot,
+                           ArSlot *slot,
                            int card_id,
                            int num_cards,
                            GdkRectangle *rect)
@@ -597,7 +597,7 @@ get_focus_rect (AisleriotBoard *board,
 
 static void
 set_focus (AisleriotBoard *board,
-           Slot *slot,
+           ArSlot *slot,
            int card_id,
            gboolean show_focus)
 {
@@ -666,7 +666,7 @@ get_selection_rect (AisleriotBoard *board,
 
 static void
 set_selection (AisleriotBoard *board,
-               Slot *slot,
+               ArSlot *slot,
                int card_id,
                gboolean show_selection)
 {
@@ -715,7 +715,7 @@ set_selection (AisleriotBoard *board,
 
 static void
 slot_update_geometry (AisleriotBoard *board,
-                      Slot *slot)
+                      ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
   GtkWidget *widget = GTK_WIDGET (board);
@@ -835,7 +835,7 @@ slot_update_geometry (AisleriotBoard *board,
 
 static void
 slot_update_card_images_full (AisleriotBoard *board,
-                              Slot *slot,
+                              ArSlot *slot,
                               int highlight_start_card_id)
 {
   AisleriotBoardPrivate *priv = board->priv;
@@ -888,7 +888,7 @@ slot_update_card_images_full (AisleriotBoard *board,
 
 static void
 slot_update_card_images (AisleriotBoard *board,
-                         Slot *slot)
+                         ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
   int highlight_start_card_id = G_MAXINT;
@@ -980,7 +980,7 @@ aisleriot_board_setup_geometry (AisleriotBoard *board)
 
   n_slots = slots->len;
   for (i = 0; i < n_slots; ++i) {
-    Slot *slot = slots->pdata[i];
+    ArSlot *slot = slots->pdata[i];
 
     slot_update_geometry (board, slot);
     slot_update_card_images (board, slot);
@@ -996,7 +996,7 @@ drag_begin (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
   GtkWidget *widget = GTK_WIDGET (board);
-  Slot *hslot;
+  ArSlot *hslot;
   int delta, height, width;
   int x, y;
   GdkPixmap *moving_pixmap;
@@ -1193,7 +1193,7 @@ drag_end (AisleriotBoard *board,
 
 static gboolean
 cards_are_droppable (AisleriotBoard *board,
-                     Slot *slot)
+                     ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
 
@@ -1206,14 +1206,14 @@ cards_are_droppable (AisleriotBoard *board,
                                     priv->moving_cards->len);
 }
 
-static Slot *
+static ArSlot *
 find_drop_target (AisleriotBoard *board,
                   gint x,
                   gint y)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *new_hslot;
-  Slot *retval = NULL;
+  ArSlot *new_hslot;
+  ArSlot *retval = NULL;
   gint i, new_cardid;
   gint min_distance = G_MAXINT;
 
@@ -1261,7 +1261,7 @@ drop_moving_cards (AisleriotBoard *board,
                    gint y)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *hslot;
+  ArSlot *hslot;
   gboolean moved = FALSE;
 
   hslot = find_drop_target (board,
@@ -1292,7 +1292,7 @@ drop_moving_cards (AisleriotBoard *board,
 
 static void
 highlight_drop_target (AisleriotBoard *board,
-                       Slot *slot)
+                       ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
   GtkWidget *widget = GTK_WIDGET (board);
@@ -1347,7 +1347,7 @@ highlight_drop_target (AisleriotBoard *board,
 
 static void
 reveal_card (AisleriotBoard *board,
-             Slot *slot,
+             ArSlot *slot,
              int cardid)
 {
   AisleriotBoardPrivate *priv = board->priv;
@@ -1431,10 +1431,10 @@ aisleriot_board_settings_update (GtkSettings *settings,
 /* Note: this unsets the selection! hslot may be equal to priv->selection_slot. */
 static gboolean
 aisleriot_board_move_selected_cards_to_slot (AisleriotBoard *board,
-                                             Slot *hslot)
+                                             ArSlot *hslot)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *selection_slot = priv->selection_slot;
+  ArSlot *selection_slot = priv->selection_slot;
   int selection_start_card_id = priv->selection_start_card_id;
   gboolean moved;
   guint8 *cards;
@@ -1620,7 +1620,7 @@ aisleriot_board_move_cursor_in_slot (AisleriotBoard *board,
                                      int count)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot;
+  ArSlot *focus_slot;
   int new_focus_card_id, first_card_id;
 
   focus_slot = priv->focus_slot;
@@ -1638,7 +1638,7 @@ aisleriot_board_move_cursor_start_end_in_slot (AisleriotBoard *board,
                                                int count)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot = priv->focus_slot;
+  ArSlot *focus_slot = priv->focus_slot;
   int first_card_id, top_card_id, new_focus_card_id;
   guint8 *cards;
 
@@ -1695,7 +1695,7 @@ aisleriot_board_extend_selection_in_slot (AisleriotBoard *board,
                                           int count)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot, *selection_slot;
+  ArSlot *focus_slot, *selection_slot;
   int new_selection_start_card_id, first_card_id;
 
   focus_slot = priv->focus_slot;
@@ -1744,7 +1744,7 @@ static gboolean
 aisleriot_board_extend_selection_in_slot_maximal (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot = priv->focus_slot;
+  ArSlot *focus_slot = priv->focus_slot;
   int new_selection_start_card_id, n_selected;
 
   n_selected = 0;
@@ -1776,7 +1776,7 @@ aisleriot_board_move_cursor_left_right_by_slot (AisleriotBoard *board,
   GtkWidget *widget = GTK_WIDGET (board);
   GPtrArray *slots;
   guint n_slots;
-  Slot *focus_slot, *new_focus_slot;
+  ArSlot *focus_slot, *new_focus_slot;
   int focus_slot_index, new_focus_slot_index;
   int new_focus_slot_topmost_card_id, new_focus_card_id;
   gboolean is_rtl;
@@ -1860,7 +1860,7 @@ aisleriot_board_move_cursor_up_down_by_slot (AisleriotBoard *board,
   AisleriotBoardPrivate *priv = board->priv;
   GPtrArray *slots;
   guint n_slots;
-  Slot *focus_slot, *new_focus_slot;
+  ArSlot *focus_slot, *new_focus_slot;
   int focus_slot_index, new_focus_slot_index;
   int new_focus_slot_topmost_card_id, new_focus_card_id;
   int x_start, x_end;
@@ -1945,7 +1945,7 @@ aisleriot_board_move_cursor_start_end_by_slot (AisleriotBoard *board,
 {
   AisleriotBoardPrivate *priv = board->priv;
   GPtrArray *slots;
-  Slot *new_focus_slot;
+  ArSlot *new_focus_slot;
   int new_focus_card_id;
 
   slots = aisleriot_game_get_slots (priv->game);
@@ -1953,10 +1953,10 @@ aisleriot_board_move_cursor_start_end_by_slot (AisleriotBoard *board,
     return FALSE;
 
   if (count > 0) {
-    new_focus_slot = (Slot *) slots->pdata[slots->len - 1];
+    new_focus_slot = (ArSlot *) slots->pdata[slots->len - 1];
     new_focus_card_id = ((int) new_focus_slot->cards->len) - 1;
   } else {
-    new_focus_slot = (Slot *) slots->pdata[0];
+    new_focus_slot = (ArSlot *) slots->pdata[0];
     if (new_focus_slot->cards->len > 0) {
       new_focus_card_id = ((int) new_focus_slot->cards->len) - ((int) new_focus_slot->exposed);
     } else {
@@ -2044,7 +2044,7 @@ aisleriot_board_extend_selection_start_end (AisleriotBoard *board,
                                             int count)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot = priv->focus_slot;
+  ArSlot *focus_slot = priv->focus_slot;
   int new_focus_card_id;
 
   if (count > 0) {
@@ -2135,7 +2135,7 @@ game_new_cb (AisleriotGame *game,
 
 static void
 slot_changed_cb (AisleriotGame *game,
-                 Slot *slot,
+                 ArSlot *slot,
                  AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
@@ -2191,8 +2191,8 @@ aisleriot_board_activate (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
   GtkWidget *widget = GTK_WIDGET (board);
-  Slot *focus_slot = priv->focus_slot;
-  Slot *selection_slot = priv->selection_slot;
+  ArSlot *focus_slot = priv->focus_slot;
+  ArSlot *selection_slot = priv->selection_slot;
   int selection_start_card_id = priv->selection_start_card_id;
   guint state = 0;
 
@@ -2358,7 +2358,7 @@ static void
 aisleriot_board_select_all (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot = priv->focus_slot;
+  ArSlot *focus_slot = priv->focus_slot;
 
   if (!focus_slot ||
       focus_slot->cards->len == 0 ||
@@ -2378,7 +2378,7 @@ static void
 aisleriot_board_toggle_selection (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot;
+  ArSlot *focus_slot;
   int focus_card_id;
 
   focus_slot = priv->focus_slot;
@@ -2562,7 +2562,7 @@ aisleriot_board_style_set (GtkWidget *widget,
     priv->selection_colour = *colour;
     gdk_color_free (colour);
   } else {
-    const GdkColor default_colour = { 0, 0 /* red */, 0 /* green */, 0xaa00 /* blue */};
+    static const GdkColor default_colour = { 0, 0 /* red */, 0 /* green */, 0xaa00 /* blue */};
 
     priv->selection_colour = default_colour;
   }
@@ -2717,7 +2717,7 @@ aisleriot_board_button_press (GtkWidget *widget,
 {
   AisleriotBoard *board = AISLERIOT_BOARD (widget);
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *hslot;
+  ArSlot *hslot;
   int cardid;
   guint button;
   gboolean drag_valid;
@@ -2793,7 +2793,7 @@ aisleriot_board_button_press (GtkWidget *widget,
    * different cards and a double-click on one card.
    */
   if (is_double_click) {
-    Slot *clicked_slot = hslot;
+    ArSlot *clicked_slot = hslot;
 
     priv->click_status = STATUS_NONE;
 
@@ -2925,7 +2925,7 @@ aisleriot_board_button_release (GtkWidget *widget,
 
     case STATUS_MAYBE_DRAG:
     case STATUS_NOT_DRAG: {
-      Slot *slot;
+      ArSlot *slot;
       int card_id;
 
       /* Don't do the action if the mouse moved away from the clicked slot; see bug #329183 */
@@ -2969,7 +2969,7 @@ aisleriot_board_motion_notify (GtkWidget *widget,
    */
 
   if (priv->click_status == STATUS_IS_DRAG) {
-    Slot *slot;
+    ArSlot *slot;
     int x, y;
 
     x = event->x - priv->last_click_x;
@@ -3014,7 +3014,7 @@ aisleriot_board_tap_and_hold_query_cb (GtkWidget *widget,
   AisleriotBoardPrivate *priv = board->priv;
   /* BadDocs! should mention that this is a GdkEventButton! */
   GdkEventButton *event = (GdkEventButton *) _event;
-  Slot *slot;
+  ArSlot *slot;
   int card_id;
 
   /* NOTE: Returning TRUE from this function means that tap-and-hold
@@ -3064,8 +3064,8 @@ aisleriot_board_expose_event (GtkWidget *widget,
   int i, n_rects;
   GPtrArray *slots;
   guint n_slots;
-  Slot **exposed_slots;
-  Slot *highlight_slot;
+  ArSlot **exposed_slots;
+  ArSlot *highlight_slot;
   guint n_exposed_slots;
   gboolean use_pixbuf_drawing = priv->use_pixbuf_drawing;
   GdkWindow *window;
@@ -3117,11 +3117,11 @@ aisleriot_board_expose_event (GtkWidget *widget,
 
   /* First check which slots are exposed */
   /* It's fine to allocate on the stack, since there'll never be very many slots */
-  exposed_slots = g_newa (Slot*, n_slots);
+  exposed_slots = g_newa (ArSlot *, n_slots);
   n_exposed_slots = 0;
 
   for (i = 0; i < n_slots; ++i) {
-    Slot *slot = slots->pdata[i];
+    ArSlot *slot = slots->pdata[i];
 
     /* Check whether this slot needs to be drawn */
     if (gdk_region_rect_in (region, &slot->rect) == GDK_OVERLAP_RECTANGLE_OUT)
@@ -3136,7 +3136,7 @@ aisleriot_board_expose_event (GtkWidget *widget,
    * (e.g. in Elevator, after a card was removed).
    */
   for (i = 0; i < n_exposed_slots; ++i) {
-    Slot *hslot = exposed_slots[i];
+    ArSlot *hslot = exposed_slots[i];
     int x, y;
 
     /* FIXMEchpe: if ((hslot->length - hslot->exposed) >= 0) ?? */
@@ -3185,7 +3185,7 @@ aisleriot_board_expose_event (GtkWidget *widget,
 
   /* Now draw the cards */
   for (i = 0; i < n_exposed_slots; ++i) {
-    Slot *hslot = exposed_slots[i];
+    ArSlot *hslot = exposed_slots[i];
     GByteArray *cards = hslot->cards;
     gpointer *card_images = hslot->card_images->pdata;
     GdkRectangle card_rect;
diff --git a/aisleriot/board-noclutter.h b/aisleriot/board-noclutter.h
new file mode 100644
index 0000000..21691b3
--- /dev/null
+++ b/aisleriot/board-noclutter.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 1998, 2003 Jonathan Blandford <jrb mit edu>
+ * Copyright © 2007 Christian Persch
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AISLERIOT_BOARD_H
+#define AISLERIOT_BOARD_H
+
+#include <gtk/gtk.h>
+
+#include <libgames-support/games-card-theme.h>
+
+#include "game.h"
+
+G_BEGIN_DECLS
+
+#define AISLERIOT_TYPE_BOARD		(aisleriot_board_get_type ())
+#define AISLERIOT_BOARD(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), AISLERIOT_TYPE_BOARD, AisleriotBoard))
+#define AISLERIOT_BOARD_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), AISLERIOT_TYPE_BOARD, AisleriotBoardClass))
+#define AISLERIOT_IS_BOARD(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), AISLERIOT_TYPE_BOARD))
+#define AISLERIOT_IS_BOARD_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), AISLERIOT_TYPE_BOARD))
+#define AISLERIOT_BOARD_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), AISLERIOT_TYPE_BOARD, AisleriotBoardClass))
+
+typedef struct _AisleriotBoard		AisleriotBoard;
+typedef struct _AisleriotBoardPrivate	AisleriotBoardPrivate;
+typedef struct _AisleriotBoardClass	AisleriotBoardClass;
+
+struct _AisleriotBoard {
+  GtkDrawingArea parent_instance;
+
+  /*< private >*/
+  AisleriotBoardPrivate *priv;
+};
+
+struct _AisleriotBoardClass {
+  GtkDrawingAreaClass parent_class;
+
+  /* keybinding signals */
+  gboolean (* move_cursor)  (AisleriotBoard *board,
+                             GtkMovementStep step,
+                             int count);
+  void (* activate)         (AisleriotBoard *board);
+  void (* toggle_selection) (AisleriotBoard *board);
+  void (* select_all)       (AisleriotBoard *board);
+  void (* deselect_all)     (AisleriotBoard *board);
+};
+
+GType aisleriot_board_get_type (void);
+
+GtkWidget *aisleriot_board_new (AisleriotGame *game);
+
+void aisleriot_board_set_card_theme (AisleriotBoard * board,
+                                     GamesCardTheme *theme);
+
+GamesCardTheme *aisleriot_board_get_card_theme (AisleriotBoard * board);
+
+void aisleriot_board_set_click_to_move (AisleriotBoard * board,
+                                        gboolean click_to_move);
+
+void aisleriot_board_set_animation_mode (AisleriotBoard *board,
+                                         gboolean enable);
+
+void aisleriot_board_abort_move (AisleriotBoard * board);
+
+void aisleriot_board_set_pixbuf_drawing (AisleriotBoard * board,
+                                         gboolean use_pixbuf_drawing);
+
+G_END_DECLS
+
+#endif /* !AISLERIOT_BOARD_H */
diff --git a/aisleriot/board.c b/aisleriot/board.c
index 24a6c95..46ad3cd 100644
--- a/aisleriot/board.c
+++ b/aisleriot/board.c
@@ -1,6 +1,6 @@
 /*
  * Copyright © 1998, 2003 Jonathan Blandford <jrb mit edu>
- * Copyright © 2007, 2008 Christian Persch
+ * Copyright © 2007, 2008, 2009 Christian Persch
  *
  * Some code copied from gtk+/gtk/gtkiconview (LGPL2+):
  * Copyright © 2002, 2004  Anders Carlsson <andersca gnu org>
@@ -29,19 +29,19 @@
 #include <clutter/clutter.h>
 
 #include <libgames-support/games-card-textures-cache.h>
+#include <libgames-support/games-debug.h>
 #include <libgames-support/games-files.h>
 #include <libgames-support/games-marshal.h>
 #include <libgames-support/games-pixbuf-utils.h>
-#include <libgames-support/games-runtime.h>
 #include <libgames-support/games-sound.h>
 
 #include "conf.h"
 
 #include "game.h"
 #include "board.h"
-#include "baize.h"
 #include "card.h"
 #include "slot-renderer.h"
+#include "ar-cursor.h"
 
 #define AISLERIOT_BOARD_GET_PRIVATE(board)(G_TYPE_INSTANCE_GET_PRIVATE ((board), AISLERIOT_TYPE_BOARD, AisleriotBoardPrivate))
 
@@ -61,40 +61,16 @@
 #define MAX_DELTA (0.2)
 #define MAX_OVERHANG (0.2)
 
-/* The proportion of a slot dedicated to the card (horiz or vert). */
-#ifndef DEFAULT_CARD_SLOT_RATIO
-#ifdef HAVE_HILDON
-#define DEFAULT_CARD_SLOT_RATIO (0.9)
-#else
-#define DEFAULT_CARD_SLOT_RATIO (0.8)
-#endif
-#endif /* !DEFAULT_CARD_SLOT_RATIO */
-
 #define DOUBLE_TO_INT_CEIL(d) ((int) (d + 0.5))
 
 #define STATIC_ASSERT(condition) STATIC_ASSERT_IMPL(condition, __LINE__)
 #define STATIC_ASSERT_IMPL(condition, line) STATIC_ASSERT_IMPL2(condition, line)
 #define STATIC_ASSERT_IMPL2(condition, line) typedef int _static_assert_line_##line[(condition) ? 1 : -1]
 
-#ifdef HAVE_HILDON 
-#define PIXBUF_DRAWING_LIKELIHOOD(cond) G_UNLIKELY (cond)
-#else
-#define PIXBUF_DRAWING_LIKELIHOOD(cond) (cond)
-#endif /* HAVE_HILDON */
-
-#if GLIB_CHECK_VERSION (2, 10, 0)
 #define I_(string) g_intern_static_string (string)
-#else
-#define I_(string) string
-#endif
 
-typedef enum {
-  CURSOR_DEFAULT,
-  CURSOR_OPEN,
-  CURSOR_CLOSED,
-  CURSOR_DROPPABLE,
-  LAST_CURSOR
-} CursorType;
+#pragma GCC poison GtkWidget
+#pragma GCC poison widget
 
 typedef enum {
   STATUS_NONE,
@@ -105,14 +81,33 @@ typedef enum {
   LAST_STATUS
 } MoveStatus;
 
+#ifdef ENABLE_KEYNAV
+
+#define MOVE_CURSOR_LEFT_RIGHT    'h'
+#define MOVE_CURSOR_LEFT_RIGHT_S  "h"
+#define MOVE_CURSOR_UP_DOWN       'v'
+#define MOVE_CURSOR_UP_DOWN_S     "v"
+#define MOVE_CURSOR_PAGES         'p'
+#define MOVE_CURSOR_PAGES_S       "p"
+#define MOVE_CURSOR_START_END     'e'
+#define MOVE_CURSOR_START_END_S   "e"
+
+#define MOVE_LEFT     'l'
+#define MOVE_LEFT_S   "l"
+#define MOVE_RIGHT    'r'
+#define MOVE_RIGHT_S  "r"
+
+#endif /* ENABLE_KEYNAV */
+
 struct _AisleriotBoardPrivate
 {
   AisleriotGame *game;
 
-  GdkCursor *cursor[LAST_CURSOR];
+  ArStyle *style;
+
+  ClutterActorBox allocation;
 
   /* Card theme */
-  GamesCardTheme *theme;
   CardSize card_size;
 
   /* Cards cache */
@@ -137,11 +132,10 @@ struct _AisleriotBoardPrivate
   /* Button press */
   int last_click_x;
   int last_click_y;
-  int double_click_time;
   guint32 last_click_time;
 
   /* Moving cards */
-  Slot *moving_cards_origin_slot;
+  ArSlot *moving_cards_origin_slot;
   int moving_cards_origin_card_id; /* The index of the card that was clicked on in hslot->cards; or -1 if the click wasn't on a card */
   ClutterActor *moving_cards_group;
   GByteArray *moving_cards;
@@ -150,31 +144,26 @@ struct _AisleriotBoardPrivate
   ClutterActor *animation_layer;
 
   /* The 'reveal card' action's slot and card link */
-  Slot *show_card_slot;
+  ArSlot *show_card_slot;
   int show_card_id;
 
   /* Click data */
-  Slot *last_clicked_slot;
+  ArSlot *last_clicked_slot;
   int last_clicked_card_id;
 
   /* Focus handling */
-  Slot *focus_slot;
+  ArSlot *focus_slot;
   int focus_card_id; /* -1 for focused empty slot */
   int focus_line_width;
   int focus_padding;
   GdkRectangle focus_rect;
 
   /* Selection */
-  Slot *selection_slot;
+  ArSlot *selection_slot;
   int selection_start_card_id;
-  GdkRectangle selection_rect;
-  ClutterColor selection_colour;
 
   /* Highlight */
-  Slot *highlight_slot;
-
-  /* Actor used for drawing the baize */
-  ClutterActor *baize_actor;
+  ArSlot *highlight_slot;
 
   /* Array RemovedCards to be dropped in animations */
   GArray *removed_cards;
@@ -183,12 +172,6 @@ struct _AisleriotBoardPrivate
      trigger animations */
   guint check_animations_handler;
 
-#ifdef HAVE_MAEMO
-  /* Tap-and-Hold */
-  Slot *tap_and_hold_slot;
-  int tap_and_hold_card_id;
-#endif
-
   /* Bit field */
   guint droppable_supported : 1;
   guint touchscreen_mode : 1;
@@ -208,9 +191,6 @@ struct _AisleriotBoardPrivate
   guint show_highlight : 1;
 
   guint force_geometry_update : 1;
-
-  guint animation_mode : 1;    /* user setting */
-  guint animations_enabled: 1; /* gtk setting  */
 };
 
 typedef struct _RemovedCard RemovedCard;
@@ -228,119 +208,44 @@ enum
 {
   PROP_0,
   PROP_GAME,
-  PROP_THEME
+  PROP_STYLE
 };
 
-#ifdef ENABLE_KEYNAV
 enum
 {
+  REQUEST_CURSOR,
+  ERROR_BELL,
+  FOCUS,
+#ifdef ENABLE_KEYNAV
   ACTIVATE,
   MOVE_CURSOR,
   TOGGLE_SELECTION,
   SELECT_ALL,
   DESELECT_ALL,
+#endif /* ENABLE_KEYNAV */
   LAST_SIGNAL
 };
 
 static guint signals[LAST_SIGNAL];
-#endif /* ENABLE_KEYNAV */
 
 static void get_slot_and_card_from_point (AisleriotBoard *board,
                                           int x,
                                           int y,
-                                          Slot **slot,
+                                          ArSlot **slot,
                                           int *_cardid);
 static void slot_update_card_images      (AisleriotBoard *board,
-                                          Slot *slot);
+                                          ArSlot *slot);
 static void slot_update_card_images_full (AisleriotBoard *board,
-                                          Slot *slot,
+                                          ArSlot *slot,
                                           gint highlight_start_card_id);
 
-#ifndef HAVE_HILDON 
-
-/* These cursors borrowed from EOG */
-/* FIXMEchpe use themeable cursors here! */
-#define hand_closed_data_width 20
-#define hand_closed_data_height 20
-static const char hand_closed_data_bits[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x3f, 0x00,
-  0x80, 0xff, 0x00, 0x80, 0xff, 0x00, 0xb0, 0xff, 0x00, 0xf0, 0xff, 0x00,
-  0xe0, 0xff, 0x00, 0xe0, 0x7f, 0x00, 0xc0, 0x7f, 0x00, 0x80, 0x3f, 0x00,
-  0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-#define hand_closed_mask_width 20
-#define hand_closed_mask_height 20
-static const char hand_closed_mask_bits[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x80, 0x3f, 0x00, 0xc0, 0xff, 0x00,
-  0xc0, 0xff, 0x01, 0xf0, 0xff, 0x01, 0xf8, 0xff, 0x01, 0xf8, 0xff, 0x01,
-  0xf0, 0xff, 0x01, 0xf0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xc0, 0x7f, 0x00,
-  0x80, 0x7f, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-#define hand_open_data_width 20
-#define hand_open_data_height 20
-static const char hand_open_data_bits[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
-  0x60, 0x36, 0x00, 0x60, 0x36, 0x00, 0xc0, 0x36, 0x01, 0xc0, 0xb6, 0x01,
-  0x80, 0xbf, 0x01, 0x98, 0xff, 0x01, 0xb8, 0xff, 0x00, 0xf0, 0xff, 0x00,
-  0xe0, 0xff, 0x00, 0xe0, 0x7f, 0x00, 0xc0, 0x7f, 0x00, 0x80, 0x3f, 0x00,
-  0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-#define hand_open_mask_width 20
-#define hand_open_mask_height 20
-static const char hand_open_mask_bits[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x3f, 0x00,
-  0xf0, 0x7f, 0x00, 0xf0, 0x7f, 0x01, 0xe0, 0xff, 0x03, 0xe0, 0xff, 0x03,
-  0xd8, 0xff, 0x03, 0xfc, 0xff, 0x03, 0xfc, 0xff, 0x01, 0xf8, 0xff, 0x01,
-  0xf0, 0xff, 0x01, 0xf0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xc0, 0x7f, 0x00,
-  0x80, 0x7f, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-#endif /* !HAVE_HILDON */
-
-/* Cursor */
-
-#ifndef HAVE_HILDON 
-
-static GdkCursor *
-make_cursor (GtkWidget *widget,
-             const char *data,
-             const char *mask_data)
-{
-  const GdkColor fg = { 0, 65535, 65535, 65535 };
-  const GdkColor bg = { 0, 0, 0, 0 };
-  GdkPixmap *source;
-  GdkPixmap *mask;
-  GdkCursor *cursor;
-
-  /* Yeah, hard-coded sizes are bad. */
-  source = gdk_bitmap_create_from_data (widget->window, data, 20, 20);
-  mask = gdk_bitmap_create_from_data (widget->window, mask_data, 20, 20);
-
-  cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 10, 10);
-
-  g_object_unref (source);
-  g_object_unref (mask);
-
-  return cursor;
-}
-
-#endif /* !HAVE_HILDON */
+static void aisleriot_board_setup_geometry (AisleriotBoard *board);
 
 static void
 set_cursor (AisleriotBoard *board,
-            CursorType cursor)
+            ArCursorType cursor)
 {
-#ifndef HAVE_HILDON 
-  AisleriotBoardPrivate *priv = board->priv;
-
-  gdk_window_set_cursor (GTK_WIDGET (board)->window,
-                         priv->cursor[cursor]);
-#endif /* !HAVE_HILDON */
+  g_signal_emit (board, signals[REQUEST_CURSOR], 0, (int) cursor);
 }
 
 /* If we are over a slot, set the cursor to the given cursor,
@@ -352,12 +257,12 @@ set_cursor_by_location (AisleriotBoard *board,
 {
 #ifndef HAVE_HILDON 
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *selection_slot = priv->selection_slot;
+  ArSlot *selection_slot = priv->selection_slot;
   int selection_start_card_id = priv->selection_start_card_id;
-  Slot *slot;
+  ArSlot *slot;
   int card_id;
   gboolean drop_valid = FALSE;
-  CursorType cursor = CURSOR_DEFAULT;
+  ArCursorType cursor = AR_CURSOR_DEFAULT;
 
   get_slot_and_card_from_point (board, x, y, &slot, &card_id);
 
@@ -377,14 +282,14 @@ set_cursor_by_location (AisleriotBoard *board,
   /* FIXMEchpe: special cursor when _drag_ is possible? */
 
   if (drop_valid) {
-    cursor = CURSOR_DROPPABLE;
+    cursor = AR_CURSOR_DROPPABLE;
   } else if (slot != NULL &&
              card_id >= 0 &&
              !CARD_GET_FACE_DOWN (CARD (slot->cards->data[card_id]))) {
     if (priv->click_status == STATUS_NONE) {
-      cursor = CURSOR_OPEN;
+      cursor = AR_CURSOR_OPEN;
     } else {
-      cursor = CURSOR_CLOSED;
+      cursor = AR_CURSOR_CLOSED;
     }
   }
 
@@ -392,62 +297,13 @@ set_cursor_by_location (AisleriotBoard *board,
 #endif /* !HAVE_HILDON */
 }
 
-/* card drawing functions */
-
-static void
-set_background_from_baize (AisleriotBoard *board)
-{
-  AisleriotBoardPrivate *priv = board->priv;
-  GError *error = NULL;
-  GdkPixbuf *pixbuf;
-  char *path;
-
-  path = games_runtime_get_file (GAMES_RUNTIME_PIXMAP_DIRECTORY, "baize.png");
-
-  pixbuf = gdk_pixbuf_new_from_file (path, &error);
-  g_free (path);
-  if (error) {
-    g_warning ("Failed to load the baize pixbuf: %s\n", error->message);
-    g_error_free (error);
-    return;
-  }
-
-  g_assert (pixbuf != NULL);
-
-  if (priv->baize_actor == NULL) {
-    ClutterActor *stage;
-
-    stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (board));
-
-    priv->baize_actor = g_object_ref_sink (aisleriot_baize_new ());
-    clutter_container_add (CLUTTER_CONTAINER (stage),
-                           priv->baize_actor, NULL);
-  }
-
-  clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (priv->baize_actor),
-                                     gdk_pixbuf_get_pixels (pixbuf),
-                                     gdk_pixbuf_get_has_alpha (pixbuf),
-                                     gdk_pixbuf_get_width (pixbuf),
-                                     gdk_pixbuf_get_height (pixbuf),
-                                     gdk_pixbuf_get_rowstride (pixbuf),
-                                     gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3,
-                                     0,
-                                     &error);
-  if (error) {
-    g_warning ("Failed to set texture from pixbuf: %s", error->message);
-    g_error_free (error);
-  }
-
-  g_object_unref (pixbuf);
-}
-
 /* Slot helpers */
 
 static void
 get_slot_and_card_from_point (AisleriotBoard *board,
                               int x,
                               int y,
-                              Slot **slot,
+                              ArSlot **slot,
                               int *_cardid)
 {
   AisleriotBoardPrivate *priv = board->priv;
@@ -464,7 +320,7 @@ get_slot_and_card_from_point (AisleriotBoard *board,
 
   n_slots = slots->len;
   for (i = n_slots - 1; i >= 0; --i) {
-    Slot *hslot = slots->pdata[i];
+    ArSlot *hslot = slots->pdata[i];
 
     /* if point is within our rectangle */
     if (hslot->rect.x <= x && x <= hslot->rect.x + hslot->rect.width &&
@@ -511,7 +367,7 @@ get_slot_and_card_from_point (AisleriotBoard *board,
 #ifdef ENABLE_KEYNAV
 
 static gboolean
-test_slot_projection_intersects_x (Slot *slot,
+test_slot_projection_intersects_x (ArSlot *slot,
                                    int x_start,
                                    int x_end)
 {
@@ -521,7 +377,7 @@ test_slot_projection_intersects_x (Slot *slot,
 
 static int
 get_slot_index_from_slot (AisleriotBoard *board,
-                          Slot *slot)
+                          ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
   GPtrArray *slots;
@@ -548,7 +404,7 @@ get_slot_index_from_slot (AisleriotBoard *board,
 
 static void
 get_rect_by_slot_and_card (AisleriotBoard *board,
-                           Slot *slot,
+                           ArSlot *slot,
                            int card_id,
                            int num_cards,
                            GdkRectangle *rect)
@@ -618,12 +474,12 @@ get_focus_rect (AisleriotBoard *board,
 
 static void
 set_focus (AisleriotBoard *board,
-           Slot *slot,
+           ArSlot *slot,
            int card_id,
            gboolean show_focus)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
+//   GtkWidget *widget = GTK_WIDGET (board);
   int top_card_id;
 
   /* Sanitise */
@@ -636,12 +492,14 @@ set_focus (AisleriotBoard *board,
     return;
 
   if (priv->focus_slot != NULL) {
+#ifdef FIXMEchpe
     if (priv->show_focus &&
         GTK_WIDGET_HAS_FOCUS (widget)) {
       gdk_window_invalidate_rect (widget->window, &priv->focus_rect, FALSE);
     
       priv->show_focus = FALSE;
     }
+#endif
 
     priv->focus_slot = NULL;
     priv->focus_card_id = -1;
@@ -655,41 +513,24 @@ set_focus (AisleriotBoard *board,
   priv->focus_slot = slot;
   priv->focus_card_id = card_id;
 
+#ifdef FIXMEchpe
   if (show_focus &&
       GTK_WIDGET_HAS_FOCUS (widget)) {
     get_focus_rect (board, &priv->focus_rect);
     gdk_window_invalidate_rect (widget->window, &priv->focus_rect, FALSE);
   }
+#endif
 }
 
 /* Selection handling */
 
 static void
-get_selection_rect (AisleriotBoard *board,
-                    GdkRectangle *rect)
-{
-  AisleriotBoardPrivate *priv = board->priv;
-  int n_cards;
-
-  if (!priv->selection_slot)
-    return;
-
-  n_cards = priv->selection_slot->cards->len - priv->selection_start_card_id;
-
-  get_rect_by_slot_and_card (board,
-                             priv->selection_slot,
-                             priv->selection_start_card_id,
-                             n_cards, rect);
-}
-
-static void
 set_selection (AisleriotBoard *board,
-               Slot *slot,
+               ArSlot *slot,
                int card_id,
                gboolean show_selection)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
 
   if (priv->selection_slot == slot &&
       priv->selection_start_card_id == card_id &&
@@ -698,8 +539,6 @@ set_selection (AisleriotBoard *board,
 
   if (priv->selection_slot != NULL) {
     if (priv->show_selection) {
-      gdk_window_invalidate_rect (widget->window, &priv->selection_rect, FALSE);
-
       /* Clear selection card images */
       slot_update_card_images_full (board, priv->selection_slot, G_MAXINT);
     }
@@ -719,9 +558,6 @@ set_selection (AisleriotBoard *board,
   g_assert (card_id < 0 || card_id < slot->cards->len);
 
   if (priv->show_selection) {
-    get_selection_rect (board, &priv->selection_rect);
-    gdk_window_invalidate_rect (widget->window, &priv->selection_rect, FALSE);
-  
     slot_update_card_images_full (board, slot, card_id);
   }
 }
@@ -730,10 +566,10 @@ set_selection (AisleriotBoard *board,
 
 static void
 slot_update_geometry (AisleriotBoard *board,
-                      Slot *slot)
+                      ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
+//   GtkWidget *widget = GTK_WIDGET (board);
   GdkRectangle old_rect;
   GByteArray *cards;
   int delta, xofs, yofs, pixeldx;
@@ -772,12 +608,17 @@ slot_update_geometry (AisleriotBoard *board,
 
     if (slot->expanded_down) {
       double y_from_bottom, max_dy = MAX_DELTA;
+      float allocation_height = priv->allocation.y2 - priv->allocation.y1;
 
       if (slot->dy_set)
         max_dy = slot->expansion.dy;
 
       /* Calculate the compressed_dy that will let us fit within the board */
+#ifdef FIXMEchpe
       y_from_bottom = ((double) (widget->allocation.height - slot->rect.y)) / ((double) priv->card_size.height);
+#else
+      y_from_bottom = ((double) (allocation_height - slot->rect.y)) / ((double) priv->card_size.height);
+#endif
       dy = (y_from_bottom - MAX_OVERHANG) / n_cards;
       dy = CLAMP (dy, MIN_DELTA, max_dy);
     } else if (slot->expanded_right) {
@@ -795,11 +636,16 @@ slot_update_geometry (AisleriotBoard *board,
         pixeldx = -slot->pixeldx;
       } else {
         double x_from_right, max_dx = MAX_DELTA;
+        float allocation_width = priv->allocation.x2 - priv->allocation.x1;
 
         if (slot->dx_set)
           max_dx = slot->expansion.dx;
 
+#ifdef FIXMEchpe
         x_from_right = ((double) (widget->allocation.width - slot->rect.x)) / ((double) priv->card_size.width);
+#else
+        x_from_right = ((double) (allocation_width - slot->rect.x)) / ((double) priv->card_size.width);
+#endif
         dx = (x_from_right - MAX_OVERHANG) / n_cards;
         dx = CLAMP (dx, MIN_DELTA, max_dx);
 
@@ -849,7 +695,7 @@ check_animations_cb (gpointer user_data)
   AisleriotBoardPrivate *priv = board->priv;
   GPtrArray *slots;
   int slot_num, i;
-  Slot *slot;
+  ArSlot *slot;
   GArray *animations = g_array_new (FALSE, FALSE, sizeof (AisleriotAnimStart));
 
   slots = aisleriot_game_get_slots (priv->game);
@@ -987,7 +833,6 @@ check_animations_cb (gpointer user_data)
 
     if (slot->cards->len == 0) {
       clutter_actor_lower_bottom (slot->slot_renderer);
-      clutter_actor_lower_bottom (priv->baize_actor);
     } else {
       clutter_actor_raise_top (slot->slot_renderer);
       ClutterActor *animation_layer = CLUTTER_ACTOR(aisleriot_slot_renderer_get_animation_layer(AISLERIOT_SLOT_RENDERER(slot->slot_renderer)));
@@ -1012,7 +857,7 @@ queue_check_animations (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
 
-  if (!priv->animation_mode || !priv->animations_enabled)
+  if (!ar_style_get_enable_animations (priv->style))
     return;
 
   /* The animations are checked for in an idle handler so that this
@@ -1033,24 +878,18 @@ queue_check_animations (AisleriotBoard *board)
 
 static void
 slot_update_card_images_full (AisleriotBoard *board,
-                              Slot *slot,
+                              ArSlot *slot,
                               gint highlight_start_card_id)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  ClutterActor *stage;
-
-  stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (board));
 
   if (!priv->geometry_set)
     return;
 
   if (slot->slot_renderer == NULL) {
-    slot->slot_renderer = aisleriot_slot_renderer_new (priv->textures, slot);
+    slot->slot_renderer = aisleriot_slot_renderer_new (priv->style, priv->textures, slot);
     g_object_ref_sink (slot->slot_renderer);
 
-    aisleriot_slot_renderer_set_highlight_color (AISLERIOT_SLOT_RENDERER (slot->slot_renderer),
-                                                 &priv->selection_colour);
-
     aisleriot_slot_renderer_set_animation_layer
       (AISLERIOT_SLOT_RENDERER (slot->slot_renderer),
        CLUTTER_CONTAINER (priv->animation_layer));
@@ -1058,7 +897,7 @@ slot_update_card_images_full (AisleriotBoard *board,
     clutter_actor_set_position (slot->slot_renderer,
                                 slot->rect.x, slot->rect.y);
 
-    clutter_container_add (CLUTTER_CONTAINER (stage),
+    clutter_container_add (CLUTTER_CONTAINER (board),
                            slot->slot_renderer, NULL);
 
     clutter_actor_raise_top (priv->animation_layer);
@@ -1074,7 +913,7 @@ slot_update_card_images_full (AisleriotBoard *board,
 
 static void
 slot_update_card_images (AisleriotBoard *board,
-                         Slot *slot)
+                         ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
   int highlight_start_card_id = G_MAXINT;
@@ -1096,9 +935,7 @@ slot_update_card_images (AisleriotBoard *board,
 static void
 aisleriot_board_error_bell (AisleriotBoard *board)
 {
-#if GTK_CHECK_VERSION (2, 12, 0) || (defined (HAVE_HILDON) && !defined(HAVE_MAEMO_3))
-  gtk_widget_error_bell (GTK_WIDGET (board));
-#endif
+  g_signal_emit (board, signals[ERROR_BELL], 0);
 }
 
 /* Work out new sizes and spacings for the cards. */
@@ -1106,29 +943,35 @@ static void
 aisleriot_board_setup_geometry (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
+  ClutterActor *actor = CLUTTER_ACTOR (board);
+  GamesCardTheme *theme;
   GPtrArray *slots;
   guint i, n_slots;
   CardSize card_size;
 
+  if (!CLUTTER_ACTOR_IS_REALIZED (actor))
+    return;
+
   /* Nothing to do yet */
   if (aisleriot_game_get_state (priv->game) <= GAME_LOADED)
     return;
-  if (!priv->theme)
+
+  theme = ar_style_get_card_theme (priv->style);
+  if (theme == NULL)
     return;
 
-  g_return_if_fail (GTK_WIDGET_REALIZED (widget));
   g_return_if_fail (priv->width > 0 && priv->height > 0);
 
-  priv->xslotstep = ((double) widget->allocation.width) / priv->width;
-  priv->yslotstep = ((double) widget->allocation.height) / priv->height;
+  // FIXMEchpe
+  priv->xslotstep = ((double) priv->allocation.x2 - priv->allocation.x1) / priv->width;
+  priv->yslotstep = ((double) priv->allocation.y2 - priv->allocation.y1) / priv->height;
 
-  games_card_theme_set_size (priv->theme,
+  games_card_theme_set_size (theme,
                              priv->xslotstep,
                              priv->yslotstep,
                              priv->card_slot_ratio);
 
-  games_card_theme_get_size (priv->theme, &card_size);
+  games_card_theme_get_size (theme, &card_size);
   priv->card_size = card_size;
 
   /* If the cards are too far apart, bunch them in the middle. */
@@ -1136,7 +979,11 @@ aisleriot_board_setup_geometry (AisleriotBoard *board)
   if (priv->xslotstep > (card_size.width * 3) / 2) {
     priv->xslotstep = (card_size.width * 3) / 2;
     /* FIXMEchpe: if there are expand-right slots, reserve the space for them instead? */
+#ifdef FIXMEchpe
     priv->xbaseoffset = (widget->allocation.width - priv->xslotstep * priv->width) / 2;
+#else
+    priv->xbaseoffset = (priv->allocation.x2 - priv->allocation.x1 - priv->xslotstep * priv->width) / 2;
+#endif
   }
   if (priv->yslotstep > (card_size.height * 3) / 2) {
     priv->yslotstep = (card_size.height * 3) / 2;
@@ -1158,7 +1005,7 @@ aisleriot_board_setup_geometry (AisleriotBoard *board)
 
   n_slots = slots->len;
   for (i = 0; i < n_slots; ++i) {
-    Slot *slot = slots->pdata[i];
+    ArSlot *slot = slots->pdata[i];
 
     slot_update_geometry (board, slot);
     slot_update_card_images (board, slot);
@@ -1166,20 +1013,18 @@ aisleriot_board_setup_geometry (AisleriotBoard *board)
 
   /* Update the focus and selection rects */
   get_focus_rect (board, &priv->focus_rect);
-  get_selection_rect (board, &priv->selection_rect);
 }
 
 static void
 drag_begin (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *hslot;
+  ArSlot *hslot;
   int delta, height, width;
   int x, y;
   int num_moving_cards;
   guint i;
   GByteArray *cards;
-  ClutterActor *stage;
 
   if (!priv->selection_slot ||
       priv->selection_start_card_id < 0) {
@@ -1263,16 +1108,14 @@ drag_begin (AisleriotBoard *board)
   slot_update_card_images (board, hslot);
   aisleriot_game_reset_old_cards (hslot);
 
-  stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (board));
-  clutter_container_add (CLUTTER_CONTAINER (stage),
+  clutter_container_add (CLUTTER_CONTAINER (board),
                          priv->moving_cards_group, NULL);
 
   if (hslot->cards->len == 0) {
     clutter_actor_lower_bottom (hslot->slot_renderer);
-    clutter_actor_lower_bottom (priv->baize_actor);
   }
 
-  set_cursor (board, CURSOR_CLOSED);
+  set_cursor (board, AR_CURSOR_CLOSED);
 }
 
 static void
@@ -1308,7 +1151,7 @@ drag_end (AisleriotBoard *board,
 
 static gboolean
 cards_are_droppable (AisleriotBoard *board,
-                     Slot *slot)
+                     ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
 
@@ -1321,14 +1164,14 @@ cards_are_droppable (AisleriotBoard *board,
                                     priv->moving_cards->len);
 }
 
-static Slot *
+static ArSlot *
 find_drop_target (AisleriotBoard *board,
                   gint x,
                   gint y)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *new_hslot;
-  Slot *retval = NULL;
+  ArSlot *new_hslot;
+  ArSlot *retval = NULL;
   gint i, new_cardid;
   gint min_distance = G_MAXINT;
 
@@ -1376,7 +1219,7 @@ drop_moving_cards (AisleriotBoard *board,
                    gint y)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *hslot;
+  ArSlot *hslot;
   gboolean moved = FALSE;
   guint i;
 
@@ -1420,12 +1263,10 @@ drop_moving_cards (AisleriotBoard *board,
 
 static void
 highlight_drop_target (AisleriotBoard *board,
-                       Slot *slot)
+                       ArSlot *slot)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
-  GdkRectangle rect;
-  Slot *old_slot = priv->highlight_slot;
+  ArSlot *old_slot = priv->highlight_slot;
 
   if (slot == old_slot)
     return;
@@ -1438,12 +1279,6 @@ highlight_drop_target (AisleriotBoard *board,
   /* Invalidate the old highlight rect */
   if (old_slot != NULL &&
       priv->show_highlight) {
-    get_rect_by_slot_and_card (board,
-                               old_slot,
-                               old_slot->cards->len - 1 /* it's ok if this is == -1 */,
-                               1, &rect);
-    gdk_window_invalidate_rect (widget->window, &rect, FALSE);
-
     /* FIXMEchpe only update the topmost card? */
     /* It's ok to call this directly here, since the old highlight_slot cannot
      * have been the same as the current selection_slot!
@@ -1457,12 +1292,7 @@ highlight_drop_target (AisleriotBoard *board,
   if (!priv->show_highlight)
     return;
 
-  /* Prepare the highlight pixbuf/pixmaps and invalidate the new highlight rect */
-  get_rect_by_slot_and_card (board,
-                             slot,
-                             slot->cards->len - 1 /* it's ok if this is == -1 */,
-                             1, &rect);
-  gdk_window_invalidate_rect (widget->window, &rect, FALSE);
+  /* Prepare the highlight pixbuf/pixmaps */
 
   /* FIXMEchpe only update the topmost card? */
   /* It's ok to call this directly, since the highlight slot is always
@@ -1473,7 +1303,7 @@ highlight_drop_target (AisleriotBoard *board,
 
 static void
 reveal_card (AisleriotBoard *board,
-             Slot *slot,
+             ArSlot *slot,
              int cardid)
 {
   AisleriotBoardPrivate *priv = board->priv;
@@ -1523,40 +1353,13 @@ clear_state (AisleriotBoard *board)
   priv->last_clicked_card_id = -1;
 }
 
-static void
-aisleriot_board_settings_update (GtkSettings *settings,
-                                 GParamSpec *pspec,
-                                 AisleriotBoard *board)
-{
-  AisleriotBoardPrivate *priv = board->priv;
-  gboolean animations_enabled;
-#if GTK_CHECK_VERSION (2, 10, 0)
-  gboolean touchscreen_mode;
-#endif /* GTK >= 2.10.0 */
-
-   /* Set up the double-click detection. */
-  g_object_get (settings,
-                "gtk-double-click-time", &priv->double_click_time,
-                "gtk-enable-animations", &animations_enabled,
-#if GTK_CHECK_VERSION (2, 10, 0)
-                "gtk-touchscreen-mode", &touchscreen_mode,
-#endif /* GTK >= 2.10.0 */
-                NULL);
-
-  priv->animations_enabled = animations_enabled;
-
-#if GTK_CHECK_VERSION (2, 10, 0)
-  priv->touchscreen_mode = touchscreen_mode != FALSE;
-#endif /* GTK >= 2.10.0 */
-}
-
 /* Note: this unsets the selection! */
 static gboolean
 aisleriot_board_move_selected_cards_to_slot (AisleriotBoard *board,
-                                             Slot *hslot)
+                                             ArSlot *hslot)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *selection_slot = priv->selection_slot;
+  ArSlot *selection_slot = priv->selection_slot;
   int selection_start_card_id = priv->selection_start_card_id;
   gboolean moved;
   guint8 *cards;
@@ -1688,53 +1491,59 @@ aisleriot_board_move_selected_cards_to_slot (AisleriotBoard *board,
  */
 
 static void
-aisleriot_board_add_move_binding (GtkBindingSet  *binding_set,
-                                  guint           keyval,
-                                  guint           modmask,
-                                  GtkMovementStep step,
-                                  gint            count)
-{
-  gtk_binding_entry_add_signal (binding_set, keyval,
-                                modmask,
-                                "move-cursor", 2,
-                                G_TYPE_ENUM, step,
-                                G_TYPE_INT, count);
-
-  if (modmask & GDK_CONTROL_MASK)
-   return;
-
-  gtk_binding_entry_add_signal (binding_set, keyval,
-                                modmask | GDK_CONTROL_MASK,
-                                "move-cursor", 2,
-                                G_TYPE_ENUM, step,
-                                G_TYPE_INT, count);
+aisleriot_board_add_move_binding (ClutterBindingPool *binding_pool,
+                                  GClosure           *closure,
+                                  const char         *action,
+                                  guint               keyval,
+                                  ClutterModifierType modifiers)
+{
+  clutter_binding_pool_install_closure (binding_pool,
+                                        action,
+                                        keyval,
+                                        modifiers,
+                                        closure);
+
+  if (modifiers & CLUTTER_CONTROL_MASK)
+    return;
 
+  clutter_binding_pool_install_closure (binding_pool,
+                                        action,
+                                        keyval,
+                                        modifiers | CLUTTER_CONTROL_MASK,
+                                        closure);
 }
 
 static void
-aisleriot_board_add_move_and_select_binding (GtkBindingSet  *binding_set,
-                                             guint           keyval,
-                                             guint           modmask,
-                                             GtkMovementStep step,
-                                             gint            count)
+aisleriot_board_add_move_and_select_binding (ClutterBindingPool *binding_pool,
+                                             GClosure           *closure,
+                                             const char         *action,
+                                             guint               keyval,
+                                             ClutterModifierType modifiers)
 {
-  aisleriot_board_add_move_binding (binding_set, keyval, modmask, step, count);
-  aisleriot_board_add_move_binding (binding_set, keyval, modmask | GDK_SHIFT_MASK, step, count);
+  aisleriot_board_add_move_binding (binding_pool, closure, action, keyval, modifiers);
+  aisleriot_board_add_move_binding (binding_pool, closure, action, keyval, modifiers | CLUTTER_SHIFT_MASK);
 }
 
 static void
-aisleriot_board_add_activate_binding (GtkBindingSet  *binding_set,
-                                      guint           keyval,
-                                      guint           modmask)
-{
-  gtk_binding_entry_add_signal (binding_set, keyval, modmask,
-                                "activate", 0);
-
-  if (modmask & GDK_CONTROL_MASK)
+aisleriot_board_add_activate_binding (ClutterBindingPool *binding_pool,
+                                      GClosure           *closure,
+                                      guint               keyval,
+                                      ClutterModifierType modifiers)
+{
+  clutter_binding_pool_install_closure (binding_pool,
+                                        I_("activate"),
+                                        keyval,
+                                        modifiers,
+                                        closure);
+
+  if (modifiers & CLUTTER_CONTROL_MASK)
     return;
 
-  gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_CONTROL_MASK,
-                                "activate", 0);
+  clutter_binding_pool_install_closure (binding_pool,
+                                        I_("activate"),
+                                        keyval,
+                                        modifiers | CLUTTER_CONTROL_MASK,
+                                        closure);
 }
 
 static gboolean
@@ -1742,7 +1551,7 @@ aisleriot_board_move_cursor_in_slot (AisleriotBoard *board,
                                      int count)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot;
+  ArSlot *focus_slot;
   int new_focus_card_id, first_card_id;
 
   focus_slot = priv->focus_slot;
@@ -1760,7 +1569,7 @@ aisleriot_board_move_cursor_start_end_in_slot (AisleriotBoard *board,
                                                int count)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot = priv->focus_slot;
+  ArSlot *focus_slot = priv->focus_slot;
   int first_card_id, top_card_id, new_focus_card_id;
   guint8 *cards;
 
@@ -1817,7 +1626,7 @@ aisleriot_board_extend_selection_in_slot (AisleriotBoard *board,
                                           int count)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot, *selection_slot;
+  ArSlot *focus_slot, *selection_slot;
   int new_selection_start_card_id, first_card_id;
 
   focus_slot = priv->focus_slot;
@@ -1866,7 +1675,7 @@ static gboolean
 aisleriot_board_extend_selection_in_slot_maximal (AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot = priv->focus_slot;
+  ArSlot *focus_slot = priv->focus_slot;
   int new_selection_start_card_id, n_selected;
 
   n_selected = 0;
@@ -1895,16 +1704,12 @@ aisleriot_board_move_cursor_left_right_by_slot (AisleriotBoard *board,
                                                 gboolean wrap)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
   GPtrArray *slots;
   guint n_slots;
-  Slot *focus_slot, *new_focus_slot;
+  ArSlot *focus_slot, *new_focus_slot;
   int focus_slot_index, new_focus_slot_index;
   int new_focus_slot_topmost_card_id, new_focus_card_id;
   gboolean is_rtl;
-#if GTK_CHECK_VERSION (2, 12, 0)
-  GtkDirectionType direction;
-#endif
 
   slots = aisleriot_game_get_slots (priv->game);
   if (!slots || slots->len == 0)
@@ -1918,8 +1723,8 @@ aisleriot_board_move_cursor_left_right_by_slot (AisleriotBoard *board,
   focus_slot_index = get_slot_index_from_slot (board, focus_slot);
 
   /* Move visually */
-  is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
-  if (is_rtl) {
+  is_rtl = priv->is_rtl;
+  if (priv->is_rtl) {
     new_focus_slot_index = focus_slot_index - count;
   } else {
     new_focus_slot_index = focus_slot_index + count;
@@ -1931,7 +1736,11 @@ aisleriot_board_move_cursor_left_right_by_slot (AisleriotBoard *board,
     if (!wrap)
       return FALSE;
 
+#ifdef FIXMEchpe
+{
+    GtkDirectionType direction;
 #if GTK_CHECK_VERSION (2, 12, 0)
+
     if (count > 0) {
       direction = GTK_DIR_RIGHT;
     } else {
@@ -1942,6 +1751,8 @@ aisleriot_board_move_cursor_left_right_by_slot (AisleriotBoard *board,
        return gtk_widget_child_focus (gtk_widget_get_toplevel (widget), direction);
     }
 #endif /* GTK 2.12. 0 */
+}
+#endif // FIXMEchpe
 
     if (new_focus_slot_index < 0) {
       new_focus_slot_index = ((int) n_slots) - 1;
@@ -1982,7 +1793,7 @@ aisleriot_board_move_cursor_up_down_by_slot (AisleriotBoard *board,
   AisleriotBoardPrivate *priv = board->priv;
   GPtrArray *slots;
   guint n_slots;
-  Slot *focus_slot, *new_focus_slot;
+  ArSlot *focus_slot, *new_focus_slot;
   int focus_slot_index, new_focus_slot_index;
   int new_focus_slot_topmost_card_id, new_focus_card_id;
   int x_start, x_end;
@@ -2009,6 +1820,7 @@ aisleriot_board_move_cursor_up_down_by_slot (AisleriotBoard *board,
            !test_slot_projection_intersects_x (slots->pdata[new_focus_slot_index], x_start, x_end));
 
   if (new_focus_slot_index < 0 || new_focus_slot_index == n_slots) {
+#ifdef FIXMEchpe
 #if GTK_CHECK_VERSION (2, 12, 0)
     GtkWidget *widget = GTK_WIDGET (board);
     GtkDirectionType direction;
@@ -2023,6 +1835,7 @@ aisleriot_board_move_cursor_up_down_by_slot (AisleriotBoard *board,
        return gtk_widget_child_focus (gtk_widget_get_toplevel (widget), direction);
     }
 #endif /* GTK 2.12. 0 */
+#endif // FIXMEchpe
 
     /* Wrap around */
     if (count > 0) {
@@ -2067,7 +1880,7 @@ aisleriot_board_move_cursor_start_end_by_slot (AisleriotBoard *board,
 {
   AisleriotBoardPrivate *priv = board->priv;
   GPtrArray *slots;
-  Slot *new_focus_slot;
+  ArSlot *new_focus_slot;
   int new_focus_card_id;
 
   slots = aisleriot_game_get_slots (priv->game);
@@ -2075,10 +1888,10 @@ aisleriot_board_move_cursor_start_end_by_slot (AisleriotBoard *board,
     return FALSE;
 
   if (count > 0) {
-    new_focus_slot = (Slot *) slots->pdata[slots->len - 1];
+    new_focus_slot = (ArSlot *) slots->pdata[slots->len - 1];
     new_focus_card_id = ((int) new_focus_slot->cards->len) - 1;
   } else {
-    new_focus_slot = (Slot *) slots->pdata[0];
+    new_focus_slot = (ArSlot *) slots->pdata[0];
     if (new_focus_slot->cards->len > 0) {
       new_focus_card_id = ((int) new_focus_slot->cards->len) - ((int) new_focus_slot->exposed);
     } else {
@@ -2099,15 +1912,11 @@ aisleriot_board_move_cursor_left_right (AisleriotBoard *board,
                                         gboolean is_control)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
-  gboolean is_rtl;
-
-  is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
 
   /* First try in-slot focus movement */
   if (!is_control &&
       priv->focus_slot->expanded_right &&
-      aisleriot_board_move_cursor_in_slot (board, is_rtl ? -count : count))
+      aisleriot_board_move_cursor_in_slot (board, priv->is_rtl ? -count : count))
     return TRUE;
 
   /* Cannot move in-slot; move focused slot */
@@ -2120,13 +1929,9 @@ aisleriot_board_move_cursor_up_down (AisleriotBoard *board,
                                      gboolean is_control)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
-  gboolean is_rtl;
 
   g_assert (priv->focus_slot != NULL);
 
-  is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
-
   /* First try in-slot focus movement */
   if (!is_control &&
       priv->focus_slot->expanded_down &&
@@ -2166,7 +1971,7 @@ aisleriot_board_extend_selection_start_end (AisleriotBoard *board,
                                             int count)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot = priv->focus_slot;
+  ArSlot *focus_slot = priv->focus_slot;
   int new_focus_card_id;
 
   if (count > 0) {
@@ -2254,13 +2059,11 @@ game_new_cb (AisleriotGame *game,
 
   /* Check for animations so that the differences will be reset */
   queue_check_animations (board);
-
-  gtk_widget_queue_draw (GTK_WIDGET (board));
 }
 
 static void
 slot_changed_cb (AisleriotGame *game,
-                 Slot *slot,
+                 ArSlot *slot,
                  AisleriotBoard *board)
 {
   AisleriotBoardPrivate *priv = board->priv;
@@ -2305,26 +2108,147 @@ slot_changed_cb (AisleriotGame *game,
   queue_check_animations (board);
 }
 
+/* Style handling */
+
+static void
+aisleriot_board_sync_style (ArStyle *style,
+                            GParamSpec *pspec,
+                            AisleriotBoard *board)
+{
+  AisleriotBoardPrivate *priv = board->priv;
+  const char *pspec_name;
+  gboolean update_geometry = FALSE, redraw_focus = FALSE;
+
+  g_assert (style == priv->style);
+
+  if (pspec != NULL) {
+    pspec_name = pspec->name;
+  } else {
+    pspec_name = NULL;
+  }
+
+  if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_CARD_THEME)) {
+    GamesCardTheme *theme;
+
+    theme = ar_style_get_card_theme (style);
+    if (theme != NULL) {
+      games_card_textures_cache_set_theme (priv->textures, theme);
+
+      priv->geometry_set = FALSE;
+
+      update_geometry |= TRUE;
+    }
+  }
+
+  if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_CARD_SLOT_RATIO)) {
+    double card_slot_ratio;
+
+    card_slot_ratio = ar_style_get_card_slot_ratio (style);
+
+    update_geometry |= (card_slot_ratio != priv->card_slot_ratio);
+
+    priv->card_slot_ratio = card_slot_ratio;
+  }
+
+  if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_INTERIOR_FOCUS)) {
+    gboolean interior_focus;
+
+    interior_focus = ar_style_get_interior_focus (style);
+
+    redraw_focus = (interior_focus != priv->interior_focus);
+
+    priv->interior_focus = interior_focus;
+  }
+
+  if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_FOCUS_LINE_WIDTH)) {
+    int focus_line_width;
+
+    focus_line_width = ar_style_get_focus_line_width (style);
+
+    redraw_focus = (focus_line_width != priv->focus_line_width);
+
+    priv->focus_line_width = focus_line_width;
+  }
+
+  if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_FOCUS_PADDING)) {
+    int focus_padding;
+
+    focus_padding = ar_style_get_focus_padding (style);
+
+    redraw_focus = (focus_padding != priv->focus_padding);
+
+    priv->focus_padding = focus_padding;
+  }
+
+  if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_RTL)) {
+    gboolean is_rtl;
+
+    is_rtl = ar_style_get_rtl (style);
+
+    update_geometry |= (is_rtl != priv->is_rtl);
+
+    priv->is_rtl = is_rtl;
+
+    /* FIXMEchpe: necessary? */
+    priv->force_geometry_update = TRUE;
+  }
+
+  if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_ENABLE_ANIMATIONS)) {
+    /* FIXMEchpe: abort animations-in-progress if the setting is now OFF */
+  }
+
+  if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_CLICK_TO_MOVE)) {
+    gboolean click_to_move;
+
+    click_to_move = ar_style_get_click_to_move (style);
+    if (click_to_move != priv->click_to_move) {
+      /* Clear the selection. Do this before setting the new value,
+      * since otherwise selection won't get cleared correctly.
+      */
+      set_selection (board, NULL, -1, FALSE);
+
+      priv->click_to_move = click_to_move;
+
+      /* FIXMEchpe: we used to queue a redraw here. WHY?? Check that it's safe not to. */
+    }
+  }
+
+  /* FIXMEchpe: queue a relayout instead? */
+  if (update_geometry) {
+    aisleriot_board_setup_geometry (board);
+  }
+
+  if (redraw_focus) {
+    /* FIXMEchpe: do redraw the focus! */
+  }
+}
+
 /* Class implementation */
 
-G_DEFINE_TYPE (AisleriotBoard, aisleriot_board, GTK_CLUTTER_TYPE_EMBED);
+G_DEFINE_TYPE (AisleriotBoard, aisleriot_board, CLUTTER_TYPE_GROUP);
 
 /* AisleriotBoardClass methods */
 
 #ifdef ENABLE_KEYNAV
 
 static void
-aisleriot_board_activate (AisleriotBoard *board)
+aisleriot_board_activate (AisleriotBoard *board,
+                          const char *action,
+                          guint keyval,
+                          ClutterModifierType modifiers)
 {
-  AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
-  Slot *focus_slot = priv->focus_slot;
-  Slot *selection_slot = priv->selection_slot;
+  AisleriotBoardPrivate *priv = board->priv;  ArSlot *focus_slot = priv->focus_slot;
+  ArSlot *selection_slot = priv->selection_slot;
   int selection_start_card_id = priv->selection_start_card_id;
-  guint state = 0;
 
+#ifdef FIXMEchpe
   if (!GTK_WIDGET_HAS_FOCUS (widget))
     return;
+#endif
+
+  _games_debug_print (GAMES_DEBUG_GAME_KEYNAV,
+                      "board ::activate keyval %x modifiers %x\n",
+                      keyval, modifiers);
 
   if (!focus_slot) {
     aisleriot_board_error_bell (board);
@@ -2337,11 +2261,8 @@ aisleriot_board_activate (AisleriotBoard *board)
     return;
   }
 
-  if (!gtk_get_current_event_state (&state))
-    state = 0;
-
   /* Control-Activate is double-click */
-  if (state & GDK_CONTROL_MASK) {
+  if (modifiers & CLUTTER_CONTROL_MASK) {
     aisleriot_game_record_move (priv->game, -1, NULL, 0);
     if (aisleriot_game_button_double_clicked_lambda (priv->game, focus_slot->id)) {
       aisleriot_game_end_move (priv->game);
@@ -2394,35 +2315,39 @@ aisleriot_board_activate (AisleriotBoard *board)
 
 static gboolean
 aisleriot_board_move_cursor (AisleriotBoard *board,
-                             GtkMovementStep step,
-                             int count)
+                             const char *action,
+                             guint keyval,
+                             ClutterModifierType modifiers)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
-  guint state;
   gboolean is_control, is_shift, moved = FALSE;
+  char step;
+  int count;
 
+#ifdef FIXMEchpe
   if (!GTK_WIDGET_HAS_FOCUS (widget))
     return FALSE;
+#endif
+
+  step = action[0];
+  count = (action[1] == MOVE_LEFT ? -1 : 1);
 
-  g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
-                        step == GTK_MOVEMENT_VISUAL_POSITIONS ||
-                        step == GTK_MOVEMENT_DISPLAY_LINES ||
-                        step == GTK_MOVEMENT_PAGES ||
-                        step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
+  _games_debug_print (GAMES_DEBUG_GAME_KEYNAV,
+                      "board ::move-cursor keyval %x modifiers %x step '%c' count %d\n",
+                      keyval, modifiers,
+                      step, count);
 
   /* No focus? Set focus to the first/last slot */
   /* This will always return TRUE, no need for keynav-failed handling */
   if (!priv->focus_slot) {
     switch (step) {
-      case GTK_MOVEMENT_DISPLAY_LINES:
-      case GTK_MOVEMENT_PAGES:
+      case MOVE_CURSOR_UP_DOWN:
+      case MOVE_CURSOR_PAGES:
         /* Focus the first slot */
         return aisleriot_board_move_cursor_start_end_by_slot (board, -1);
-      case GTK_MOVEMENT_LOGICAL_POSITIONS:
-      case GTK_MOVEMENT_VISUAL_POSITIONS:
+      case MOVE_CURSOR_LEFT_RIGHT:
         /* Move as if we'd been on the last/first slot */
-        if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL) {
+        if (!priv->is_rtl) {
           return aisleriot_board_move_cursor_start_end_by_slot (board, -count);
         }
         /* fall-through */
@@ -2433,34 +2358,30 @@ aisleriot_board_move_cursor (AisleriotBoard *board,
 
   g_assert (priv->focus_slot != NULL);
 
-  if (!gtk_get_current_event_state (&state))
-    state = 0;
-
-  is_shift = (state & GDK_SHIFT_MASK) != 0;
-  is_control = (state & GDK_CONTROL_MASK) != 0;
+  is_shift = (modifiers & CLUTTER_SHIFT_MASK) != 0;
+  is_control = (modifiers & CLUTTER_CONTROL_MASK) != 0;
 
   switch (step) {
-    case GTK_MOVEMENT_LOGICAL_POSITIONS:
-    case GTK_MOVEMENT_VISUAL_POSITIONS:
+    case MOVE_CURSOR_LEFT_RIGHT:
       if (is_shift) {
         moved = aisleriot_board_extend_selection_left_right (board, count);
       } else {
         moved = aisleriot_board_move_cursor_left_right (board, count, is_control);
       }
       break;
-    case GTK_MOVEMENT_DISPLAY_LINES:
+    case MOVE_CURSOR_UP_DOWN:
       if (is_shift) {
         moved = aisleriot_board_extend_selection_up_down (board, count);
       } else {
         moved = aisleriot_board_move_cursor_up_down (board, count, is_control);
       }
       break;
-    case GTK_MOVEMENT_PAGES:
+    case MOVE_CURSOR_PAGES:
       if (!is_shift) {
         moved = aisleriot_board_move_cursor_up_down (board, count, TRUE);
       }
       break;
-    case GTK_MOVEMENT_BUFFER_ENDS:
+    case MOVE_CURSOR_START_END:
       if (is_shift) {
         moved = aisleriot_board_extend_selection_start_end (board, count);
       } else if (is_control) {
@@ -2483,10 +2404,17 @@ aisleriot_board_move_cursor (AisleriotBoard *board,
 }
 
 static void
-aisleriot_board_select_all (AisleriotBoard *board)
+aisleriot_board_select_all (AisleriotBoard *board,
+                            const char *action,
+                            guint keyval,
+                            ClutterModifierType modifiers)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot = priv->focus_slot;
+  ArSlot *focus_slot = priv->focus_slot;
+
+  _games_debug_print (GAMES_DEBUG_GAME_KEYNAV,
+                      "board ::select-all keyval %x modifiers %x\n",
+                      keyval, modifiers);
 
   if (!focus_slot ||
       focus_slot->cards->len == 0 ||
@@ -2497,18 +2425,32 @@ aisleriot_board_select_all (AisleriotBoard *board)
 }
 
 static void
-aisleriot_board_deselect_all (AisleriotBoard *board)
+aisleriot_board_deselect_all (AisleriotBoard *board,
+                              const char *action,
+                              guint keyval,
+                              ClutterModifierType modifiers)
 {
+  _games_debug_print (GAMES_DEBUG_GAME_KEYNAV,
+                      "board ::deselect-all keyval %x modifiers %x\n",
+                      keyval, modifiers);
+
   set_selection (board, NULL, -1, FALSE);
 }
 
 static void
-aisleriot_board_toggle_selection (AisleriotBoard *board)
+aisleriot_board_toggle_selection (AisleriotBoard *board,
+                                  const char *action,
+                                  guint keyval,
+                                  ClutterModifierType modifiers)
 {
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *focus_slot;
+  ArSlot *focus_slot;
   int focus_card_id;
 
+  _games_debug_print (GAMES_DEBUG_GAME_KEYNAV,
+                      "board ::toggle-selection keyval %x modifiers %x\n",
+                      keyval, modifiers);
+
   focus_slot = priv->focus_slot;
   if (!focus_slot)
     return;
@@ -2550,28 +2492,18 @@ aisleriot_board_toggle_selection (AisleriotBoard *board)
 
 #endif /* ENABLE_KEYNAV */
 
-/* GtkWidgetClass methods */
+
+/* ClutterActorClass impl */
+
+#if 0
 static void
 aisleriot_board_realize (GtkWidget *widget)
 {
   AisleriotBoard *board = AISLERIOT_BOARD (widget);
-  AisleriotBoardPrivate *priv = board->priv;
-  GdkDisplay *display;
+//   AisleriotBoardPrivate *priv = board->priv;
 
   GTK_WIDGET_CLASS (aisleriot_board_parent_class)->realize (widget);
 
-  display = gtk_widget_get_display (widget);
-
-  set_background_from_baize (board);
-  
-#ifndef HAVE_HILDON
-  /* Create cursors */
-  priv->cursor[CURSOR_DEFAULT] = gdk_cursor_new_for_display (display, GDK_LEFT_PTR);
-  priv->cursor[CURSOR_OPEN] = make_cursor (widget, hand_open_data_bits, hand_open_mask_bits);
-  priv->cursor[CURSOR_CLOSED] = make_cursor (widget, hand_closed_data_bits, hand_closed_mask_bits);
-  priv->cursor[CURSOR_DROPPABLE] = gdk_cursor_new_for_display (display, GDK_DOUBLE_ARROW); /* FIXMEchpe: better cursor */
-#endif /* !HAVE_HILDON */
-
   aisleriot_board_setup_geometry (board);
 }
 
@@ -2580,197 +2512,81 @@ aisleriot_board_unrealize (GtkWidget *widget)
 {
   AisleriotBoard *board = AISLERIOT_BOARD (widget);
   AisleriotBoardPrivate *priv = board->priv;
-#ifndef HAVE_HILDON 
-  guint i;
-#endif
 
   priv->geometry_set = FALSE;
 
-#ifndef HAVE_HILDON
-  for (i = 0; i < LAST_CURSOR; ++i) {
-    gdk_cursor_unref (priv->cursor[i]);
-    priv->cursor[i] = NULL;
-  }
-#endif /* !HAVE_HILDON*/
-
   clear_state (board);
 
   GTK_WIDGET_CLASS (aisleriot_board_parent_class)->unrealize (widget);
 }
+#endif
 
 static void
-aisleriot_board_screen_changed (GtkWidget *widget,
-                                GdkScreen *previous_screen)
-{
-  AisleriotBoard *board = AISLERIOT_BOARD (widget);
-  GdkScreen *screen;
-  GtkSettings *settings;
-
-  if (GTK_WIDGET_CLASS (aisleriot_board_parent_class)->screen_changed) {
-    GTK_WIDGET_CLASS (aisleriot_board_parent_class)->screen_changed (widget, previous_screen);
-  }
-
-  screen = gtk_widget_get_screen (widget);
-  if (screen == previous_screen)
-    return;
-
-  if (previous_screen) {
-    g_signal_handlers_disconnect_by_func (gtk_settings_get_for_screen (previous_screen),
-                                          G_CALLBACK (aisleriot_board_settings_update),
-                                          board);
-  }
-
-  if (screen == NULL)
-    return;
-
-  settings = gtk_settings_get_for_screen (screen);
-
-  aisleriot_board_settings_update (settings, NULL, board);
-  g_signal_connect (settings, "notify::gtk-double-click-time",
-                    G_CALLBACK (aisleriot_board_settings_update), board);
-  g_signal_connect (settings, "notify::gtk-enable-animations",
-                    G_CALLBACK (aisleriot_board_settings_update), board);
-#if GTK_CHECK_VERSION (2, 10, 0)
-  g_signal_connect (settings, "notify::gtk-touchscreen-mode",
-                    G_CALLBACK (aisleriot_board_settings_update), board);
-#endif /* GTK >= 2.10.0 */
-}
-
-static void
-aisleriot_board_style_set (GtkWidget *widget,
-                           GtkStyle *previous_style)
+aisleriot_board_allocate (ClutterActor *actor,
+                          const ClutterActorBox *box,
+                          ClutterAllocationFlags flags)
 {
-  AisleriotBoard *board = AISLERIOT_BOARD (widget);
+  AisleriotBoard *board = AISLERIOT_BOARD (actor);
   AisleriotBoardPrivate *priv = board->priv;
-  GdkColor *colour = NULL;
-  GdkColor selection_colour;
-  gboolean interior_focus;
-  double card_slot_ratio;
-  GPtrArray *slots;
-  int i, n_slots;
-
-  gtk_widget_style_get (widget,
-                        "focus-line-width", &priv->focus_line_width,
-                        "focus-padding", &priv->focus_padding,
-                        "interior-focus", &interior_focus,
-                        "selection-color", &colour,
-                        "card-slot-ratio", &card_slot_ratio,
-                        NULL);
-
-#if 0
-  g_print ("style-set: focus width %d padding %d interior-focus %s card-slot-ratio %.2f\n",
-           priv->focus_line_width,
-           priv->focus_padding,
-           interior_focus ? "t" : "f",
-           card_slot_ratio);
-#endif
+  gboolean is_same;
 
-  priv->interior_focus = interior_focus != FALSE;
+  is_same = clutter_actor_box_equal (box, &priv->allocation);
 
-  priv->card_slot_ratio = card_slot_ratio;
-  /* FIXMEchpe: if the ratio changed, we should re-layout the board below */
+  _games_debug_print (GAMES_DEBUG_GAME_SIZING,
+                      "board ::allocate (%f / %f)-(%f / %f) => %f x %f is-same %s force-update %s\n",
+                      box->x1, box->y1, box->x2, box->y2,
+                      box->x2 - box->x1, box->y2 - box->y1,
+                      is_same ? "t" : "f",
+                      priv->force_geometry_update ? "t" : "f");
 
-  if (colour != NULL) {
-    selection_colour = *colour;
-    gdk_color_free (colour);
-  } else {
-    const GdkColor default_selection_colour = { 0, 0 /* red */, 0 /* green */, 0xaa00 /* blue */};
+  CLUTTER_ACTOR_CLASS (aisleriot_board_parent_class)->allocate (actor, box, flags);
 
-    selection_colour = default_selection_colour;
-  }
+  priv->allocation = *box;
 
-  priv->selection_colour.red   = selection_colour.red   >> 8;
-  priv->selection_colour.green = selection_colour.green >> 8;
-  priv->selection_colour.blue  = selection_colour.blue  >> 8;
-  priv->selection_colour.alpha = 0xff;
-
-  /* Update the existing slots */
-  slots = aisleriot_game_get_slots (priv->game);
-  n_slots = slots->len;
-  for (i = 0; i < n_slots; ++i) {
-    Slot *slot = slots->pdata[i];
+  if (is_same && !priv->force_geometry_update)
+    return;
 
-    if (slot->slot_renderer)
-      aisleriot_slot_renderer_set_highlight_color (AISLERIOT_SLOT_RENDERER (slot->slot_renderer),
-                                                   &priv->selection_colour);
-  }
+  priv->force_geometry_update = FALSE;
 
-  GTK_WIDGET_CLASS (aisleriot_board_parent_class)->style_set (widget, previous_style);
+  /* FIXMEchpe: just queue this instead maybe? */
+  aisleriot_board_setup_geometry (board);
 }
 
 static void
-aisleriot_board_direction_changed (GtkWidget *widget,
-                                   GtkTextDirection previous_direction)
+aisleriot_board_get_preferred_width (ClutterActor *actor,
+                                     float for_height,
+                                     float *min_width_p,
+                                     float *natural_width_p)
 {
-  AisleriotBoard *board = AISLERIOT_BOARD (widget);
-  AisleriotBoardPrivate *priv = board->priv;
-  GtkTextDirection direction;
-
-  direction = gtk_widget_get_direction (widget);
-
-  priv->is_rtl = (direction == GTK_TEXT_DIR_RTL);
-
-  if (direction != previous_direction) {
-    priv->force_geometry_update = TRUE;
-  }
+  _games_debug_print (GAMES_DEBUG_GAME_SIZING,
+                      "board ::get-preferred-width\n");
 
-  /* This will queue a resize */
-  GTK_WIDGET_CLASS (aisleriot_board_parent_class)->direction_changed (widget, previous_direction);
+  *min_width_p = BOARD_MIN_WIDTH;
+  *natural_width_p = 3 * BOARD_MIN_WIDTH;
 }
 
 static void
-aisleriot_board_size_allocate (GtkWidget *widget,
-                               GtkAllocation *allocation)
+aisleriot_board_get_preferred_height (ClutterActor *actor,
+                                      float for_width,
+                                      float *min_height_p,
+                                      float *natural_height_p)
 {
-  AisleriotBoard *board = AISLERIOT_BOARD (widget);
-  AisleriotBoardPrivate *priv = board->priv;
-  gboolean is_same;
+  _games_debug_print (GAMES_DEBUG_GAME_SIZING,
+                      "board ::get-preferred-height\n");
 
-  is_same = (memcmp (&widget->allocation, allocation, sizeof (GtkAllocation)) == 0);
-  
-  GTK_WIDGET_CLASS (aisleriot_board_parent_class)->size_allocate (widget, allocation);
-
-  if (is_same && !priv->force_geometry_update)
-    return;
-
-  priv->force_geometry_update = FALSE;
-
-  if (GTK_WIDGET_REALIZED (widget)) {
-    aisleriot_board_setup_geometry (board);
-  }
-}
-
-static void
-aisleriot_board_size_request (GtkWidget *widget,
-                              GtkRequisition *requisition)
-{
-  requisition->width = BOARD_MIN_WIDTH;
-  requisition->height = BOARD_MIN_HEIGHT;
+  *min_height_p = BOARD_MIN_HEIGHT;
+  *natural_height_p = 3 * BOARD_MIN_HEIGHT;
 }
 
 #ifdef ENABLE_KEYNAV
 
 static gboolean
-aisleriot_board_focus (GtkWidget *widget,
-                       GtkDirectionType direction)
+aisleriot_board_focus (AisleriotBoard *board,
+                       int count)
 {
-  AisleriotBoard *board = AISLERIOT_BOARD (widget);
   AisleriotBoardPrivate *priv = board->priv;
 
   if (!priv->focus_slot) {
-    int count;
-
-    switch (direction) {
-      case GTK_DIR_TAB_FORWARD:
-        count = 1;
-        break;
-      case GTK_DIR_TAB_BACKWARD:
-        count = -1;
-        break;
-      default:
-        break;
-    }
-
     return aisleriot_board_move_cursor_start_end_by_slot (board, -count);
   }
 
@@ -2779,11 +2595,31 @@ aisleriot_board_focus (GtkWidget *widget,
     return TRUE;
 #endif
 
-  return GTK_WIDGET_CLASS (aisleriot_board_parent_class)->focus (widget, direction);
+  return FALSE;
+}
+
+static gboolean
+aisleriot_board_key_press (ClutterActor *actor,
+                           ClutterKeyEvent *event)
+{
+  ClutterBindingPool *pool;
+
+  _games_debug_print (GAMES_DEBUG_GAME_EVENTS,
+                      "board ::key-press keyval %x modifiers %x\n",
+                      event->keyval, event->modifier_state);
+
+  pool = clutter_binding_pool_get_for_class (CLUTTER_ACTOR_GET_CLASS (actor));
+  g_assert (pool != NULL);
+
+  return clutter_binding_pool_activate (pool,
+                                        event->keyval,
+                                        event->modifier_state,
+                                        G_OBJECT (actor));
 }
 
 #endif /* ENABLE_KEYNAV */
 
+#ifdef FIXMEchpe
 /* The gtkwidget.c focus in/out handlers queue a shallow draw;
  * that's ok for us but maybe we want to optimise this a bit to
  * only do it if we have a focus to draw/erase?
@@ -2827,30 +2663,43 @@ aisleriot_board_focus_out (GtkWidget *widget,
 
   return FALSE;
 }
+#endif /* FIXMEchpe */
 
 static gboolean
-aisleriot_board_button_press (GtkWidget *widget,
-                              GdkEventButton *event)
+aisleriot_board_button_press (ClutterActor *actor,
+                              ClutterButtonEvent *event)
 {
-  AisleriotBoard *board = AISLERIOT_BOARD (widget);
+  AisleriotBoard *board = AISLERIOT_BOARD (actor);
   AisleriotBoardPrivate *priv = board->priv;
-  Slot *hslot;
+  ArSlot *hslot;
   int cardid;
-  guint button;
+  guint32 button;
   gboolean drag_valid;
   guint state;
   gboolean is_double_click, show_focus;
 
+  _games_debug_print (GAMES_DEBUG_GAME_EVENTS,
+                      "board ::button-press @(%f / %f) button %d click-count %d modifiers %x\n",
+                      event->x, event->y,
+                      event->button, event->click_count,
+                      event->modifier_state);
+
   /* NOTE: It's ok to just return instead of chaining up, since the
-   * parent class has no class closure for this event.
+   * parent classes have no class closure for this event.
    */
 
+  /* FIXMEchpe: check event coordinate handling (float vs int!) */
+
+#ifdef FIXMEchpe
+  /* FIXMEchpe: we might be able to use ClutterButtonEvent::click_count for double-click detection! */
   /* ignore the gdk synthetic double/triple click events */
   if (event->type != GDK_BUTTON_PRESS)
     return FALSE;
+#endif
 
   /* Don't do anything if a modifier is pressed */
-  state = event->state & gtk_accelerator_get_default_mod_mask ();
+  /* FIXMEchpe: is there anything like gtk_accelerator_get_default_mod_mask() in clutter? */
+  state = event->modifier_state;
   if (state != 0)
     return FALSE;
 
@@ -2872,7 +2721,7 @@ aisleriot_board_button_press (GtkWidget *widget,
 
   is_double_click = button == 2 ||
                     (priv->last_click_left_click &&
-                     (event->time - priv->last_click_time <= priv->double_click_time) &&
+                     (event->time - priv->last_click_time <= ar_style_get_double_click_time (priv->style)) &&
                      priv->last_clicked_slot == hslot &&
                      priv->last_clicked_card_id == cardid);
 
@@ -2892,7 +2741,7 @@ aisleriot_board_button_press (GtkWidget *widget,
     return FALSE;
   }
 
-  set_cursor (board, CURSOR_CLOSED);
+  set_cursor (board, AR_CURSOR_CLOSED);
 
   /* First check if it's a right-click: if so, we reveal the card and do nothing else */
   if (button == 3) {
@@ -2910,7 +2759,7 @@ aisleriot_board_button_press (GtkWidget *widget,
    * different cards and a double-click on one card.
    */
   if (is_double_click) {
-    Slot *clicked_slot = hslot;
+    ArSlot *clicked_slot = hslot;
 
     priv->click_status = STATUS_NONE;
 
@@ -2926,7 +2775,7 @@ aisleriot_board_button_press (GtkWidget *widget,
 
     aisleriot_game_test_end_of_game (priv->game);
 
-    set_cursor (board, CURSOR_OPEN);
+    set_cursor (board, AR_CURSOR_OPEN);
 
     return TRUE;
   }
@@ -3012,15 +2861,23 @@ set_selection:
 }
 
 static gboolean
-aisleriot_board_button_release (GtkWidget *widget,
-                                GdkEventButton *event)
+aisleriot_board_button_release (ClutterActor *actor,
+                                ClutterButtonEvent *event)
 {
-  AisleriotBoard *board = AISLERIOT_BOARD (widget);
+  AisleriotBoard *board = AISLERIOT_BOARD (actor);
   AisleriotBoardPrivate *priv = board->priv;
   /* guint state; */
 
+  _games_debug_print (GAMES_DEBUG_GAME_EVENTS,
+                      "board ::button-release @(%f / %f) button %d click-count %d modifiers %x\n",
+                      event->x, event->y,
+                      event->button, event->click_count,
+                      event->modifier_state);
+
+  /* FIXMEchpe: check event coordinate handling (float vs int!) */
+
   /* NOTE: It's ok to just return instead of chaining up, since the
-   * parent class has no class closure for this event.
+   * parent classes have no class closure for this event.
    */
 
   /* We just abort any action on button release, even if the button-up
@@ -3042,7 +2899,7 @@ aisleriot_board_button_release (GtkWidget *widget,
 
     case STATUS_MAYBE_DRAG:
     case STATUS_NOT_DRAG: {
-      Slot *slot;
+      ArSlot *slot;
       int card_id;
 
       /* Don't do the action if the mouse moved away from the clicked slot; see bug #329183 */
@@ -3075,18 +2932,25 @@ aisleriot_board_button_release (GtkWidget *widget,
 }
 
 static gboolean
-aisleriot_board_motion_notify (GtkWidget *widget,
-                               GdkEventMotion * event)
+aisleriot_board_motion (ClutterActor *actor,
+                        ClutterMotionEvent *event)
 {
-  AisleriotBoard *board = AISLERIOT_BOARD (widget);
+  AisleriotBoard *board = AISLERIOT_BOARD (actor);
   AisleriotBoardPrivate *priv = board->priv;
 
+  _games_debug_print (GAMES_DEBUG_GAME_EVENTS,
+                      "board ::motion @(%f / %f) modifiers %x\n",
+                      event->x, event->y,
+                      event->modifier_state);
+
+  /* FIXMEchpe: check event coordinate handling (float vs int!) */
+
   /* NOTE: It's ok to just return instead of chaining up, since the
-   * parent class has no class closure for this event.
+   * parent classes have no class closure for this event.
    */
 
   if (priv->click_status == STATUS_IS_DRAG) {
-    Slot *slot;
+    ArSlot *slot;
     int x, y;
 
     x = event->x - priv->last_click_x;
@@ -3098,13 +2962,13 @@ aisleriot_board_motion_notify (GtkWidget *widget,
     clutter_actor_set_position (priv->moving_cards_group, x, y);
     clutter_actor_raise_top (priv->moving_cards_group);
 
-    set_cursor (board, CURSOR_CLOSED);
+    set_cursor (board, AR_CURSOR_CLOSED);
   } else if (priv->click_status == STATUS_MAYBE_DRAG &&
-             gtk_drag_check_threshold (widget,
-                                       priv->last_click_x,
-                                       priv->last_click_y,
-                                       event->x,
-                                       event->y)) {
+             ar_style_check_dnd_drag_threshold (priv->style,
+                                                priv->last_click_x,
+                                                priv->last_click_y,
+                                                event->x,
+                                                event->y)) {
     drag_begin (board);
   } else {
     set_cursor_by_location (board, event->x, event->y);
@@ -3114,83 +2978,72 @@ aisleriot_board_motion_notify (GtkWidget *widget,
 }
 
 static gboolean
-aisleriot_board_key_press (GtkWidget *widget,
-                           GdkEventKey* event)
+aisleriot_board_enter (ClutterActor *actor,
+                       ClutterCrossingEvent *event)
 {
-  return GTK_WIDGET_CLASS (aisleriot_board_parent_class)->key_press_event (widget, event);
-}
+  _games_debug_print (GAMES_DEBUG_GAME_EVENTS,
+                      "board ::enter @(%f / %f)\n",
+                      event->x, event->y);
 
-#ifdef HAVE_MAEMO
+  /* NOTE: It's ok to just return instead of chaining up, since the
+   * parent classes have no class closure for this event.
+   */
+
+  return FALSE;
+}
 
 static gboolean
-aisleriot_board_tap_and_hold_query_cb (GtkWidget *widget,
-                                       GdkEvent *_event,
-                                       AisleriotBoard *board)
+aisleriot_board_leave (ClutterActor *actor,
+                       ClutterCrossingEvent *event)
 {
-  AisleriotBoardPrivate *priv = board->priv;
-  /* BadDocs! should mention that this is a GdkEventButton! */
-  GdkEventButton *event = (GdkEventButton *) _event;
-  Slot *slot;
-  int card_id;
+  AisleriotBoard *board = AISLERIOT_BOARD (actor);
 
-  /* NOTE: Returning TRUE from this function means that tap-and-hold
-   * is disallowed here; FALSE means to allow tap-and-hold.
-   */
+  _games_debug_print (GAMES_DEBUG_GAME_EVENTS,
+                      "board ::leave @(%f / %f)\n",
+                      event->x, event->y);
 
-  /* In click-to-move mode, we always reveal with just the left click */
-  if (priv->click_to_move)
-    return TRUE;
-
-  get_slot_and_card_from_point (board, event->x, event->y, &slot, &card_id);
-  if (!slot ||
-      card_id < 0 ||
-      card_id == slot->cards->len - 1 ||
-      CARD_GET_FACE_DOWN (CARD (slot->cards->data[card_id])))
-    return TRUE;
+  /* NOTE: It's ok to just return instead of chaining up, since the
+   * parent classes have no class closure for this event.
+   */
 
-  priv->tap_and_hold_slot = slot;
-  priv->tap_and_hold_card_id = card_id;
+  set_cursor (board, AR_CURSOR_DEFAULT);
 
-  return FALSE; /* chain up to the default handler */
+  return FALSE;
 }
 
 static void
-aisleriot_board_tap_and_hold_cb (GtkWidget *widget,
-                                 AisleriotBoard *board)
+aisleriot_board_key_focus_in (ClutterActor *actor)
 {
-  AisleriotBoardPrivate *priv = board->priv;
-
-  if (priv->tap_and_hold_slot == NULL ||
-      priv->tap_and_hold_card_id < 0)
-    return;
-
-  reveal_card (board, priv->tap_and_hold_slot, priv->tap_and_hold_card_id);
+  _games_debug_print (GAMES_DEBUG_GAME_EVENTS,
+                      "board ::key-focus-in\n");
 }
 
-#endif /* HAVE_MAEMO */
+static void
+aisleriot_board_key_focus_out (ClutterActor *actor)
+{
+  _games_debug_print (GAMES_DEBUG_GAME_EVENTS,
+                      "board ::key-focus-out\n");
+}
 
 /* GObjectClass methods */
 
 static void
 aisleriot_board_init (AisleriotBoard *board)
 {
-  GtkWidget *widget = GTK_WIDGET (board);
+  ClutterActor *actor = CLUTTER_ACTOR (board);
   AisleriotBoardPrivate *priv;
-  ClutterActor *stage;
 
   priv = board->priv = AISLERIOT_BOARD_GET_PRIVATE (board);
 
-  gtk_widget_set_name (widget, "aisleriot-board");
+  memset (&priv->allocation, 0, sizeof (ClutterActorBox));
 
-  GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
-
-  priv->is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+  /* We want to receive events! */
+  clutter_actor_set_reactive (actor, TRUE);
 
   priv->force_geometry_update = FALSE;
 
   priv->click_to_move = FALSE;
   priv->show_selection = FALSE;
-  priv->animation_mode = FALSE;
 
   priv->show_card_id = -1;
 
@@ -3198,25 +3051,8 @@ aisleriot_board_init (AisleriotBoard *board)
 
   priv->removed_cards = g_array_new (FALSE, FALSE, sizeof (RemovedCard));
 
-  gtk_widget_set_events (widget,
-			 gtk_widget_get_events (widget) |
-                         GDK_EXPOSURE_MASK |
-                         GDK_BUTTON_PRESS_MASK |
-                         GDK_POINTER_MOTION_MASK |
-                         GDK_BUTTON_RELEASE_MASK);
-  /* FIMXEchpe: no need for motion events on maemo, unless we explicitly activate drag mode */
-
-#ifdef HAVE_MAEMO
-  gtk_widget_tap_and_hold_setup (widget, NULL, NULL, GTK_TAP_AND_HOLD_PASS_PRESS);
-  g_signal_connect (widget, "tap-and-hold-query",
-                    G_CALLBACK (aisleriot_board_tap_and_hold_query_cb), board);
-  g_signal_connect (widget, "tap-and-hold",
-                    G_CALLBACK (aisleriot_board_tap_and_hold_cb), board);
-#endif /* HAVE_MAEMO */
-
-  stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (board));
   priv->animation_layer = g_object_ref_sink (clutter_group_new ());
-  clutter_container_add (CLUTTER_CONTAINER (stage),
+  clutter_container_add (CLUTTER_CONTAINER (board),
                          priv->animation_layer, NULL);
 }
 
@@ -3235,6 +3071,7 @@ aisleriot_board_constructor (GType type,
   board = AISLERIOT_BOARD (object);
   priv = board->priv;
 
+  g_assert (priv->style != NULL);
   g_assert (priv->game != NULL);
 
   priv->textures = games_card_textures_cache_new ();
@@ -3257,8 +3094,12 @@ aisleriot_board_finalize (GObject *object)
 
   g_byte_array_free (priv->moving_cards, TRUE);
 
-  if (priv->theme) {
-    g_object_unref (priv->theme);
+  if (priv->style != NULL) {
+    g_signal_handlers_disconnect_matched (priv->style,
+                                          G_SIGNAL_MATCH_DATA,
+                                          0, 0, NULL, NULL, board);
+
+    g_object_unref (priv->style);
   }
 
 #if 0
@@ -3277,12 +3118,6 @@ aisleriot_board_dispose (GObject *object)
   AisleriotBoard *board = AISLERIOT_BOARD (object);
   AisleriotBoardPrivate *priv = board->priv;
 
-  if (priv->baize_actor) {
-    clutter_actor_destroy (priv->baize_actor);
-    g_object_unref (priv->baize_actor);
-    priv->baize_actor = NULL;
-  }
-
   if (priv->textures) {
     g_object_unref (priv->textures);
     priv->textures = NULL;
@@ -3302,21 +3137,6 @@ aisleriot_board_dispose (GObject *object)
 }
 
 static void
-aisleriot_board_get_property (GObject *object,
-                              guint prop_id,
-                              GValue *value,
-                              GParamSpec *pspec)
-{
-  AisleriotBoard *board = AISLERIOT_BOARD (object);
-
-  switch (prop_id) {
-    case PROP_THEME:
-      g_value_set_object (value, aisleriot_board_get_card_theme (board));
-      break;
-  }
-}
-
-static void
 aisleriot_board_set_property (GObject *object,
                               guint prop_id,
                               const GValue *value,
@@ -3339,9 +3159,17 @@ aisleriot_board_set_property (GObject *object,
                         G_CALLBACK (slot_changed_cb), board);
 
       break;
-    case PROP_THEME:
-      aisleriot_board_set_card_theme (board, g_value_get_object (value));
+
+    case PROP_STYLE:
+      priv->style = g_value_dup_object (value);
+
+      aisleriot_board_sync_style (priv->style, NULL, board);
+      g_signal_connect (priv->style, "notify",
+                        G_CALLBACK (aisleriot_board_sync_style), board);
       break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   }
 }
 
@@ -3349,9 +3177,10 @@ static void
 aisleriot_board_class_init (AisleriotBoardClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
 #ifdef ENABLE_KEYNAV
-  GtkBindingSet *binding_set;
+  ClutterBindingPool *binding_pool;
+  GClosure *closure;
 #endif
 
   g_type_class_add_private (gobject_class, sizeof (AisleriotBoardPrivate));
@@ -3360,30 +3189,63 @@ aisleriot_board_class_init (AisleriotBoardClass *klass)
   gobject_class->dispose = aisleriot_board_dispose;
   gobject_class->finalize = aisleriot_board_finalize;
   gobject_class->set_property = aisleriot_board_set_property;
-  gobject_class->get_property = aisleriot_board_get_property;
 
+#ifdef FIXMEchpe
   widget_class->realize = aisleriot_board_realize;
   widget_class->unrealize = aisleriot_board_unrealize;
-  widget_class->screen_changed = aisleriot_board_screen_changed;
-  widget_class->style_set = aisleriot_board_style_set;
-  widget_class->direction_changed = aisleriot_board_direction_changed;
-  widget_class->size_allocate = aisleriot_board_size_allocate;
-  widget_class->size_request = aisleriot_board_size_request;
-#ifdef ENABLE_KEYNAV
-  widget_class->focus = aisleriot_board_focus;
-#endif /* ENABLE_KEYNAV */
   widget_class->focus_in_event = aisleriot_board_focus_in;
   widget_class->focus_out_event = aisleriot_board_focus_out;
-  widget_class->button_press_event = aisleriot_board_button_press;
-  widget_class->button_release_event = aisleriot_board_button_release;
-  widget_class->motion_notify_event = aisleriot_board_motion_notify;
-  widget_class->key_press_event = aisleriot_board_key_press;
-#ifdef HAVE_MAEMO
-  widget_class->tap_and_hold_query = aisleriot_board_tap_and_hold_query;
-  widget_class->tap_and_hold = aisleriot_board_tap_and_hold;
-#endif /* HAVE_MAEMO */
+#endif // FIXMEchpe
 
+  actor_class->allocate = aisleriot_board_allocate;
+  actor_class->get_preferred_width = aisleriot_board_get_preferred_width;
+  actor_class->get_preferred_height = aisleriot_board_get_preferred_height;
 #ifdef ENABLE_KEYNAV
+  actor_class->key_press_event = aisleriot_board_key_press;
+#endif /* ENABLE_KEYNAV */
+  actor_class->button_press_event = aisleriot_board_button_press;
+  actor_class->button_release_event = aisleriot_board_button_release;
+  actor_class->motion_event = aisleriot_board_motion;
+  actor_class->enter_event = aisleriot_board_enter;
+  actor_class->leave_event = aisleriot_board_leave;
+  actor_class->key_focus_in = aisleriot_board_key_focus_in;
+  actor_class->key_focus_out = aisleriot_board_key_focus_out;
+
+
+  signals[REQUEST_CURSOR] =
+    g_signal_new (I_("request-cursor"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (AisleriotBoardClass, request_cursor),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__INT,
+                  G_TYPE_NONE,
+                  1,
+                  G_TYPE_INT);
+
+  signals[ERROR_BELL] =
+    g_signal_new (I_("error-bell"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (AisleriotBoardClass, request_cursor),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE,
+                  0);
+
+  signals[ERROR_BELL] =
+    g_signal_new (I_("focus"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (AisleriotBoardClass, focus),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__INT,
+                  G_TYPE_BOOLEAN,
+                  1,
+                  G_TYPE_INT);
+
+#ifdef ENABLE_KEYNAV
+  klass->focus = aisleriot_board_focus;
   klass->activate = aisleriot_board_activate;
   klass->move_cursor = aisleriot_board_move_cursor;
   klass->select_all = aisleriot_board_select_all;
@@ -3391,15 +3253,21 @@ aisleriot_board_class_init (AisleriotBoardClass *klass)
   klass->toggle_selection = aisleriot_board_toggle_selection;
 
   /* Keybinding signals */
-  widget_class->activate_signal = signals[ACTIVATE] =
+#ifdef FIXMEchpe
+  widget_class->activate_signal =
+#endif
+  signals[ACTIVATE] =
     g_signal_new (I_("activate"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (AisleriotBoardClass, activate),
                   NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE,
-                  0);
+                  games_marshal_BOOLEAN__STRING_UINT_ENUM,
+                  G_TYPE_BOOLEAN,
+                  3,
+                  G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+                  G_TYPE_UINT,
+                  CLUTTER_TYPE_MODIFIER_TYPE);
 
   signals[MOVE_CURSOR] =
     g_signal_new (I_("move-cursor"),
@@ -3407,11 +3275,12 @@ aisleriot_board_class_init (AisleriotBoardClass *klass)
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (AisleriotBoardClass, move_cursor),
                   NULL, NULL,
-                  games_marshal_BOOLEAN__ENUM_INT,
+                  games_marshal_BOOLEAN__STRING_UINT_ENUM,
                   G_TYPE_BOOLEAN,
-                  2,
-                  GTK_TYPE_MOVEMENT_STEP,
-                  G_TYPE_INT);
+                  3,
+                  G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+                  G_TYPE_UINT,
+                  CLUTTER_TYPE_MODIFIER_TYPE);
 
   signals[TOGGLE_SELECTION] =
     g_signal_new (I_("toggle-selection"),
@@ -3419,9 +3288,12 @@ aisleriot_board_class_init (AisleriotBoardClass *klass)
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (AisleriotBoardClass, toggle_selection),
                   NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE,
-                  0);
+                  games_marshal_BOOLEAN__STRING_UINT_ENUM,
+                  G_TYPE_BOOLEAN,
+                  3,
+                  G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+                  G_TYPE_UINT,
+                  CLUTTER_TYPE_MODIFIER_TYPE);
 
   signals[SELECT_ALL] =
     g_signal_new (I_("select-all"),
@@ -3429,9 +3301,12 @@ aisleriot_board_class_init (AisleriotBoardClass *klass)
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (AisleriotBoardClass, select_all),
                   NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE,
-                  0);
+                  games_marshal_BOOLEAN__STRING_UINT_ENUM,
+                  G_TYPE_BOOLEAN,
+                  3,
+                  G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+                  G_TYPE_UINT,
+                  CLUTTER_TYPE_MODIFIER_TYPE);
 
   signals[DESELECT_ALL] =
     g_signal_new (I_("deselect-all"),
@@ -3439,9 +3314,12 @@ aisleriot_board_class_init (AisleriotBoardClass *klass)
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (AisleriotBoardClass, deselect_all),
                   NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE,
-                  0);
+                  games_marshal_BOOLEAN__STRING_UINT_ENUM,
+                  G_TYPE_BOOLEAN,
+                  3,
+                  G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+                  G_TYPE_UINT,
+                  CLUTTER_TYPE_MODIFIER_TYPE);
 #endif /* ENABLE_KEYNAV */
 
   /* Properties */
@@ -3450,195 +3328,148 @@ aisleriot_board_class_init (AisleriotBoardClass *klass)
      PROP_GAME,
      g_param_spec_object ("game", NULL, NULL,
                           AISLERIOT_TYPE_GAME,
-                          G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT_ONLY));
+                          G_PARAM_WRITABLE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property
     (gobject_class,
-     PROP_THEME,
-     g_param_spec_object ("theme", NULL, NULL,
-                          GAMES_TYPE_CARD_THEME,
-                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
-
-  gtk_widget_class_install_style_property
-    (widget_class,
-     g_param_spec_boxed ("selection-color", NULL, NULL,
-                         GDK_TYPE_COLOR,
-                         G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
-
-  /**
-   * AisleriotBoard:card-slot-ratio:
-   *
-   * The ratio of card to slot size. Note that this is the ratio of
-   * card width/slot width and card height/slot height, not of
-   * card area/slot area.
-  */
-  gtk_widget_class_install_style_property
-    (widget_class,
-     g_param_spec_double ("card-slot-ratio", NULL, NULL,
-                          0.1, 1.0, DEFAULT_CARD_SLOT_RATIO,
-                          G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+     PROP_STYLE,
+     g_param_spec_object ("style", NULL, NULL,
+                          AR_TYPE_STYLE,
+                          G_PARAM_WRITABLE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
 
 #ifdef ENABLE_KEYNAV
   /* Keybindings */
-  binding_set = gtk_binding_set_by_class (klass);
+  binding_pool = clutter_binding_pool_get_for_class (klass);
 
   /* Cursor movement */
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_Left, 0,
-                                               GTK_MOVEMENT_VISUAL_POSITIONS, -1);
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_KP_Left, 0,
-                                               GTK_MOVEMENT_VISUAL_POSITIONS, -1);
-
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_Right, 0,
-                                               GTK_MOVEMENT_VISUAL_POSITIONS, 1);
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_KP_Right, 0,
-                                               GTK_MOVEMENT_VISUAL_POSITIONS, 1);
+  closure = g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (klass),
+                                        G_STRUCT_OFFSET (AisleriotBoardClass, move_cursor));
+
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_LEFT_RIGHT_S MOVE_LEFT_S),
+                                               CLUTTER_Left, 0);
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_LEFT_RIGHT_S MOVE_LEFT_S),
+                                               CLUTTER_KP_Left, 0);
+
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_LEFT_RIGHT_S MOVE_RIGHT_S),
+                                               CLUTTER_Right, 0);
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_LEFT_RIGHT_S MOVE_RIGHT_S),
+                                               CLUTTER_KP_Right, 0);
   
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_Up, 0,
-                                               GTK_MOVEMENT_DISPLAY_LINES, -1);
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_KP_Up, 0,
-                                               GTK_MOVEMENT_DISPLAY_LINES, -1);
-
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_Down, 0,
-                                               GTK_MOVEMENT_DISPLAY_LINES, 1);
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_KP_Down, 0,
-                                               GTK_MOVEMENT_DISPLAY_LINES, 1);
-
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_Home, 0,
-                                               GTK_MOVEMENT_BUFFER_ENDS, -1);
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_KP_Home, 0,
-                                               GTK_MOVEMENT_BUFFER_ENDS, -1);
-
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_End, 0,
-                                               GTK_MOVEMENT_BUFFER_ENDS, 1);
-  aisleriot_board_add_move_and_select_binding (binding_set, GDK_KP_End, 0,
-                                               GTK_MOVEMENT_BUFFER_ENDS, 1);
-
-  aisleriot_board_add_move_binding (binding_set, GDK_Page_Up, 0,
-                                    GTK_MOVEMENT_PAGES, -1);
-  aisleriot_board_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
-                                    GTK_MOVEMENT_PAGES, -1);
-
-  aisleriot_board_add_move_binding (binding_set, GDK_Page_Down, 0,
-                                    GTK_MOVEMENT_PAGES, 1);
-  aisleriot_board_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
-                                    GTK_MOVEMENT_PAGES, 1);
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_UP_DOWN_S MOVE_LEFT_S),
+                                               CLUTTER_Up, 0);
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_UP_DOWN_S MOVE_LEFT_S),
+                                               CLUTTER_KP_Up, 0);
+
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_UP_DOWN_S MOVE_RIGHT_S),
+                                               CLUTTER_Down, 0);
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_UP_DOWN_S MOVE_RIGHT_S),
+                                               CLUTTER_KP_Down, 0);
+
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_START_END_S MOVE_LEFT_S),
+                                               CLUTTER_Home, 0);
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_START_END_S MOVE_LEFT_S),
+                                               CLUTTER_KP_Home, 0);
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_START_END_S MOVE_LEFT_S),
+                                               CLUTTER_Begin, 0);
+
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_START_END_S MOVE_RIGHT_S),
+                                               CLUTTER_End, 0);
+  aisleriot_board_add_move_and_select_binding (binding_pool, closure,
+                                               I_(MOVE_CURSOR_START_END_S MOVE_RIGHT_S),
+                                               CLUTTER_KP_End, 0);
+
+  aisleriot_board_add_move_binding (binding_pool, closure,
+                                    I_(MOVE_CURSOR_PAGES_S MOVE_LEFT_S),
+                                    CLUTTER_Page_Up, 0);
+  aisleriot_board_add_move_binding (binding_pool, closure,
+                                    I_(MOVE_CURSOR_PAGES_S MOVE_LEFT_S),
+                                    CLUTTER_KP_Page_Up, 0);
+
+  aisleriot_board_add_move_binding (binding_pool, closure,
+                                    I_(MOVE_CURSOR_PAGES_S MOVE_RIGHT_S),
+                                    CLUTTER_Page_Down, 0);
+  aisleriot_board_add_move_binding (binding_pool, closure,
+                                    I_(MOVE_CURSOR_PAGES_S MOVE_RIGHT_S),
+                                    CLUTTER_KP_Page_Down, 0);
+
+  g_closure_unref (closure);
 
   /* Selection */
-  gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
-                                "toggle-selection", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0,
-                                "toggle-selection", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
-                                "select-all", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                "deselect-all", 0);
+  closure = g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (klass),
+                                        G_STRUCT_OFFSET (AisleriotBoardClass, toggle_selection));
+
+  clutter_binding_pool_install_closure (binding_pool,
+                                        I_("toggle-selection"),
+                                        CLUTTER_space,
+                                        0,
+                                       closure);
+  clutter_binding_pool_install_closure (binding_pool,
+                                        I_("toggle-selection"),
+                                        CLUTTER_KP_Space,
+                                        0,
+                                        closure);
+  g_closure_unref (closure);
+
+  closure = g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (klass),
+                                        G_STRUCT_OFFSET (AisleriotBoardClass, select_all));
+  clutter_binding_pool_install_closure (binding_pool,
+                                        I_("select-all"),
+                                        CLUTTER_a,
+                                        CLUTTER_CONTROL_MASK,
+                                        closure);
+  g_closure_unref (closure);
+
+  closure = g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (klass),
+                                        G_STRUCT_OFFSET (AisleriotBoardClass, deselect_all));
+  clutter_binding_pool_install_closure (binding_pool,
+                                        I_("deselect-all"),
+                                        CLUTTER_a,
+                                        CLUTTER_CONTROL_MASK | CLUTTER_SHIFT_MASK,
+                                        closure);
+  g_closure_unref (closure);
 
   /* Activate */
-  aisleriot_board_add_activate_binding (binding_set, GDK_Return, 0);
-  aisleriot_board_add_activate_binding (binding_set, GDK_ISO_Enter, 0);
-  aisleriot_board_add_activate_binding (binding_set, GDK_KP_Enter, 0);
+  closure = g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (klass),
+                                        G_STRUCT_OFFSET (AisleriotBoardClass, activate));
+
+  aisleriot_board_add_activate_binding (binding_pool, closure, CLUTTER_Return, 0);
+  aisleriot_board_add_activate_binding (binding_pool, closure, CLUTTER_ISO_Enter, 0);
+  aisleriot_board_add_activate_binding (binding_pool, closure, CLUTTER_KP_Enter, 0);
+
+  g_closure_unref (closure);
 #endif /* ENABLE_KEYNAV */
 }
 
 /* public API */
 
-GtkWidget *
-aisleriot_board_new (AisleriotGame *game)
+ClutterActor *
+aisleriot_board_new (ArStyle *style,
+                     AisleriotGame *game)
 {
   return g_object_new (AISLERIOT_TYPE_BOARD,
+                       "style", style,
                        "game", game,
                        NULL);
 }
 
 void
-aisleriot_board_set_card_theme (AisleriotBoard *board,
-                                GamesCardTheme *theme)
-{
-  AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
-
-  g_return_if_fail (AISLERIOT_IS_BOARD (board));
-  g_return_if_fail (GAMES_IS_CARD_THEME (theme));
-
-  if (theme == priv->theme)
-    return;
-
-  if (priv->theme) {
-    g_object_unref (priv->theme);
-  }
-
-  priv->geometry_set = FALSE;
-
-  priv->theme = g_object_ref (theme);
-
-  games_card_textures_cache_set_theme (priv->textures, priv->theme);
-
-  if (GTK_WIDGET_REALIZED (widget)) {
-    /* Update card size and slot locations for new card theme (might have changed aspect!)*/
-    aisleriot_board_setup_geometry (board);
-
-    gtk_widget_queue_draw (widget);
-  }
-
-  g_object_notify (G_OBJECT (board), "theme");
-}
-
-GamesCardTheme *
-aisleriot_board_get_card_theme (AisleriotBoard *board)
-{
-  AisleriotBoardPrivate *priv = board->priv;
-
-  return priv->theme;
-}
-
-void
-aisleriot_board_set_click_to_move (AisleriotBoard *board,
-                                   gboolean click_to_move)
-{
-  AisleriotBoardPrivate *priv = board->priv;
-  GtkWidget *widget = GTK_WIDGET (board);
-
-  click_to_move = click_to_move != FALSE;
-  if (priv->click_to_move == click_to_move)
-    return;
-
-  /* Clear the selection. Do this before setting the new value,
-   * since otherwise selection won't get cleared correctly.
-   */
-  set_selection (board, NULL, -1, FALSE);
-
-  priv->click_to_move = click_to_move;
-
-  /* FIXMEchpe why? */
-  if (GTK_WIDGET_REALIZED (widget)) {
-    gtk_widget_queue_draw (widget);
-  }
-}
-
-void
-aisleriot_board_set_animation_mode (AisleriotBoard *board,
-                                    gboolean enabled)
-{
-  AisleriotBoardPrivate *priv = board->priv;
-
-  enabled = enabled != FALSE;
-  if (priv->animation_mode == enabled)
-    return;
-
-  priv->animation_mode = enabled;
-
-  /* FIXME: stop in-progress animations? */
-}
-
-void
 aisleriot_board_abort_move (AisleriotBoard *board)
 {
   clear_state (board);
 }
-
-void
-aisleriot_board_set_pixbuf_drawing (AisleriotBoard *board,
-                                    gboolean use_pixbuf_drawing)
-{
-  /* makes no sense for Clutter */
-}
diff --git a/aisleriot/board.h b/aisleriot/board.h
index bab8997..908fceb 100644
--- a/aisleriot/board.h
+++ b/aisleriot/board.h
@@ -19,14 +19,14 @@
 #ifndef AISLERIOT_BOARD_H
 #define AISLERIOT_BOARD_H
 
-#include <gtk/gtk.h>
-
-#ifdef HAVE_CLUTTER
-#include <clutter-gtk/clutter-gtk.h>
+#ifndef HAVE_CLUTTER
+#error board.h requires clutter
 #endif
 
-#include <libgames-support/games-card-theme.h>
+#include <clutter/clutter.h>
 
+#include "ar-style.h"
+#include "ar-cursor.h"
 #include "game.h"
 
 G_BEGIN_DECLS
@@ -43,52 +43,53 @@ typedef struct _AisleriotBoardPrivate	AisleriotBoardPrivate;
 typedef struct _AisleriotBoardClass	AisleriotBoardClass;
 
 struct _AisleriotBoard {
-#ifdef HAVE_CLUTTER
-  GtkClutterEmbed parent_instance;
-#else
-  GtkDrawingArea parent_instance;
-#endif
+  ClutterGroup parent_instance;
 
   /*< private >*/
   AisleriotBoardPrivate *priv;
 };
 
 struct _AisleriotBoardClass {
-#ifdef HAVE_CLUTTER
-  GtkClutterEmbedClass parent_class;
-#else
-  GtkDrawingAreaClass parent_class;
-#endif
+  ClutterGroupClass parent_class;
 
-  /* keybinding signals */
-  gboolean (* move_cursor)  (AisleriotBoard *board,
-                             GtkMovementStep step,
-                             int count);
-  void (* activate)         (AisleriotBoard *board);
-  void (* toggle_selection) (AisleriotBoard *board);
-  void (* select_all)       (AisleriotBoard *board);
-  void (* deselect_all)     (AisleriotBoard *board);
-};
+  void (* request_cursor)   (AisleriotBoard *board,
+                             ArCursorType cursor_type);
 
-GType aisleriot_board_get_type (void);
+  void (* error_bell)       (AisleriotBoard *board);
 
-GtkWidget *aisleriot_board_new (AisleriotGame *game);
+  /* Focus */
+  gboolean (* focus)        (AisleriotBoard *,
+                             int direction);
 
-void aisleriot_board_set_card_theme (AisleriotBoard * board,
-                                     GamesCardTheme *theme);
-
-GamesCardTheme *aisleriot_board_get_card_theme (AisleriotBoard * board);
-
-void aisleriot_board_set_click_to_move (AisleriotBoard * board,
-                                        gboolean click_to_move);
+  /* keybinding signals */
+  gboolean (* move_cursor)  (AisleriotBoard *,
+                             const char *,
+                             guint,
+                             ClutterModifierType);
+  void (* activate)         (AisleriotBoard *,
+                             const char *,
+                             guint,
+                             ClutterModifierType);
+  void (* toggle_selection) (AisleriotBoard *,
+                             const char *,
+                             guint,
+                             ClutterModifierType);
+  void (* select_all)       (AisleriotBoard *,
+                             const char *,
+                             guint,
+                             ClutterModifierType);
+  void (* deselect_all)     (AisleriotBoard *,
+                             const char *,
+                             guint,
+                             ClutterModifierType);
+};
 
-void aisleriot_board_set_animation_mode (AisleriotBoard *board,
-                                         gboolean enable);
+GType aisleriot_board_get_type (void);
 
-void aisleriot_board_abort_move (AisleriotBoard * board);
+ClutterActor *aisleriot_board_new (ArStyle *style,
+                                   AisleriotGame *game);
 
-void aisleriot_board_set_pixbuf_drawing (AisleriotBoard * board,
-                                         gboolean use_pixbuf_drawing);
+void aisleriot_board_abort_move (AisleriotBoard *board);
 
 G_END_DECLS
 
diff --git a/aisleriot/card.c b/aisleriot/card.c
index d7c1ef9..0a56fe4 100644
--- a/aisleriot/card.c
+++ b/aisleriot/card.c
@@ -95,30 +95,21 @@ aisleriot_card_class_init (AisleriotCardClass *klass)
 
   pspec = g_param_spec_uchar ("bottom-card", NULL, NULL,
                               0, 255, 0,
-                              G_PARAM_WRITABLE |
-                              G_PARAM_READABLE |
-                              G_PARAM_STATIC_NAME |
-                              G_PARAM_STATIC_NICK |
-                              G_PARAM_STATIC_BLURB);
+                              G_PARAM_READWRITE |
+                              G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (gobject_class, PROP_BOTTOM_CARD, pspec);
 
   pspec = g_param_spec_uchar ("top-card", NULL, NULL,
                               0, 255, 0,
-                              G_PARAM_WRITABLE |
-                              G_PARAM_READABLE |
-                              G_PARAM_STATIC_NAME |
-                              G_PARAM_STATIC_NICK |
-                              G_PARAM_STATIC_BLURB);
+                              G_PARAM_READWRITE |
+                              G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (gobject_class, PROP_TOP_CARD, pspec);
 
   pspec = g_param_spec_object ("cache", NULL, NULL,
                                GAMES_TYPE_CARD_TEXTURES_CACHE,
-                               G_PARAM_WRITABLE |
-                               G_PARAM_READABLE |
+                               G_PARAM_READWRITE |
                                G_PARAM_CONSTRUCT_ONLY |
-                               G_PARAM_STATIC_NAME |
-                               G_PARAM_STATIC_NICK |
-                               G_PARAM_STATIC_BLURB);
+                               G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (gobject_class, PROP_CACHE, pspec);
 
   g_type_class_add_private (klass, sizeof (AisleriotCardPrivate));
diff --git a/aisleriot/game.c b/aisleriot/game.c
index 39dd9c2..c48ac7b 100644
--- a/aisleriot/game.c
+++ b/aisleriot/game.c
@@ -44,8 +44,6 @@
 
 #include "game.h"
 
-#include "board.h"
-
 #define DELAYED_CALLBACK_DELAY (50)
 
 #if GLIB_CHECK_VERSION (2, 10, 0)
@@ -239,7 +237,7 @@ clear_slots (AisleriotGame *game,
 
   n_slots = game->slots->len;
   for (i = 0; i < n_slots; ++i) {
-    Slot *slot = game->slots->pdata[i];
+    ArSlot *slot = game->slots->pdata[i];
 
 #ifdef HAVE_CLUTTER
     if (slot->slot_renderer) {
@@ -254,7 +252,7 @@ clear_slots (AisleriotGame *game,
     g_byte_array_free (slot->cards, TRUE);
 
 #if GLIB_CHECK_VERSION (2, 10, 0)
-    g_slice_free (Slot, slot);
+    g_slice_free (ArSlot, slot);
 #else
     g_free (slot);
 #endif
@@ -267,7 +265,7 @@ clear_slots (AisleriotGame *game,
   }
 }
 
-static Slot *
+static ArSlot *
 get_slot (AisleriotGame *game,
           gint slotid)
 {
@@ -275,7 +273,7 @@ get_slot (AisleriotGame *game,
 
   n_slots = game->slots->len;
   for (i = 0; i < n_slots; ++i) {
-    Slot *hslot = game->slots->pdata[i];
+    ArSlot *hslot = game->slots->pdata[i];
 
     if (hslot->id == slotid)
       return hslot;
@@ -347,7 +345,7 @@ cscmi_exception_get_backtrace (SCM tag, SCM throw_args)
   n_slots = slots->len;
   if (n_slots > 0) {
     for (i = 0; i < n_slots; ++i) {
-      Slot *slot = slots->pdata[i];
+      ArSlot *slot = slots->pdata[i];
       GByteArray *cards = slot->cards;
       guint n_cards;
 
@@ -529,7 +527,7 @@ c2scm_deck (guint8 *cards,
 }
 
 static void
-cscmi_slot_set_cards (Slot *slot,
+cscmi_slot_set_cards (ArSlot *slot,
                       SCM cards)
 {
   AisleriotGame *game = app_game;
@@ -569,7 +567,7 @@ static SCM
 cscmi_add_slot (SCM slot_data)
 {
   AisleriotGame *game = app_game;
-  Slot *slot;
+  ArSlot *slot;
   gboolean expanded_down = FALSE;
   gboolean expanded_right = FALSE;
   int expansion_depth = 0;
@@ -633,7 +631,7 @@ cscmi_add_slot (SCM slot_data)
 
   /* create and initialize slot */
 #if GLIB_CHECK_VERSION (2, 10, 0)
-  slot = g_slice_new0 (Slot);
+  slot = g_slice_new0 (ArSlot);
 #else
   slot = g_new0 (Slot, 1);
 #endif
@@ -789,7 +787,7 @@ scm_set_slot_x_expansion (SCM scm_slot_id,
                           SCM new_exp_val)
 {
   AisleriotGame *game = app_game;
-  Slot *slot;
+  ArSlot *slot;
 
   slot = get_slot (game, scm_num2int (scm_slot_id, SCM_ARG1, NULL));
 
@@ -813,7 +811,7 @@ scm_set_slot_y_expansion (SCM scm_slot_id,
                           SCM new_exp_val)
 {
   AisleriotGame *game = app_game;
-  Slot *slot;
+  ArSlot *slot;
 
   slot = get_slot (game, scm_num2int (scm_slot_id, SCM_ARG1, NULL));
 
@@ -836,7 +834,7 @@ static SCM
 scm_get_slot (SCM scm_slot_id)
 {
   AisleriotGame *game = app_game;
-  Slot *slot;
+  ArSlot *slot;
 
   slot = get_slot (game, scm_num2int (scm_slot_id, SCM_ARG1, NULL));
 
@@ -853,7 +851,7 @@ scm_set_cards (SCM scm_slot_id,
                SCM new_cards)
 {
   AisleriotGame *game = app_game;
-  Slot *slot;
+  ArSlot *slot;
 
   slot = get_slot (game, scm_num2int (scm_slot_id, SCM_ARG1, NULL));
 
@@ -1439,7 +1437,7 @@ aisleriot_game_get_slots (AisleriotGame *game)
  */
 void
 aisleriot_game_slot_add_cards (AisleriotGame *game,
-                               Slot *slot,
+                               ArSlot *slot,
                                guint8 *cards,
                                guint n_cards)
 {
@@ -2396,7 +2394,7 @@ aisleriot_game_deal_cards (AisleriotGame *game)
 #ifdef HAVE_CLUTTER
 
 void
-aisleriot_game_get_card_offset (Slot *slot,
+aisleriot_game_get_card_offset (ArSlot *slot,
                                 guint card_num,
                                 gboolean old_cards,
                                 gint *xoff, gint *yoff)
@@ -2422,7 +2420,7 @@ aisleriot_game_get_card_offset (Slot *slot,
 }
 
 void
-aisleriot_game_reset_old_cards (Slot *slot)
+aisleriot_game_reset_old_cards (ArSlot *slot)
 {
   g_byte_array_set_size (slot->old_cards, 0);
   g_byte_array_append (slot->old_cards, slot->cards->data, slot->cards->len);
diff --git a/aisleriot/game.h b/aisleriot/game.h
index 2e778ea..f76c262 100644
--- a/aisleriot/game.h
+++ b/aisleriot/game.h
@@ -83,7 +83,7 @@ typedef struct {
   guint dx_set : 1;
   guint dy_set : 1;
   guint needs_update : 1;
-} Slot;
+} ArSlot;
 
 #define SLOT_CARDS_N_PREALLOC (32)
 
@@ -151,7 +151,7 @@ AisleriotGame *aisleriot_game_new (void);
 GPtrArray *aisleriot_game_get_slots (AisleriotGame * game);
 
 void aisleriot_game_slot_add_cards (AisleriotGame * game,
-                                    Slot * slot,
+                                    ArSlot * slot,
                                     guint8 * cards, guint n_cards);
 
 guint aisleriot_game_get_state (AisleriotGame * game);
@@ -228,12 +228,12 @@ void aisleriot_game_generate_exception (AisleriotGame * game);
 
 void aisleriot_game_deal_cards (AisleriotGame *game);
 
-void aisleriot_game_get_card_offset (Slot *slot,
+void aisleriot_game_get_card_offset (ArSlot *slot,
                                      guint card_num,
                                      gboolean old_cards,
                                      gint *xoff, gint *yoff);
 
-void aisleriot_game_reset_old_cards (Slot *slot);
+void aisleriot_game_reset_old_cards (ArSlot *slot);
 
 G_END_DECLS
 
diff --git a/aisleriot/slot-renderer.c b/aisleriot/slot-renderer.c
index 4a829f9..3e60672 100644
--- a/aisleriot/slot-renderer.c
+++ b/aisleriot/slot-renderer.c
@@ -45,7 +45,6 @@ static void aisleriot_slot_renderer_set_cache (AisleriotSlotRenderer *srend,
 
 static void completed_cb (AisleriotSlotRenderer *srend);
 
-static const ClutterColor default_highlight_color = { 0, 0, 0xaa, 0xff };
 
 G_DEFINE_TYPE (AisleriotSlotRenderer, aisleriot_slot_renderer,
                CLUTTER_TYPE_ACTOR);
@@ -58,9 +57,11 @@ typedef struct _AnimationData AnimationData;
 
 struct _AisleriotSlotRendererPrivate
 {
+  ArStyle *style;
+
   GamesCardTexturesCache *cache;
 
-  Slot *slot;
+  ArSlot *slot;
 
   CoglHandle material;
 
@@ -90,13 +91,30 @@ enum
 
   PROP_CACHE,
   PROP_SLOT,
+  PROP_STYLE,
   PROP_HIGHLIGHT,
-  PROP_HIGHLIGHT_COLOR,
   PROP_REVEALED_CARD,
   PROP_ANIMATION_LAYER
 };
 
 static void
+sync_style_selection_color (ArStyle *style,
+                            GParamSpec *pspec,
+                            AisleriotSlotRenderer *srend)
+{
+  AisleriotSlotRendererPrivate *priv = srend->priv;
+  ClutterColor color;
+
+  ar_style_get_selection_color (style, &color);
+  if (clutter_color_equal (&color, &priv->highlight_color))
+    return;
+
+  priv->highlight_color = color;
+
+  /* FIXMEchpe: queue a redraw if necessary! */
+}
+
+static void
 aisleriot_slot_renderer_class_init (AisleriotSlotRendererClass *klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
@@ -111,67 +129,44 @@ aisleriot_slot_renderer_class_init (AisleriotSlotRendererClass *klass)
 
   actor_class->paint = aisleriot_slot_renderer_paint;
 
+  g_object_class_install_property
+    (gobject_class,
+     PROP_STYLE,
+     g_param_spec_object ("style", NULL, NULL,
+                          AR_TYPE_STYLE,
+                          G_PARAM_WRITABLE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
   pspec = g_param_spec_object ("cache", NULL, NULL,
                                GAMES_TYPE_CARD_TEXTURES_CACHE,
                                G_PARAM_WRITABLE |
                                G_PARAM_CONSTRUCT_ONLY |
-                               G_PARAM_STATIC_NAME |
-                               G_PARAM_STATIC_NICK |
-                               G_PARAM_STATIC_BLURB);
+                               G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (gobject_class, PROP_CACHE, pspec);
 
   pspec = g_param_spec_pointer ("slot", NULL, NULL,
                                 G_PARAM_WRITABLE |
                                 G_PARAM_CONSTRUCT_ONLY |
-                                G_PARAM_STATIC_NAME |
-                                G_PARAM_STATIC_NICK |
-                                G_PARAM_STATIC_BLURB);
+                                G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (gobject_class, PROP_SLOT, pspec);
 
   pspec = g_param_spec_int ("highlight", NULL, NULL,
                             -1, G_MAXINT, G_MAXINT,
-                            G_PARAM_WRITABLE |
-                            G_PARAM_READABLE |
-                            G_PARAM_STATIC_NAME |
-                            G_PARAM_STATIC_NICK |
-                            G_PARAM_STATIC_BLURB);
+                               G_PARAM_READWRITE |
+                            G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (gobject_class, PROP_HIGHLIGHT, pspec);
 
-
-#if 0
-  pspec = clutter_param_spec_color ("highlight-color", NULL, NULL,
-                                    &default_highlight_color,
-                                    G_PARAM_WRITABLE |
-                                    G_PARAM_STATIC_NAME |
-                                    G_PARAM_STATIC_NICK |
-                                    G_PARAM_STATIC_BLURB |
-                                    G_PARAM_CONSTRUCT);
-#else
-  pspec = g_param_spec_boxed ("highlight-color", NULL, NULL,
-                              CLUTTER_TYPE_COLOR,
-                              G_PARAM_WRITABLE |
-                              G_PARAM_STATIC_NAME |
-                              G_PARAM_STATIC_NICK |
-                              G_PARAM_STATIC_BLURB);
-#endif
-  g_object_class_install_property (gobject_class, PROP_HIGHLIGHT_COLOR, pspec);
-
   pspec = g_param_spec_int ("revealed-card", NULL, NULL,
                             -1, G_MAXINT, -1,
-                            G_PARAM_WRITABLE |
-                            G_PARAM_READABLE |
-                            G_PARAM_STATIC_NAME |
-                            G_PARAM_STATIC_NICK |
-                            G_PARAM_STATIC_BLURB);
+                            G_PARAM_READWRITE |
+                            G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (gobject_class, PROP_REVEALED_CARD, pspec);
 
   pspec = g_param_spec_object ("animation-layer", NULL, NULL,
                                CLUTTER_TYPE_CONTAINER,
-                               G_PARAM_WRITABLE |
-                               G_PARAM_READABLE |
-                               G_PARAM_STATIC_NAME |
-                               G_PARAM_STATIC_NICK |
-                               G_PARAM_STATIC_BLURB);
+                               G_PARAM_READWRITE |
+                               G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (gobject_class, PROP_ANIMATION_LAYER, pspec);
 
   g_type_class_add_private (klass, sizeof (AisleriotSlotRendererPrivate));
@@ -186,7 +181,6 @@ aisleriot_slot_renderer_init (AisleriotSlotRenderer *self)
 
   priv->revealed_card = -1;
   priv->highlight_start = G_MAXINT;
-  priv->highlight_color = default_highlight_color;
 
   priv->animations = g_array_new (FALSE, FALSE, sizeof (AnimationData));
   priv->timeline = clutter_timeline_new (500);
@@ -223,23 +217,29 @@ aisleriot_slot_renderer_dispose (GObject *object)
 static void
 aisleriot_slot_renderer_finalize (GObject *object)
 {
-  AisleriotSlotRenderer *self = (AisleriotSlotRenderer *) object;
-  AisleriotSlotRendererPrivate *priv = self->priv;
+  AisleriotSlotRenderer *srend = AISLERIOT_SLOT_RENDERER (object);
+  AisleriotSlotRendererPrivate *priv = srend->priv;
 
   g_array_free (priv->animations, TRUE);
 
+  g_signal_handlers_disconnect_by_func (priv->style,
+                                        G_CALLBACK (sync_style_selection_color),
+                                        srend);
+  g_object_unref (priv->style);
+
   G_OBJECT_CLASS (aisleriot_slot_renderer_parent_class)->finalize (object);
 }
 
 ClutterActor *
-aisleriot_slot_renderer_new (GamesCardTexturesCache *cache, Slot *slot)
+aisleriot_slot_renderer_new (ArStyle *style,
+                             GamesCardTexturesCache *cache,
+                             ArSlot *slot)
 {
-  ClutterActor *self = g_object_new (AISLERIOT_TYPE_SLOT_RENDERER,
-                                     "cache", cache,
-                                     "slot", slot,
-                                     NULL);
-
-  return self;
+  return g_object_new (AISLERIOT_TYPE_SLOT_RENDERER,
+                       "style", style,
+                       "cache", cache,
+                       "slot", slot,
+                       NULL);
 }
 
 static void
@@ -278,16 +278,19 @@ aisleriot_slot_renderer_set_property (GObject *object,
       priv->slot = g_value_get_pointer (value);
       break;
 
+    case PROP_STYLE:
+      priv->style = g_value_dup_object (value);
+
+      sync_style_selection_color (priv->style, NULL, srend);
+      g_signal_connect (priv->style, "notify::" AR_STYLE_PROP_SELECTION_COLOR,
+                        G_CALLBACK (sync_style_selection_color), srend);
+      break;
+
     case PROP_HIGHLIGHT:
       aisleriot_slot_renderer_set_highlight (srend,
                                              g_value_get_int (value));
       break;
 
-    case PROP_HIGHLIGHT_COLOR:
-      aisleriot_slot_renderer_set_highlight_color (srend,
-                                                   g_value_get_boxed (value));
-      break;
-
     case PROP_REVEALED_CARD:
       aisleriot_slot_renderer_set_revealed_card (srend,
                                                  g_value_get_int (value));
@@ -328,7 +331,6 @@ aisleriot_slot_renderer_get_property (GObject *object,
                           aisleriot_slot_renderer_get_animation_layer (srend));
       break;
 
-    case PROP_HIGHLIGHT_COLOR:
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -485,22 +487,6 @@ aisleriot_slot_renderer_set_highlight (AisleriotSlotRenderer *srend,
   g_object_notify (G_OBJECT (srend), "highlight");
 }
 
-void
-aisleriot_slot_renderer_set_highlight_color (AisleriotSlotRenderer *srend,
-                                             const ClutterColor *color)
-{
-  AisleriotSlotRendererPrivate *priv = srend->priv;
-
-  g_return_if_fail (color != NULL);
-
-  if (clutter_color_equal (color, &priv->highlight_color))
-    return;
-
-  priv->highlight_color = *color;
-
-  g_object_notify (G_OBJECT (srend), "highlight-color");
-}
-
 gint
 aisleriot_slot_renderer_get_revealed_card (AisleriotSlotRenderer *srend)
 {
diff --git a/aisleriot/slot-renderer.h b/aisleriot/slot-renderer.h
index e2b564c..e96737b 100644
--- a/aisleriot/slot-renderer.h
+++ b/aisleriot/slot-renderer.h
@@ -20,7 +20,9 @@
 
 #include <clutter/clutter.h>
 #include <libgames-support/games-card-textures-cache.h>
+
 #include "game.h"
+#include "ar-style.h"
 
 G_BEGIN_DECLS
 
@@ -71,16 +73,14 @@ struct _AisleriotAnimStart
 
 GType aisleriot_slot_renderer_get_type (void) G_GNUC_CONST;
 
-ClutterActor *aisleriot_slot_renderer_new (GamesCardTexturesCache *cache,
-                                           Slot *slot);
+ClutterActor *aisleriot_slot_renderer_new (ArStyle *style,
+                                           GamesCardTexturesCache *cache,
+                                           ArSlot *slot);
 
 void aisleriot_slot_renderer_set_highlight (AisleriotSlotRenderer *srend,
                                             gint hightlight_start);
 guint aisleriot_slot_renderer_get_highlight (AisleriotSlotRenderer *srend);
 
-void aisleriot_slot_renderer_set_highlight_color (AisleriotSlotRenderer *srend,
-                                                  const ClutterColor *color);
-
 void aisleriot_slot_renderer_set_revealed_card (AisleriotSlotRenderer *srend,
                                                 gint revealed_card);
 gint aisleriot_slot_renderer_get_revealed_card (AisleriotSlotRenderer *srend);
diff --git a/aisleriot/window.c b/aisleriot/window.c
index 59e9032..1e08e53 100644
--- a/aisleriot/window.c
+++ b/aisleriot/window.c
@@ -50,7 +50,15 @@
 #include <libgames-support/games-atk-utils.h>
 #endif
 
+#ifdef HAVE_CLUTTER
+#include "ar-clutter-embed.h"
+#include "ar-style.h"
+#include "baize.h"
 #include "board.h"
+#else
+#include "board-noclutter.h"
+#endif
+
 #include "conf.h"
 #include "game.h"
 #include "stats-dialog.h"
@@ -121,7 +129,14 @@ enum
 struct _AisleriotWindowPrivate
 {
   AisleriotGame *game;
+#ifdef HAVE_CLUTTER
+  ArClutterEmbed *board;
+  ArStyle *board_style;
+  ClutterActor *baize_actor;
+  ClutterActor *board_actor;
+#else
   AisleriotBoard *board;
+#endif
 
   GamesCardThemes *theme_manager;
   GamesCardTheme *theme;
@@ -168,7 +183,10 @@ struct _AisleriotWindowPrivate
 
   guint load_idle_id;
 
+#ifndef HAVE_CLUTTER
   guint use_pixbuf_drawing : 1;
+#endif
+
   guint changing_game_type : 1;
   guint freecell_mode : 1;
   guint toolbar_visible : 1;
@@ -357,7 +375,7 @@ new_game_cb (GtkAction *action,
   aisleriot_game_new_game (priv->game, NULL);
 
   gtk_widget_grab_focus (GTK_WIDGET (priv->board));
-};
+}
 
 static void
 undo_cb (GtkAction *action,
@@ -366,7 +384,11 @@ undo_cb (GtkAction *action,
   AisleriotWindowPrivate *priv = window->priv;
 
   /* If a move is in progress, cancel it before changing the game! */
+#ifdef HAVE_CLUTTER
+  aisleriot_board_abort_move (AISLERIOT_BOARD (priv->board_actor));
+#else
   aisleriot_board_abort_move (priv->board);
+#endif
 
   aisleriot_game_undo_move (priv->game);
 }
@@ -377,8 +399,11 @@ redo_cb (GtkAction *action,
 {
   AisleriotWindowPrivate *priv = window->priv;
 
-  /* If a move is in progress, cancel it before changing the game! */
+#ifdef HAVE_CLUTTER
+  aisleriot_board_abort_move (AISLERIOT_BOARD (priv->board_actor));
+#else
   aisleriot_board_abort_move (priv->board);
+#endif
 
   aisleriot_game_redo_move (priv->game);
 }
@@ -831,6 +856,7 @@ debug_choose_seed_cb (GtkAction *action,
   gtk_window_present (GTK_WINDOW (dialog));
 }
 
+#ifndef HAVE_CLUTTER
 static void
 debug_pixbuf_drawing_cb (GtkToggleAction *action,
                          AisleriotWindow *window)
@@ -841,6 +867,7 @@ debug_pixbuf_drawing_cb (GtkToggleAction *action,
   active = gtk_toggle_action_get_active (action);
   aisleriot_board_set_pixbuf_drawing (priv->board, active);
 }
+#endif /* !HAVE_CLUTTER */
 
 #endif /* ENABLE_DEBUG_UI */
 
@@ -971,7 +998,11 @@ clickmove_toggle_cb (GtkToggleAction *action,
   click_to_move = gtk_toggle_action_get_active (action);
 
   aisleriot_game_set_click_to_move (priv->game, click_to_move);
+#ifdef HAVE_CLUTTER
+  ar_style_set_click_to_move (priv->board_style, click_to_move);
+#else
   aisleriot_board_set_click_to_move (priv->board, click_to_move);
+#endif
   
   games_conf_set_boolean (NULL, aisleriot_conf_get_key (CONF_CLICK_TO_MOVE), click_to_move);
 }
@@ -1004,7 +1035,11 @@ animations_toggle_cb (GtkToggleAction *action,
 
   enabled = gtk_toggle_action_get_active (action);
 
+#ifdef HAVE_CLUTTER
+  ar_style_set_enable_animations (priv->board_style, enabled);
+#else
   aisleriot_board_set_animation_mode (priv->board, enabled);
+#endif
   
   games_conf_set_boolean (NULL, aisleriot_conf_get_key (CONF_ANIMATIONS), enabled);
 }
@@ -1388,7 +1423,11 @@ aisleriot_window_take_card_theme (AisleriotWindow *window,
   }
 #endif /* GTK+ 2.10.0 */
 
+#ifdef HAVE_CLUTTER
+  ar_style_set_card_theme (priv->board_style, theme);
+#else
   aisleriot_board_set_card_theme (priv->board, theme);
+#endif
 }    
 
 static void
@@ -2006,6 +2045,37 @@ aisleriot_window_set_freecell_mode (AisleriotWindow *window,
   }
 }
 
+#ifdef HAVE_CLUTTER
+
+static void
+board_cursor_cb (AisleriotBoard *board,
+                 int cursor_type,
+                 ArClutterEmbed *embed)
+{
+  ar_clutter_embed_set_cursor (embed, (ArCursorType) cursor_type);
+}
+
+static void
+board_error_bell_cb (AisleriotBoard *board,
+                     ArClutterEmbed *embed)
+{
+#if GTK_CHECK_VERSION (2, 12, 0) || (defined (HAVE_HILDON) && !defined(HAVE_MAEMO_3))
+  gtk_widget_error_bell (GTK_WIDGET (embed));
+#endif
+}
+
+static void
+embed_size_allocate_cb (ArClutterEmbed *embed,
+                        GtkAllocation *allocation,
+                        AisleriotWindow *window)
+{
+  AisleriotWindowPrivate *priv = window->priv;
+
+  clutter_actor_set_size (priv->board_actor, allocation->width, allocation->height);
+}
+
+#endif /* HAVE_CLUTTER */
+
 /* Class implementation */
 
 #ifdef HAVE_HILDON
@@ -2232,7 +2302,7 @@ aisleriot_window_init (AisleriotWindow *window)
       G_CALLBACK (animations_toggle_cb),
       FALSE /* not active by default */ },
 #endif /* HAVE_CLUTTER */
-#ifdef ENABLE_DEBUG_UI
+#if defined(ENABLE_DEBUG_UI) && !defined(HAVE_CLUTTER)
     { "DebugPixbufDrawing", NULL, "_Pixbuf drawing", NULL, NULL,
       G_CALLBACK (debug_pixbuf_drawing_cb),
       FALSE },
@@ -2296,7 +2366,9 @@ aisleriot_window_init (AisleriotWindow *window)
 #ifdef ENABLE_DEBUG_UI
         "<menu action='DebugMenu'>"
           "<menuitem action='DebugChooseSeed'/>"
+#ifndef HAVE_CLUTTER
           "<menuitem action='DebugPixbufDrawing'/>"
+#endif /* !HAVE_CLUTTER */
         "</menu>"
 #endif /* ENABLE_DEBUG_UI */
         "<menuitem action='CloseWindow'/>"
@@ -2400,11 +2472,11 @@ aisleriot_window_init (AisleriotWindow *window)
   GamesCardTheme *theme;
   guint i;
 #ifndef HAVE_HILDON
-  const char *env;
   GtkStatusbar *statusbar;
-  GtkWidget *statusbar_hbox, *statusbar_label, *label, *time_box;
-  GtkContainer *statusbar_frame;
-  GList *list;
+  GtkWidget *statusbar_hbox, *label, *time_box;
+#endif
+#ifdef HAVE_CLUTTER
+  ClutterContainer *stage;
 #endif
 
   g_assert (G_N_ELEMENTS (names) == LAST_ACTION);
@@ -2415,12 +2487,19 @@ aisleriot_window_init (AisleriotWindow *window)
 
   priv->game = aisleriot_game_new ();
 
+#ifndef HAVE_CLUTTER
+
 #ifdef HAVE_HILDON
   priv->use_pixbuf_drawing = FALSE;
 #else
-  /* Default to pixbuf drawing */
+{
+  const char *env;
+
   env = g_getenv ("AISLERIOT_PIXBUF_DRAWING");
+
+  /* Default to pixbuf drawing */
   priv->use_pixbuf_drawing = env == NULL || g_ascii_strtoull (env, NULL, 10) != 0;
+}
 #endif /* HAVE_HILDON */
 
 #ifdef GNOME_ENABLE_DEBUG
@@ -2430,11 +2509,41 @@ aisleriot_window_init (AisleriotWindow *window)
     g_print ("Using pixmap drawing method\n");
 #endif /* GNOME_ENABLE_DEBUG */
 
+#endif /* !HAVE_CLUTTER */
+
   priv->theme_manager = games_card_themes_new ();
 
+#ifdef HAVE_CLUTTER
+  priv->board_style = ar_style_new ();
+  priv->board = ar_clutter_embed_new (priv->board_style);
+
+  priv->baize_actor = aisleriot_baize_new ();
+
+  stage = CLUTTER_CONTAINER (gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (priv->board)));
+  clutter_container_add (stage, priv->baize_actor, NULL);
+  /* FIXMEchpe: how to ensure this is ALWAYS the lowest actor? */
+  clutter_actor_lower_bottom (priv->baize_actor);
+
+  priv->board_actor = aisleriot_board_new (priv->board_style, priv->game);
+  clutter_container_add (stage, priv->board_actor, NULL);
+
+  /* FIXMEchpe */
+  clutter_stage_set_key_focus (CLUTTER_STAGE (stage), priv->board_actor);
+
+  g_signal_connect_after (priv->board, "size-allocate",
+                          G_CALLBACK (embed_size_allocate_cb), window);
+
+  g_signal_connect (priv->board_actor, "request-cursor",
+                    G_CALLBACK (board_cursor_cb), priv->board);
+  g_signal_connect (priv->board_actor, "error-bell",
+                    G_CALLBACK (board_error_bell_cb), priv->board);
+
+  /* FIXMEchpe: unref baize & board_actor here? */
+#else
   priv->board = AISLERIOT_BOARD (aisleriot_board_new (priv->game));
 
   aisleriot_board_set_pixbuf_drawing (priv->board, priv->use_pixbuf_drawing);
+#endif /* HAVE_CLUTTER */
 
   theme_name = games_conf_get_string (NULL, aisleriot_conf_get_key (CONF_THEME), NULL);
   theme = games_card_themes_get_theme_by_name (priv->theme_manager, theme_name);
@@ -2490,6 +2599,15 @@ aisleriot_window_init (AisleriotWindow *window)
   gtk_statusbar_set_has_resize_grip (priv->statusbar, FALSE);
 #endif
 
+#if GTK_CHECK_VERSION (2, 19, 1)
+  statusbar_hbox = gtk_statusbar_get_message_area (statusbar);
+  gtk_box_set_spacing (GTK_BOX (statusbar_hbox), 24);
+#else
+{
+  GtkWidget *statusbar_label,
+  GtkContainer *statusbar_frame;
+  GList *list;
+
   /* Widget surgery: move the statusbar's label into a hbox
    * which we put in the statusbar's frame instead.
    */
@@ -2504,6 +2622,8 @@ aisleriot_window_init (AisleriotWindow *window)
   g_object_unref (statusbar_label);
   gtk_container_add (statusbar_frame, statusbar_hbox);
   gtk_widget_show (statusbar_hbox);
+}
+#endif /* GTK+ >= 2.19.1 */
 
   /* Score */
   priv->score_box = gtk_hbox_new (12, FALSE);
@@ -2717,10 +2837,10 @@ aisleriot_window_init (AisleriotWindow *window)
                     G_CALLBACK (sync_window_topmost_cb), NULL);
 #endif
 
-#ifdef ENABLE_DEBUG_UI
+#if defined(ENABLE_DEBUG_UI) && !defined(HAVE_CLUTTER)
   action = gtk_action_group_get_action (priv->action_group, "DebugPixbufDrawing");
   gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), priv->use_pixbuf_drawing);
-#endif /* ENABLE_DEBUG_UI */
+#endif /* ENABLE_DEBUG_UI && !HAVE_CLUTTER */
 }
 
 static void
@@ -2775,6 +2895,10 @@ aisleriot_window_finalize (GObject *object)
   AisleriotWindow *window = AISLERIOT_WINDOW (object);
   AisleriotWindowPrivate *priv = window->priv;
 
+#ifdef HAVE_CLUTTER
+  g_object_unref (priv->board_style);
+#endif /* HAVE_CLUTTER */
+
   if (priv->theme) {
     g_object_unref (priv->theme);
   }
diff --git a/libgames-support/games-debug.c b/libgames-support/games-debug.c
index 0145a8c..852c94d 100644
--- a/libgames-support/games-debug.c
+++ b/libgames-support/games-debug.c
@@ -37,7 +37,12 @@ _games_debug_init (void)
     { "runtime",      GAMES_DEBUG_RUNTIME      },
     { "scheme",       GAMES_DEBUG_SCHEME       },
     { "sound",        GAMES_DEBUG_SOUND        },
-    { "window-state", GAMES_DEBUG_WINDOW_STATE }
+    { "window-state", GAMES_DEBUG_WINDOW_STATE },
+
+    { "game-drawing", GAMES_DEBUG_GAME_DRAWING },
+    { "game-events",  GAMES_DEBUG_GAME_EVENTS  },
+    { "game-keynav",  GAMES_DEBUG_GAME_KEYNAV  },
+    { "game-sizing",  GAMES_DEBUG_GAME_SIZING  }
   };
   const char *env;
 
diff --git a/libgames-support/games-debug.h b/libgames-support/games-debug.h
index b9c7fe7..cdc4d38 100644
--- a/libgames-support/games-debug.h
+++ b/libgames-support/games-debug.h
@@ -34,7 +34,12 @@ typedef enum {
   GAMES_DEBUG_RUNTIME       = 1 << 3,
   GAMES_DEBUG_SCHEME        = 1 << 4,
   GAMES_DEBUG_SOUND         = 1 << 5,
-  GAMES_DEBUG_WINDOW_STATE  = 1 << 6
+  GAMES_DEBUG_WINDOW_STATE  = 1 << 6,
+
+  GAMES_DEBUG_GAME_DRAWING  = 1 << 7,
+  GAMES_DEBUG_GAME_EVENTS   = 1 << 8,
+  GAMES_DEBUG_GAME_KEYNAV   = 1 << 9,
+  GAMES_DEBUG_GAME_SIZING   = 1 << 10
 } GamesDebugFlags;
 
 #ifdef GNOME_ENABLE_DEBUG
diff --git a/libgames-support/games-marshal.list b/libgames-support/games-marshal.list
index d726378..4b35878 100644
--- a/libgames-support/games-marshal.list
+++ b/libgames-support/games-marshal.list
@@ -1,2 +1,3 @@
 VOID:STRING,STRING
 BOOLEAN:ENUM,INT
+BOOLEAN:STRING,UINT,ENUM



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