gnome-games r8416 - in trunk: aisleriot blackjack/src libgames-support



Author: chpe
Date: Tue Jan  6 18:17:59 2009
New Revision: 8416
URL: http://svn.gnome.org/viewvc/gnome-games?rev=8416&view=rev

Log:
Refactor card themes by splitting it into an abstract base class
GamesCardTheme and two implementations for SVG themes and prerendered
themes. Adapt callers to the new API.

Added:
   trunk/libgames-support/games-card-theme-fixed.c
   trunk/libgames-support/games-card-theme-private.h
   trunk/libgames-support/games-card-theme-svg.c
Modified:
   trunk/aisleriot/board-noclutter.c
   trunk/aisleriot/board.c
   trunk/blackjack/src/card.cpp
   trunk/libgames-support/Makefile.am
   trunk/libgames-support/games-card-theme.c
   trunk/libgames-support/games-card-theme.h
   trunk/libgames-support/render-cards.c

Modified: trunk/aisleriot/board-noclutter.c
==============================================================================
--- trunk/aisleriot/board-noclutter.c	(original)
+++ trunk/aisleriot/board-noclutter.c	Tue Jan  6 18:17:59 2009
@@ -3357,7 +3357,11 @@
   g_assert (priv->game != NULL);
 
   /* Create this down here since we need to have the scalable_cards value */
-  priv->theme = games_card_theme_new (NULL, priv->scalable_cards);
+  if (priv->scalable_cards)
+    priv->theme = games_card_theme_svg_new ();
+  else
+    priv->theme = games_card_theme_fixed_new ();
+
   priv->images = games_card_images_new (priv->theme);
 
   return object;
@@ -3659,7 +3663,7 @@
   priv->geometry_set = FALSE;
   priv->slot_image = NULL;
 
-  retval = games_card_theme_set_theme (priv->theme, card_theme);
+  retval = games_card_theme_set_theme (priv->theme, NULL, card_theme);
 
   /* NOTE! We need to do this even if setting the theme failed, since
    * the attempt will have wiped out the old theme data!

Modified: trunk/aisleriot/board.c
==============================================================================
--- trunk/aisleriot/board.c	(original)
+++ trunk/aisleriot/board.c	Tue Jan  6 18:17:59 2009
@@ -3184,7 +3184,11 @@
   g_assert (priv->game != NULL);
 
   /* Create this down here since we need to have the scalable_cards value */
-  priv->theme = games_card_theme_new (NULL, priv->scalable_cards);
+  if (priv->scalable_cards)
+    priv->theme = games_card_theme_svg_new ();
+  else
+    priv->theme = games_card_theme_fixed_new ();
+
   priv->images = games_card_images_new (priv->theme);
   priv->textures = games_card_textures_cache_new (priv->images);
 
@@ -3513,7 +3517,7 @@
 
   priv->geometry_set = FALSE;
 
-  retval = games_card_theme_set_theme (priv->theme, card_theme);
+  retval = games_card_theme_set_theme (priv->theme, NULL, card_theme);
 
   /* NOTE! We need to do this even if setting the theme failed, since
    * the attempt will have wiped out the old theme data!

Modified: trunk/blackjack/src/card.cpp
==============================================================================
--- trunk/blackjack/src/card.cpp	(original)
+++ trunk/blackjack/src/card.cpp	Tue Jan  6 18:17:59 2009
@@ -126,7 +126,10 @@
                 env = g_getenv ("BLACKJACK_CARDS_SCALABLE");
                 scalable = env == NULL || g_ascii_strtoll (env, NULL, 10) != 0;
 
-                theme = games_card_theme_new (NULL, scalable);
+                if (scalable)
+                          theme = games_card_theme_svg_new ();
+                else
+                          theme = games_card_theme_fixed_new ();
 
                 images = games_card_images_new (theme);
                 g_object_unref (theme);
@@ -135,7 +138,7 @@
                 games_card_images_set_drawable (images, playing_area->window);
 
                 card_theme = bj_get_card_style ();
-                if (!games_card_theme_set_theme (theme, card_theme)) {
+                if (!games_card_theme_set_theme (theme, NULL, card_theme)) {
                         g_warning ("Failed to load theme %s!", card_theme);
                 }
                 g_free (card_theme);
@@ -154,7 +157,7 @@
 void
 bj_card_set_theme (gchar *card_theme)
 {
-        games_card_theme_set_theme (theme, card_theme);
+        games_card_theme_set_theme (theme, NULL, card_theme);
 
         bj_draw_rescale_cards ();
         mask = games_card_images_get_card_mask (images);

Modified: trunk/libgames-support/Makefile.am
==============================================================================
--- trunk/libgames-support/Makefile.am	(original)
+++ trunk/libgames-support/Makefile.am	Tue Jan  6 18:17:59 2009
@@ -30,6 +30,8 @@
 	games-card-images.h		\
 	games-card-theme.c		\
 	games-card-theme.h		\
+	games-card-theme-private.h	\
+	games-card-theme-fixed.c	\
 	games-conf.c			\
 	games-conf.h			\
 	games-files.c			\
@@ -87,6 +89,12 @@
 endif
 endif
 
+if HAVE_RSVG
+libgames_support_la_SOURCES += \
+	games-card-theme-svg.c		\
+	$(NULL)
+endif
+
 if HAVE_CLUTTER
 libgames_support_la_SOURCES += \
 	games-card-textures-cache.c	\

Added: trunk/libgames-support/games-card-theme-fixed.c
==============================================================================
--- (empty file)
+++ trunk/libgames-support/games-card-theme-fixed.c	Tue Jan  6 18:17:59 2009
@@ -0,0 +1,406 @@
+/*
+   Copyright  2004 Callum McKenzie
+   Copyright  2007, 2008 Christian Persch
+
+   This library is free software; you can redistribute it and'or modify
+   it under the terms of the GNU Library General Public License as published 
+   by the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Authors:   Callum McKenzie <callum physics otago ac nz> */
+
+#include <config.h>
+
+#include <string.h>
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
+
+#include "games-find-file.h"
+#include "games-files.h"
+#include "games-preimage.h"
+#include "games-runtime.h"
+
+#include "games-card-theme.h"
+#include "games-card-theme-private.h"
+
+struct _GamesCardThemeFixedClass {
+  GamesCardThemeClass parent_class;
+};
+
+struct _GamesCardThemeFixed {
+  GamesCardTheme parent_instance;
+
+  char *theme_dir;
+  char *theme_name;
+
+  /* Switched on GamesCardThemeFixed.use_scalable */
+  char *themesizepath;
+  CardSize *card_sizes;
+  guint n_card_sizes;
+
+  CardSize slot_size;
+  CardSize card_size;
+
+  guint use_scalable : 1;
+  guint theme_loaded : 1;
+  guint size_available : 1;
+
+  guint subrender : 1;
+  guint prescaled : 1;
+};
+
+/* #defining this prints out the time it takes to render the theme */
+/* #define INSTRUMENT_LOADING */
+
+#ifdef INSTRUMENT_LOADING
+static long totaltime = 0;
+#endif
+
+/* Class implementation */
+
+G_DEFINE_TYPE (GamesCardThemeFixed, games_card_theme_fixed, GAMES_TYPE_CARD_THEME);
+
+static void
+games_card_theme_fixed_clear_theme_data (GamesCardThemeFixed *theme)
+{
+#ifdef INSTRUMENT_LOADING
+  /* Reset the time */
+  totaltime = 0;
+#endif
+
+  g_free (theme->theme_name);
+  theme->theme_name = NULL;
+
+  g_free (theme->theme_dir);
+  theme->theme_dir = NULL;
+
+  g_free (theme->card_sizes);
+  theme->card_sizes = NULL;
+  theme->n_card_sizes = 0;
+
+  g_free (theme->themesizepath);
+  theme->themesizepath = NULL;
+
+  theme->size_available = FALSE;
+
+  theme->theme_loaded = FALSE;
+
+  theme->card_size.width = theme->card_size.height = theme->slot_size.width =
+    theme->slot_size.width = -1;
+}
+
+static gboolean
+games_card_theme_fixed_load_theme (GamesCardTheme *card_theme,
+                                   const char *theme_dir,
+                                   const char *theme_name,
+                                   GError **error__)
+{
+  GamesCardThemeFixed *theme = (GamesCardThemeFixed *) card_theme;
+  GKeyFile *key_file;
+  char *filename, *path;
+  GError *error = NULL;
+  int *sizes = NULL;
+  gsize n_sizes, i;
+  gboolean retval = FALSE;
+
+  if (theme->theme_name != NULL &&
+      strcmp (theme_name, theme->theme_name) == 0)
+    return TRUE;
+
+  games_card_theme_fixed_clear_theme_data (theme);
+
+  if (!theme_dir)
+    theme_dir = games_runtime_get_directory (GAMES_RUNTIME_PRERENDERED_CARDS_DIRECTORY);
+
+  filename = g_strdup_printf ("%s.card-theme", theme_name);
+  path = g_build_filename (theme_dir, filename, NULL);
+  g_free (filename);
+
+  key_file = g_key_file_new ();
+  if (!g_key_file_load_from_file (key_file, path, 0, &error)) {
+    g_warning ("Failed to load prerendered card theme from %s: %s\n", path,
+               error->message);
+    g_error_free (error);
+    goto loser;
+  }
+
+  sizes =
+    g_key_file_get_integer_list (key_file, "Card Theme", "Sizes", &n_sizes,
+                                 &error);
+  if (error) {
+    g_warning ("Failed to get card sizes: %s\n", error->message);
+    g_error_free (error);
+    goto loser;
+  }
+
+  if (n_sizes == 0) {
+    g_warning ("Card theme contains no sizes\n");
+    goto loser;
+  }
+
+  theme->card_sizes = g_new (CardSize, n_sizes);
+  theme->n_card_sizes = n_sizes;
+
+  for (i = 0; i < n_sizes; ++i) {
+    char group[32];
+    GError *err = NULL;
+    int width, height;
+
+    g_snprintf (group, sizeof (group), "%d", sizes[i]);
+
+    width = g_key_file_get_integer (key_file, group, "Width", &err);
+    if (err) {
+      g_warning ("Error loading width for size %d: %s\n", sizes[i],
+                 err->message);
+      g_error_free (err);
+      goto loser;
+    }
+    height = g_key_file_get_integer (key_file, group, "Height", &err);
+    if (err) {
+      g_warning ("Error loading height for size %d: %s\n", sizes[i],
+                 err->message);
+      g_error_free (err);
+      goto loser;
+    }
+
+    theme->card_sizes[i].width = width;
+    theme->card_sizes[i].height = height;
+  }
+
+  retval = TRUE;
+    
+  theme->theme_name = g_strdup (theme_name);
+  theme->theme_dir = g_strdup (theme_dir);
+
+  theme->theme_loaded = TRUE;
+
+loser:
+
+  g_free (sizes);
+
+  g_key_file_free (key_file);
+  g_free (path);
+
+  if (!retval) {
+    games_card_theme_fixed_clear_theme_data (theme);
+  }
+
+  _games_card_theme_emit_changed (card_theme);
+
+  return retval;
+}
+
+static GdkPixbuf *
+games_card_theme_fixed_load_card (GamesCardThemeFixed *theme,
+                                  int card_id)
+{
+  GdkPixbuf *pixbuf;
+  GError *error = NULL;
+  char name[64], filename[64];
+  char *path;
+
+  if (!theme->theme_loaded || !theme->size_available)
+    return NULL;
+
+  g_return_val_if_fail (!theme->use_scalable, NULL);
+
+  games_card_get_name_by_id_snprintf (name, sizeof (name), card_id);
+  g_snprintf (filename, sizeof (filename), "%s.png", name);
+  path = g_build_filename (theme->themesizepath, filename, NULL);
+
+  pixbuf = gdk_pixbuf_new_from_file (path, &error);
+  if (!pixbuf) {
+    g_warning ("Failed to load card image %s: %s\n", filename,
+               error->message);
+    g_error_free (error);
+  }
+
+  g_free (path);
+
+  return pixbuf;
+}
+
+static void
+games_card_theme_fixed_finalize (GObject * object)
+{
+  GamesCardThemeFixed *theme = GAMES_CARD_THEME_FIXED (object);
+
+  games_card_theme_fixed_clear_theme_data (theme);
+
+  G_OBJECT_CLASS (games_card_theme_fixed_parent_class)->finalize (object);
+}
+
+static void
+games_card_theme_fixed_init (GamesCardThemeFixed *theme)
+{
+  theme->card_size.width = theme->card_size.height = -1;
+  theme->theme_name = NULL;
+}
+
+static const gchar *
+games_card_theme_fixed_get_theme_name (GamesCardTheme *card_theme)
+{
+  GamesCardThemeFixed *theme = (GamesCardThemeFixed *) card_theme;
+
+  return theme->theme_name;
+}
+
+static gboolean
+games_card_theme_fixed_set_card_size (GamesCardTheme *card_theme,
+                                      int width,
+                                      int height,
+                                      double proportion)
+{
+  GamesCardThemeFixed *theme = (GamesCardThemeFixed *) card_theme;
+
+  if (!theme->theme_loaded) {
+    g_warning ("Theme not loaded yet; cannot set size!");
+    return FALSE;
+  }
+
+  if ((width == theme->slot_size.width) &&
+      (height == theme->slot_size.height))
+    return FALSE;
+
+  theme->slot_size.width = width;
+  theme->slot_size.height = height;
+
+  {
+    guint i;
+    int twidth, theight;
+    CardSize size = { -1, -1 }, fit_size = { -1, -1};
+
+    twidth = FLOAT_TO_INT_CEIL (((double) width) * proportion);
+    theight = FLOAT_TO_INT_CEIL (((double) height) * proportion);
+
+    /* Find the closest prerendered size */
+    for (i = 0; i < theme->n_card_sizes; ++i) {
+      CardSize info = theme->card_sizes[i];
+
+      if (info.width > width || info.height > height)
+        continue;
+
+      if (info.width > fit_size.width && info.height > fit_size.height)
+        fit_size = info;
+
+      /* FIXMEchpe */
+      if (info.width <= twidth && info.height <= theight &&
+          info.width > size.width && info.height > size.height)
+        size = info;
+    }
+
+    if (size.width < 0 || size.height < 0)
+      size = fit_size;
+
+    if (size.width > 0 && size.height > 0) {
+      char sizestr[16];
+
+      if (size.width == theme->card_size.width &&
+          size.height == theme->card_size.height)
+        return FALSE;
+
+      g_free (theme->themesizepath);
+
+      g_snprintf (sizestr, sizeof (sizestr), "%d", size.width);
+      theme->themesizepath =
+        g_build_filename (theme->theme_dir, theme->theme_name, sizestr, NULL);
+
+      theme->size_available = TRUE;
+      theme->card_size = size;
+    } else {
+      g_warning ("No prerendered size available for %d:%d\n", width, height);
+      theme->size_available = FALSE;
+
+      /* FIXMEchpe: at least use the smallest available size here, or
+       * programme will surely crash when trying to render NULL pixbufs
+       * later on!
+       */
+      return FALSE;
+    }
+  }
+
+  _games_card_theme_emit_changed (card_theme);
+
+  return TRUE;
+}
+
+static CardSize
+games_card_theme_fixed_get_card_size (GamesCardTheme *card_theme)
+{
+  GamesCardThemeFixed *theme = (GamesCardThemeFixed *) card_theme;
+
+  return theme->card_size;
+}
+
+static double
+games_card_theme_fixed_get_card_aspect (GamesCardTheme *card_theme)
+{
+  GamesCardThemeFixed *theme = (GamesCardThemeFixed *) card_theme;
+
+  return ((double) theme->card_size.width) / ((double) theme->card_size.height);
+}
+
+static GdkPixbuf *
+games_card_theme_fixed_get_card_pixbuf (GamesCardTheme *card_theme,
+                                        int card_id)
+{
+  GamesCardThemeFixed *theme = (GamesCardThemeFixed *) card_theme;
+  GdkPixbuf *pixbuf;
+
+#ifdef INSTRUMENT_LOADING
+  clock_t t1, t2;
+
+  t1 = clock ();
+#endif
+
+  pixbuf = games_card_theme_fixed_load_card (theme, card_id);
+
+#ifdef INSTRUMENT_LOADING
+  t2 = clock ();
+  totaltime += (t2 - t1);
+  g_print ("took %.3fs to render card %d (cumulative: %.3fs)\n",
+           (t2 - t1) * 1.0 / CLOCKS_PER_SEC, card_id,
+           totaltime * 1.0 / CLOCKS_PER_SEC);
+#endif
+
+  return pixbuf;
+}
+
+static void
+games_card_theme_fixed_class_init (GamesCardThemeFixedClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GamesCardThemeClass *theme_class = GAMES_CARD_THEME_CLASS (klass);
+
+  gobject_class->finalize = games_card_theme_fixed_finalize;
+
+  theme_class->load_theme = games_card_theme_fixed_load_theme;
+  theme_class->get_theme_name = games_card_theme_fixed_get_theme_name;
+  theme_class->set_card_size = games_card_theme_fixed_set_card_size;
+  theme_class->get_card_size = games_card_theme_fixed_get_card_size;
+  theme_class->get_card_aspect = games_card_theme_fixed_get_card_aspect;
+  theme_class->get_card_pixbuf = games_card_theme_fixed_get_card_pixbuf;
+}
+
+/* public API */
+
+/**
+ * games_card_theme_fixed_new:
+ *
+ * Returns: a new #GamesCardThemeFixed
+ */
+GamesCardTheme *
+games_card_theme_fixed_new (void)
+{
+  return g_object_new (GAMES_TYPE_CARD_THEME_FIXED, NULL);
+}

Added: trunk/libgames-support/games-card-theme-private.h
==============================================================================
--- (empty file)
+++ trunk/libgames-support/games-card-theme-private.h	Tue Jan  6 18:17:59 2009
@@ -0,0 +1,55 @@
+/*
+   Copyright  2004 Callum McKenzie
+   Copyright  2007, 2008 Christian Persch
+
+   This library is free software; you can redistribute it and'or modify
+   it under the terms of the GNU Library General Public License as published 
+   by the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Authors:   Callum McKenzie <callum physics otago ac nz> */
+
+#define FLOAT_TO_INT_CEIL(f) ((int) (f + 0.5f))
+
+struct _GamesCardThemeClass {
+  GObjectClass parent_class;
+
+  /* vfuncs */
+  gboolean    (* load_theme)        (GamesCardTheme *theme,
+                                     const char *theme_dir,
+                                     const char *theme_name,
+                                     GError **error);
+  const char* (* get_theme_name)    (GamesCardTheme *theme);
+  gboolean    (* set_card_size)     (GamesCardTheme *theme,
+                                     int width,
+                                     int height,
+                                     double proportion);
+  CardSize    (* get_card_size)     (GamesCardTheme *theme);
+  double      (* get_card_aspect)   (GamesCardTheme *theme);
+  GdkPixbuf*  (* get_card_pixbuf)   (GamesCardTheme *theme,
+                                     int card_id);
+
+#if GTK_CHECK_VERSION (2, 10, 0)
+  void        (* set_font_options)  (GamesCardTheme *theme,
+                                     const cairo_font_options_t *font_options);
+#endif
+};
+
+struct _GamesCardTheme {
+  GObject parent;
+
+  GamesCardThemeClass *klass;
+
+  char *theme_name;
+};
+
+void _games_card_theme_emit_changed (GamesCardTheme * theme);

Added: trunk/libgames-support/games-card-theme-svg.c
==============================================================================
--- (empty file)
+++ trunk/libgames-support/games-card-theme-svg.c	Tue Jan  6 18:17:59 2009
@@ -0,0 +1,531 @@
+/*
+   Copyright  2004 Callum McKenzie
+   Copyright  2007, 2008 Christian Persch
+
+   This library is free software; you can redistribute it and'or modify
+   it under the terms of the GNU Library General Public License as published 
+   by the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Authors:   Callum McKenzie <callum physics otago ac nz> */
+
+#include <config.h>
+
+#include <string.h>
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
+
+#include "games-find-file.h"
+#include "games-files.h"
+#include "games-preimage.h"
+#include "games-runtime.h"
+
+#include "games-card-theme.h"
+#include "games-card-theme-private.h"
+
+struct _GamesCardThemeSVGClass {
+  GamesCardThemeClass parent_class;
+};
+
+struct _GamesCardThemeSVG {
+  GamesCardTheme parent_instance;
+
+  char *theme_dir;
+  char *theme_name;
+
+  GamesPreimage *cards_preimage;
+  GamesPreimage *slot_preimage;
+  GdkPixbuf *source;
+  CardSize subsize;
+
+  CardSize slot_size;
+  CardSize card_size;
+
+  guint theme_loaded : 1;
+  guint size_available : 1;
+
+  guint subrender : 1;
+  guint prescaled : 1;
+
+  cairo_font_options_t *font_options;
+};
+
+#define N_ROWS ((double) 5.0)
+#define N_COLS ((double) 13.0)
+
+#define DELTA (0.0f)
+
+/* #defining this prints out the time it takes to render the theme */
+/* #define INSTRUMENT_LOADING */
+
+#ifdef INSTRUMENT_LOADING
+static long totaltime = 0;
+#endif
+
+/* Class implementation */
+
+G_DEFINE_TYPE (GamesCardThemeSVG, games_card_theme_svg, GAMES_TYPE_CARD_THEME);
+
+static void
+games_card_theme_svg_clear_source_pixbuf (GamesCardThemeSVG *theme)
+{
+  if (theme->source) {
+    g_object_unref (theme->source);
+    theme->source = NULL;
+  }
+
+#ifdef INSTRUMENT_LOADING
+  /* Reset the time */
+  totaltime = 0;
+#endif
+}
+
+static void
+games_card_theme_svg_clear_theme_data (GamesCardThemeSVG *theme)
+{
+  games_card_theme_svg_clear_source_pixbuf (theme);
+
+  if (theme->cards_preimage != NULL) {
+    g_object_unref (theme->cards_preimage);
+    theme->cards_preimage = NULL;
+  }
+  if (theme->slot_preimage != NULL) {
+    g_object_unref (theme->slot_preimage);
+    theme->slot_preimage = NULL;
+  }
+
+  theme->subsize.width = -1;
+  theme->subsize.height = -1;
+
+  theme->theme_loaded = FALSE;
+
+  theme->card_size.width = theme->card_size.height = theme->slot_size.width =
+    theme->slot_size.width = -1;
+}
+
+static gboolean
+games_card_theme_svg_load_theme (GamesCardTheme *card_theme,
+                                 const char *theme_dir,
+                                 const char *theme_name,
+                                 GError **error)
+{
+  GamesCardThemeSVG *theme = (GamesCardThemeSVG *) card_theme;
+  GamesPreimage *preimage;
+  const char *slot_dir, *env;
+  gchar *filename, *path;
+
+#ifdef INSTRUMENT_LOADING
+  clock_t t1, t2;
+
+  t1 = clock ();
+#endif
+
+  if (theme->theme_name != NULL &&
+      strcmp (theme_name, theme->theme_name) == 0)
+    return TRUE;
+
+  games_card_theme_svg_clear_theme_data (theme);
+
+  g_free (theme->theme_name);
+  theme->theme_name = NULL;
+
+  // FIXMEchpe wtf?
+  if (theme->cards_preimage != NULL)
+    return TRUE;
+
+  if (!theme_dir)
+    theme_dir = games_runtime_get_directory (GAMES_RUNTIME_SCALABLE_CARDS_DIRECTORY);
+
+  /* First try and load the given file. */
+  filename = g_strdup_printf ("%s.svg", theme_name);
+  path = g_build_filename (theme_dir, filename, NULL);
+  preimage = games_preimage_new_from_file (path, NULL);
+  g_free (path);
+
+  /* Failing that, try and find a similar file (e.g. a suffix change). */
+  if (!preimage) {
+    path = games_find_similar_file (filename, theme_dir);
+    if (path) {
+      preimage = games_preimage_new_from_file (path, NULL);
+      g_free (path);
+    }
+  }
+
+  g_free (filename);
+
+  if (!preimage)
+    goto out;
+
+  if (theme->font_options) {
+    games_preimage_set_font_options (preimage, theme->font_options);
+  }
+
+  theme->cards_preimage = preimage;
+  theme->prescaled = games_preimage_is_scalable (preimage);
+
+  /* If we don't have a scalable format, build a scaled pixbuf that we'll cut up later */
+  if (!theme->prescaled) {
+    theme->source =
+      games_preimage_render_unscaled_pixbuf (theme->
+                                             cards_preimage);
+  }
+
+  /* And the slot image */
+  /* FIXMEchpe: use uninstalled data dir for rendering the card theme! */
+  slot_dir = games_runtime_get_directory (GAMES_RUNTIME_PIXMAP_DIRECTORY);
+  path = g_build_filename (slot_dir, "slot.svg", NULL);
+  theme->slot_preimage = games_preimage_new_from_file (path, NULL);
+  g_free (path);
+  g_return_val_if_fail (theme->slot_preimage != NULL, FALSE);
+
+  if (theme->font_options) {
+    games_preimage_set_font_options (theme->slot_preimage,
+                                     theme->font_options);
+  }
+
+  /* Use subrendering by default, but allow to override with the env var */
+  theme->subrender = TRUE;
+
+  env = g_getenv ("GAMES_CARDS_SUBRENDERING");
+  if (env != NULL) {
+    theme->subrender = g_ascii_strtoull (env, NULL, 0) != 0;
+  }
+#ifdef GNOME_ENABLE_DEBUG
+  if (theme->subrender)
+    g_print ("Using subrendering for theme \"%s\"\n", theme_name);
+  else
+    g_print ("Not using subrendering for theme \"%s\"\n", theme_name);
+#endif
+
+out:
+
+#ifdef INSTRUMENT_LOADING
+  t2 = clock ();
+  totaltime += (t2 - t1);
+  g_print ("took %.3fs to create preimage (cumulative %.3fs)\n",
+           (t2 - t1) * 1.0 / CLOCKS_PER_SEC,
+           totaltime * 1.0 / CLOCKS_PER_SEC);
+#endif
+
+  if (theme->cards_preimage != NULL) {
+    theme->theme_name = g_strdup (theme_name);
+
+    theme->theme_loaded = TRUE;
+
+    _games_card_theme_emit_changed (card_theme);
+    return TRUE;
+  }
+
+  games_card_theme_svg_clear_theme_data (theme);
+  _games_card_theme_emit_changed (card_theme);
+
+  return FALSE;
+}
+
+static gboolean
+games_card_theme_svg_prerender_scalable (GamesCardThemeSVG * theme)
+{
+#ifdef INSTRUMENT_LOADING
+  clock_t t1, t2;
+
+  t1 = clock ();
+#endif
+
+  g_return_val_if_fail (theme->cards_preimage != NULL, FALSE);
+  g_return_val_if_fail (theme->prescaled
+                        || theme->source != NULL, FALSE);
+
+  theme->source =
+    games_preimage_render (theme->cards_preimage,
+                           theme->card_size.width * 13,
+                           theme->card_size.height * 5);
+  if (!theme->source)
+    return FALSE;
+
+  theme->subsize.width =
+    gdk_pixbuf_get_width (theme->source) / 13;
+  theme->subsize.height =
+    gdk_pixbuf_get_height (theme->source) / 5;
+
+#ifdef INSTRUMENT_LOADING
+  t2 = clock ();
+  g_print ("took %.3fs to prerender\n", (t2 - t1) * 1.0 / CLOCKS_PER_SEC);
+#endif
+
+  return TRUE;
+}
+
+static GdkPixbuf *
+games_card_theme_svg_render_card (GamesCardThemeSVG * theme, int card_id)
+{
+  GamesPreimage *preimage = theme->cards_preimage;
+  GdkPixbuf *subpixbuf, *card_pixbuf;
+  int suit, rank;
+
+  if (!theme->theme_loaded)
+    return NULL;
+
+  suit = card_id / 13;
+  rank = card_id % 13;
+
+  if (G_UNLIKELY (card_id == GAMES_CARD_SLOT)) {
+    subpixbuf = games_preimage_render (theme->slot_preimage,
+                                       theme->card_size.width,
+                                       theme->card_size.height);
+
+    return subpixbuf;
+  }
+
+  if (theme->subrender) {
+    double card_width, card_height;
+    double width, height;
+    double offsetx, offsety;
+    double zoomx, zoomy;
+    char node[64];
+
+    card_width = ((double) games_preimage_get_width (preimage)) / N_COLS;
+    card_height = ((double) games_preimage_get_height (preimage)) / N_ROWS;
+
+    width = theme->card_size.width - 2 * DELTA;
+    height = theme->card_size.height - 2 * DELTA;
+
+    offsetx = -((double) rank) * card_width + DELTA;
+    offsety = -((double) suit) * card_height + DELTA;
+
+    zoomx = width / card_width;
+    zoomy = height / card_height;
+
+    games_card_get_node_by_suit_and_rank_snprintf (node, sizeof (node), suit, rank);
+
+    subpixbuf = games_preimage_render_sub (preimage,
+                                           node,
+                                           theme->card_size.width, theme->card_size.height,
+                                           offsetx, offsety,
+                                           zoomx, zoomy);
+
+    return subpixbuf;
+  }
+
+  /* Not using subrendering */
+  if (!theme->source &&
+      !games_card_theme_svg_prerender_scalable (theme))
+    return NULL;
+
+  subpixbuf = gdk_pixbuf_new_subpixbuf (theme->source,
+                                        rank *
+                                        theme->subsize.width,
+                                        suit *
+                                        theme->subsize.height,
+                                        theme->subsize.width,
+                                        theme->subsize.height);
+  if (theme->prescaled) {
+    card_pixbuf = subpixbuf;
+  } else {
+    card_pixbuf = gdk_pixbuf_scale_simple (subpixbuf,
+                                           theme->card_size.width,
+                                           theme->card_size.height,
+                                           GDK_INTERP_BILINEAR);
+    g_object_unref (subpixbuf);
+  }
+
+  return card_pixbuf;
+}
+
+static void
+games_card_theme_svg_finalize (GObject * object)
+{
+  GamesCardThemeSVG *theme = GAMES_CARD_THEME_SVG (object);
+
+  games_card_theme_svg_clear_theme_data (theme);
+
+  g_free (theme->theme_name);
+  g_free (theme->theme_dir);
+
+  if (theme->font_options) {
+    cairo_font_options_destroy (theme->font_options);
+  }
+
+  G_OBJECT_CLASS (games_card_theme_svg_parent_class)->finalize (object);
+}
+
+static void
+games_card_theme_svg_init (GamesCardThemeSVG * cardtheme)
+{
+  cardtheme->card_size.width = cardtheme->card_size.height = -1;
+  cardtheme->theme_name = NULL;
+
+  cardtheme->prescaled = FALSE;
+
+  cardtheme->subrender = FALSE;
+}
+
+static void
+games_card_theme_svg_set_font_options (GamesCardTheme *card_theme,
+                                       const cairo_font_options_t *font_options)
+{
+  GamesCardThemeSVG *theme = (GamesCardThemeSVG *) card_theme;
+
+  if (font_options &&
+      theme->font_options &&
+      cairo_font_options_equal (font_options, theme->font_options))
+    return;
+
+  if (theme->font_options) {
+    cairo_font_options_destroy (theme->font_options);
+  }
+
+  if (font_options) {
+    theme->font_options = cairo_font_options_copy (font_options);
+  } else {
+    theme->font_options = NULL;
+  }
+
+  games_card_theme_svg_clear_source_pixbuf (theme);
+  _games_card_theme_emit_changed (card_theme);
+}
+
+static const gchar *
+games_card_theme_svg_get_theme_name (GamesCardTheme *card_theme)
+{
+  GamesCardThemeSVG *theme = (GamesCardThemeSVG *) card_theme;
+
+  return theme->theme_name;
+}
+
+static gboolean
+games_card_theme_svg_set_card_size (GamesCardTheme *card_theme,
+                                    int width,
+                                    int height,
+                                    double proportion)
+{
+  GamesCardThemeSVG *theme = (GamesCardThemeSVG *) card_theme;
+  double aspect_ratio, twidth, theight;
+
+  if (!theme->theme_loaded) {
+    g_warning ("Theme not loaded yet; cannot set size!");
+    return FALSE;
+  }
+
+  if ((width == theme->slot_size.width) &&
+      (height == theme->slot_size.height))
+    return FALSE;
+
+  theme->slot_size.width = width;
+  theme->slot_size.height = height;
+
+  /* Now calculate the card size: find the maximum size that fits
+   * into the given area, preserving the card's aspect ratio.
+   */
+  aspect_ratio = games_card_theme_get_aspect (card_theme);
+
+  twidth = proportion * width;
+  theight = proportion * height;
+  if (twidth / theight < aspect_ratio) {
+    theight = twidth / aspect_ratio;
+  } else {
+    twidth = theight * aspect_ratio;
+  }
+
+  if (theme->card_size.width == (int) twidth &&
+      theme->card_size.height == (int) theight)
+    return FALSE;
+
+  theme->card_size.width = twidth;
+  theme->card_size.height = theight;
+
+  games_card_theme_svg_clear_source_pixbuf (theme);
+  _games_card_theme_emit_changed (card_theme);
+
+  return TRUE;
+}
+
+static CardSize
+games_card_theme_svg_get_card_size (GamesCardTheme *card_theme)
+{
+  GamesCardThemeSVG *theme = (GamesCardThemeSVG *) card_theme;
+
+  return theme->card_size;
+}
+
+static double
+games_card_theme_svg_get_card_aspect (GamesCardTheme* card_theme)
+{
+  GamesCardThemeSVG *theme = (GamesCardThemeSVG *) card_theme;
+  double aspect;
+
+  g_return_val_if_fail (GAMES_IS_CARD_THEME_SVG (theme), 1.0);
+
+  aspect =
+      (((double) games_preimage_get_width (theme->cards_preimage))
+       * N_ROWS) /
+      (((double) games_preimage_get_height (theme->cards_preimage))
+       * N_COLS);
+
+  return aspect;
+}
+
+static GdkPixbuf *
+games_card_theme_svg_get_card_pixbuf (GamesCardTheme *card_theme,
+                                      int card_id)
+{
+  GamesCardThemeSVG *theme = (GamesCardThemeSVG *) card_theme;
+  GdkPixbuf *pixbuf;
+
+#ifdef INSTRUMENT_LOADING
+  clock_t t1, t2;
+
+  t1 = clock ();
+#endif
+
+  pixbuf = games_card_theme_svg_render_card (theme, card_id);
+
+#ifdef INSTRUMENT_LOADING
+  t2 = clock ();
+  totaltime += (t2 - t1);
+  g_print ("took %.3fs to render card %d (cumulative: %.3fs)\n",
+           (t2 - t1) * 1.0 / CLOCKS_PER_SEC, card_id,
+           totaltime * 1.0 / CLOCKS_PER_SEC);
+#endif
+
+  return pixbuf;
+}
+
+static void
+games_card_theme_svg_class_init (GamesCardThemeSVGClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GamesCardThemeClass *theme_class = GAMES_CARD_THEME_CLASS (klass);
+
+  gobject_class->finalize = games_card_theme_svg_finalize;
+
+  theme_class->load_theme = games_card_theme_svg_load_theme;
+  theme_class->get_theme_name = games_card_theme_svg_get_theme_name;
+  theme_class->set_card_size = games_card_theme_svg_set_card_size;
+  theme_class->get_card_size = games_card_theme_svg_get_card_size;
+  theme_class->get_card_aspect = games_card_theme_svg_get_card_aspect;
+  theme_class->get_card_pixbuf = games_card_theme_svg_get_card_pixbuf;
+  theme_class->set_font_options = games_card_theme_svg_set_font_options;
+}
+
+/* public API */
+
+/**
+ * games_card_theme_svg_new:
+ *
+ * Returns: a new #GamesCardThemeSVG
+ */
+GamesCardTheme*
+games_card_theme_svg_new (void)
+{
+  return g_object_new (GAMES_TYPE_CARD_THEME_SVG, NULL);
+}

Modified: trunk/libgames-support/games-card-theme.c
==============================================================================
--- trunk/libgames-support/games-card-theme.c	(original)
+++ trunk/libgames-support/games-card-theme.c	Tue Jan  6 18:17:59 2009
@@ -1,6 +1,6 @@
 /*
    Copyright  2004 Callum McKenzie
-   Copyright  2007 Christian Persch
+   Copyright  2007, 2008 Christian Persch
 
    This library is free software; you can redistribute it and'or modify
    it under the terms of the GNU Library General Public License as published 
@@ -31,52 +31,7 @@
 #include "games-runtime.h"
 
 #include "games-card-theme.h"
-
-struct _GamesCardThemeClass {
-  GObjectClass parent_class;
-};
-
-struct _GamesCardTheme {
-  GObject parent;
-
-  gchar *theme_dir;
-  gchar *theme_name;
-
-  /* Switched on GamesCardTheme.use_scalable */
-  union {
-    struct {
-      GamesPreimage *cards_preimage;
-      GamesPreimage *slot_preimage;
-      GdkPixbuf *source;
-      CardSize subsize;
-    } scalable;
-    struct {
-      char *themesizepath;
-      CardSize *card_sizes;
-      guint n_card_sizes;
-    } prerendered;
-  } theme_data;
-
-  CardSize slot_size;
-  CardSize card_size;
-
-  guint use_scalable : 1;
-  guint theme_loaded : 1;
-  guint size_available : 1;
-
-  guint subrender : 1;
-  guint prescaled : 1;
-
-#if GTK_CHECK_VERSION (2, 10, 0)
-  cairo_font_options_t *font_options;
-#endif
-};
-
-enum {
-  PROP_0,
-  PROP_SCALABLE,
-  PROP_THEME_DIRECTORY
-};
+#include "games-card-theme-private.h"
 
 enum {
   CHANGED,
@@ -85,12 +40,6 @@
 
 static guint signals[LAST_SIGNAL];
 
-#define N_ROWS ((double) 5.0)
-#define N_COLS ((double) 13.0)
-
-#define FLOAT_TO_INT_CEIL(f) ((int) (f + 0.5f))
-#define DELTA (0.0f)
-
 /* #defining this prints out the time it takes to render the theme */
 /* #define INSTRUMENT_LOADING */
 
@@ -98,284 +47,37 @@
 static long totaltime = 0;
 #endif
 
-static void
-games_card_theme_clear_source_pixbuf (GamesCardTheme * theme)
-{
-#ifdef HAVE_RSVG
-  if (theme->use_scalable) {
-    if (theme->theme_data.scalable.source) {
-      g_object_unref (theme->theme_data.scalable.source);
-    }
-
-    theme->theme_data.scalable.source = NULL;
-  }
-#endif /* HAVE_RSVG */
-
-#ifdef INSTRUMENT_LOADING
-  /* Reset the time */
-  totaltime = 0;
-#endif
-}
-
-static void
-games_card_theme_clear_theme_data (GamesCardTheme * theme)
-{
-#ifdef HAVE_RSVG
-  if (theme->use_scalable) {
-    if (theme->theme_data.scalable.cards_preimage != NULL) {
-      g_object_unref (theme->theme_data.scalable.cards_preimage);
-      theme->theme_data.scalable.cards_preimage = NULL;
-    }
-    if (theme->theme_data.scalable.slot_preimage != NULL) {
-      g_object_unref (theme->theme_data.scalable.slot_preimage);
-      theme->theme_data.scalable.slot_preimage = NULL;
-    }
-
-    theme->theme_data.scalable.subsize.width = -1;
-    theme->theme_data.scalable.subsize.height = -1;
-  } else
-#endif /* HAVE_RSVG */
-  {
-    g_free (theme->theme_data.prerendered.card_sizes);
-    theme->theme_data.prerendered.card_sizes = NULL;
-    theme->theme_data.prerendered.n_card_sizes = 0;
-
-    g_free (theme->theme_data.prerendered.themesizepath);
-    theme->theme_data.prerendered.themesizepath = NULL;
-
-    theme->size_available = FALSE;
-  }
-
-  theme->theme_loaded = FALSE;
-}
-
-#ifdef HAVE_RSVG
-
-static gboolean
-games_card_theme_load_theme_scalable (GamesCardTheme * theme,
-                                      const gchar * theme_name)
-{
-  GamesPreimage *preimage;
-  const char *theme_dir, *slot_dir, *env;
-  gchar *filename, *path;
-
-#ifdef INSTRUMENT_LOADING
-  clock_t t1, t2;
-
-  t1 = clock ();
-#endif
-
-  if (theme->theme_data.scalable.cards_preimage != NULL)
-    return TRUE;
-
-  theme_dir = theme->theme_dir;
-  if (!theme_dir)
-    return FALSE;
-
-  /* First try and load the given file. */
-  filename = g_strdup_printf ("%s.svg", theme_name);
-  path = g_build_filename (theme_dir, filename, NULL);
-  preimage = games_preimage_new_from_file (path, NULL);
-  g_free (path);
-
-  /* Failing that, try and find a similar file (e.g. a suffix change). */
-  if (!preimage) {
-    path = games_find_similar_file (filename, theme_dir);
-    if (path) {
-      preimage = games_preimage_new_from_file (path, NULL);
-      g_free (path);
-    }
-  }
-
-  g_free (filename);
-
-  if (!preimage)
-    goto out;
-
-#if GTK_CHECK_VERSION (2, 10, 0)
-  if (theme->font_options) {
-    games_preimage_set_font_options (preimage, theme->font_options);
-  }
-#endif
-
-  theme->theme_data.scalable.cards_preimage = preimage;
-  theme->prescaled = games_preimage_is_scalable (preimage);
-
-  /* If we don't have a scalable format, build a scaled pixbuf that we'll cut up later */
-  if (!theme->prescaled) {
-    theme->theme_data.scalable.source =
-      games_preimage_render_unscaled_pixbuf (theme->theme_data.scalable.
-                                             cards_preimage);
-  }
-
-  /* And the slot image */
-  /* FIXMEchpe: use uninstalled data dir for rendering the card theme! */
-  slot_dir = games_runtime_get_directory (GAMES_RUNTIME_PIXMAP_DIRECTORY);
-  path = g_build_filename (slot_dir, "slot.svg", NULL);
-  theme->theme_data.scalable.slot_preimage = games_preimage_new_from_file (path, NULL);
-  g_free (path);
-  g_return_val_if_fail (theme->theme_data.scalable.slot_preimage != NULL, FALSE);
-
-#if GTK_CHECK_VERSION (2, 10, 0)
-  if (theme->font_options) {
-    games_preimage_set_font_options (theme->theme_data.scalable.slot_preimage,
-                                     theme->font_options);
-  }
-#endif
-
-  /* Use subrendering by default, but allow to override with the env var */
-  theme->subrender = TRUE;
-
-  env = g_getenv ("GAMES_CARDS_SUBRENDERING");
-  if (env != NULL) {
-    theme->subrender = g_ascii_strtoull (env, NULL, 0) != 0;
-  }
-#ifdef GNOME_ENABLE_DEBUG
-  if (theme->subrender)
-    g_print ("Using subrendering for theme \"%s\"\n", theme_name);
-  else
-    g_print ("Not using subrendering for theme \"%s\"\n", theme_name);
-#endif
-
-out:
-
-#ifdef INSTRUMENT_LOADING
-  t2 = clock ();
-  totaltime += (t2 - t1);
-  g_print ("took %.3fs to create preimage (cumulative %.3fs)\n",
-           (t2 - t1) * 1.0 / CLOCKS_PER_SEC,
-           totaltime * 1.0 / CLOCKS_PER_SEC);
-#endif
-
-  if (theme->theme_data.scalable.cards_preimage == NULL) {
-    games_card_theme_clear_theme_data (theme);
-  }
-
-  return theme->theme_data.scalable.cards_preimage != NULL;
-}
-
-#endif /* HAVE_RSVG */
-
 static gboolean
-games_card_theme_load_theme_prerendered (GamesCardTheme * theme,
-                                         const gchar * theme_name)
+games_card_theme_load_theme (GamesCardTheme *theme,
+                             const char *theme_dir,
+                             const char *theme_name)
 {
-  GKeyFile *key_file;
-  const char *theme_dir;
-  char *filename, *path;
-  GError *error = NULL;
-  int *sizes = NULL;
-  gsize n_sizes, i;
-  gboolean retval = FALSE;
-
-  theme_dir = games_runtime_get_directory (GAMES_RUNTIME_PRERENDERED_CARDS_DIRECTORY);
-  filename = g_strdup_printf ("%s.card-theme", theme_name);
-  path = g_build_filename (theme_dir, filename, NULL);
-  g_free (filename);
-
-  key_file = g_key_file_new ();
-  if (!g_key_file_load_from_file (key_file, path, 0, &error)) {
-    g_warning ("Failed to load prerendered card theme from %s: %s\n", path,
-               error->message);
-    g_error_free (error);
-    goto loser;
-  }
-
-  sizes =
-    g_key_file_get_integer_list (key_file, "Card Theme", "Sizes", &n_sizes,
-                                 &error);
-  if (error) {
-    g_warning ("Failed to get card sizes: %s\n", error->message);
-    g_error_free (error);
-    goto loser;
-  }
-
-  if (n_sizes == 0) {
-    g_warning ("Card theme contains no sizes\n");
-    goto loser;
-  }
-
-  theme->theme_data.prerendered.card_sizes = g_new (CardSize, n_sizes);
-  theme->theme_data.prerendered.n_card_sizes = n_sizes;
-
-  for (i = 0; i < n_sizes; ++i) {
-    char group[32];
-    GError *err = NULL;
-    int width, height;
-
-    g_snprintf (group, sizeof (group), "%d", sizes[i]);
-
-    width = g_key_file_get_integer (key_file, group, "Width", &err);
-    if (err) {
-      g_warning ("Error loading width for size %d: %s\n", sizes[i],
-                 err->message);
-      g_error_free (err);
-      goto loser;
-    }
-    height = g_key_file_get_integer (key_file, group, "Height", &err);
-    if (err) {
-      g_warning ("Error loading height for size %d: %s\n", sizes[i],
-                 err->message);
-      g_error_free (err);
-      goto loser;
-    }
-
-    theme->theme_data.prerendered.card_sizes[i].width = width;
-    theme->theme_data.prerendered.card_sizes[i].height = height;
-  }
-
-  retval = TRUE;
-
-loser:
-
-  g_free (sizes);
-
-  g_key_file_free (key_file);
-  g_free (path);
-
-  if (!retval) {
-    games_card_theme_clear_theme_data (theme);
-  }
-
-  return retval;
+  return theme->klass->load_theme (theme, theme_dir, theme_name, NULL);
 }
 
 static gboolean
-games_card_theme_load_theme (GamesCardTheme * theme, const gchar * theme_name)
+games_card_theme_load_theme_with_fallback (GamesCardTheme *theme,
+                                           const char *theme_dir,
+                                           const char *theme_name)
 {
-  gboolean success;
-
-#ifdef HAVE_RSVG
-  if (theme->use_scalable) {
-    success = games_card_theme_load_theme_scalable (theme, theme_name);
-  } else
-#endif /* HAVE_RSVG */
-  {
-    success = games_card_theme_load_theme_prerendered (theme, theme_name);
-  }
-
-  if (success) {
-    g_free (theme->theme_name);
-    theme->theme_name = g_strdup (theme_name);
-
-    theme->theme_loaded = TRUE;
-  }
-
-  return success;
-}
+  if (games_card_theme_load_theme (theme, theme_dir, theme_name))
+    return TRUE;
 
-static gboolean
-games_card_theme_load_theme_with_fallback (GamesCardTheme * theme,
-                                           const gchar * theme_name)
-{
-  if (games_card_theme_load_theme (theme, theme_name))
+  // FIXMEchpe: compare strict dir equality, not just != NULL
+  /* Try fallback in default theme directory */
+  if (theme_dir != NULL &&
+      games_card_theme_load_theme (theme, NULL, theme_name))
     return TRUE;
 
   g_warning ("Failed to load theme '%s'; trying fallback theme '%s'",
              theme_name, GAMES_CARD_THEME_DEFAULT);
 
   if (strcmp (theme_name, GAMES_CARD_THEME_DEFAULT) != 0 &&
-      games_card_theme_load_theme (theme, GAMES_CARD_THEME_DEFAULT))
+      (games_card_theme_load_theme (theme, theme_dir, GAMES_CARD_THEME_DEFAULT)))
+    return FALSE;
+  if (theme_dir != NULL &&
+      strcmp (theme_name, GAMES_CARD_THEME_DEFAULT) != 0 &&
+      (games_card_theme_load_theme (theme, NULL, GAMES_CARD_THEME_DEFAULT)))
     return FALSE;
 
   g_warning ("Failed to load fallback theme!");
@@ -383,220 +85,34 @@
   return FALSE;
 }
 
-#ifdef HAVE_RSVG
-
-static gboolean
-games_card_theme_prerender_scalable (GamesCardTheme * theme)
-{
-#ifdef INSTRUMENT_LOADING
-  clock_t t1, t2;
-
-  t1 = clock ();
-#endif
-
-  g_return_val_if_fail (theme->use_scalable, FALSE);
-  g_return_val_if_fail (theme->theme_data.scalable.cards_preimage != NULL, FALSE);
-  g_return_val_if_fail (theme->prescaled
-                        || theme->theme_data.scalable.source != NULL, FALSE);
-
-  theme->theme_data.scalable.source =
-    games_preimage_render (theme->theme_data.scalable.cards_preimage,
-                           theme->card_size.width * 13,
-                           theme->card_size.height * 5);
-  if (!theme->theme_data.scalable.source)
-    return FALSE;
-
-  theme->theme_data.scalable.subsize.width =
-    gdk_pixbuf_get_width (theme->theme_data.scalable.source) / 13;
-  theme->theme_data.scalable.subsize.height =
-    gdk_pixbuf_get_height (theme->theme_data.scalable.source) / 5;
-
-#ifdef INSTRUMENT_LOADING
-  t2 = clock ();
-  g_print ("took %.3fs to prerender\n", (t2 - t1) * 1.0 / CLOCKS_PER_SEC);
-#endif
-
-  return TRUE;
-}
-
-static GdkPixbuf *
-games_card_theme_render_card (GamesCardTheme * theme, int card_id)
-{
-  GamesPreimage *preimage = theme->theme_data.scalable.cards_preimage;
-  GdkPixbuf *subpixbuf, *card_pixbuf;
-  int suit, rank;
-
-  if (!theme->theme_loaded)
-    return NULL;
-
-  g_return_val_if_fail (theme->use_scalable, NULL);
-
-  suit = card_id / 13;
-  rank = card_id % 13;
-
-  if (G_UNLIKELY (card_id == GAMES_CARD_SLOT)) {
-    subpixbuf = games_preimage_render (theme->theme_data.scalable.slot_preimage,
-                                       theme->card_size.width,
-                                       theme->card_size.height);
-
-    return subpixbuf;
-  }
-
-  if (theme->subrender) {
-    double card_width, card_height;
-    double width, height;
-    double offsetx, offsety;
-    double zoomx, zoomy;
-    char node[64];
-
-    card_width = ((double) games_preimage_get_width (preimage)) / N_COLS;
-    card_height = ((double) games_preimage_get_height (preimage)) / N_ROWS;
-
-    width = theme->card_size.width - 2 * DELTA;
-    height = theme->card_size.height - 2 * DELTA;
-
-    offsetx = -((double) rank) * card_width + DELTA;
-    offsety = -((double) suit) * card_height + DELTA;
-
-    zoomx = width / card_width;
-    zoomy = height / card_height;
-
-    games_card_get_node_by_suit_and_rank_snprintf (node, sizeof (node), suit, rank);
-
-    subpixbuf = games_preimage_render_sub (preimage,
-                                           node,
-                                           theme->card_size.width, theme->card_size.height,
-                                           offsetx, offsety,
-                                           zoomx, zoomy);
-
-    return subpixbuf;
-  }
-
-  /* Not using subrendering */
-  if (!theme->theme_data.scalable.source &&
-      !games_card_theme_prerender_scalable (theme))
-    return NULL;
-
-  subpixbuf = gdk_pixbuf_new_subpixbuf (theme->theme_data.scalable.source,
-                                        rank *
-                                        theme->theme_data.scalable.subsize.width,
-                                        suit *
-                                        theme->theme_data.scalable.subsize.height,
-                                        theme->theme_data.scalable.subsize.width,
-                                        theme->theme_data.scalable.subsize.height);
-  if (theme->prescaled) {
-    card_pixbuf = subpixbuf;
-  } else {
-    card_pixbuf = gdk_pixbuf_scale_simple (subpixbuf,
-                                           theme->card_size.width,
-                                           theme->card_size.height,
-                                           GDK_INTERP_BILINEAR);
-    g_object_unref (subpixbuf);
-  }
-
-  return card_pixbuf;
-}
-
-#endif /* HAVE_RSVG */
-
-static GdkPixbuf *
-games_card_theme_load_card (GamesCardTheme * theme, int card_id)
-{
-  GdkPixbuf *pixbuf;
-  GError *error = NULL;
-  char name[64], filename[64];
-  char *path;
-
-  if (!theme->theme_loaded || !theme->size_available)
-    return NULL;
-
-  g_return_val_if_fail (!theme->use_scalable, NULL);
-
-  games_card_get_name_by_id_snprintf (name, sizeof (name), card_id);
-  g_snprintf (filename, sizeof (filename), "%s.png", name);
-  path = g_build_filename (theme->theme_data.prerendered.themesizepath, filename, NULL);
-
-  pixbuf = gdk_pixbuf_new_from_file (path, &error);
-  if (!pixbuf) {
-    g_warning ("Failed to load card image %s: %s\n", filename,
-               error->message);
-    g_error_free (error);
-    return NULL;
-  }
-  g_free (path);
-
-  return pixbuf;
-}
-
 /* Class implementation */
 
-G_DEFINE_TYPE (GamesCardTheme, games_card_theme, G_TYPE_OBJECT);
+G_DEFINE_ABSTRACT_TYPE (GamesCardTheme, games_card_theme, G_TYPE_OBJECT);
 
 static void
-games_card_theme_finalize (GObject * object)
+games_card_theme_init (GamesCardTheme * theme)
 {
-  GamesCardTheme *theme = GAMES_CARD_THEME (object);
-
-  games_card_theme_clear_source_pixbuf (theme);
-
-  games_card_theme_clear_theme_data (theme);
-
-  g_free (theme->theme_name);
-  g_free (theme->theme_dir);
-
-#if GTK_CHECK_VERSION (2, 10, 0)
-  if (theme->font_options) {
-    cairo_font_options_destroy (theme->font_options);
-  }
-#endif
-
-  G_OBJECT_CLASS (games_card_theme_parent_class)->finalize (object);
 }
 
-static void
-games_card_theme_init (GamesCardTheme * cardtheme)
+static GObject *
+games_card_theme_constructor (GType type,
+                              guint n_construct_properties,
+                              GObjectConstructParam *construct_params)
 {
-  cardtheme->card_size.width = cardtheme->card_size.height = -1;
-  cardtheme->theme_name = NULL;
+  GObject *object;
+  GamesCardTheme *theme;
 
-  cardtheme->prescaled = FALSE;
+  object = G_OBJECT_CLASS (games_card_theme_parent_class)->constructor
+             (type, n_construct_properties, construct_params);
 
-#ifdef HAVE_RSVG
-  cardtheme->subrender = FALSE;
-  cardtheme->use_scalable = TRUE;
-#else
-  cardtheme->use_scalable = FALSE;
-#endif /* HAVE_RSVG */
-}
+  theme = GAMES_CARD_THEME (object);
 
-static void
-games_card_theme_set_property (GObject * object,
-                               guint prop_id,
-                               const GValue * value, GParamSpec * pspec)
-{
-  GamesCardTheme *theme = GAMES_CARD_THEME (object);
-
-  switch (prop_id) {
-  case PROP_SCALABLE: {
-    gboolean use_scalable = (g_value_get_boolean (value) != FALSE);
-
-#ifndef HAVE_RSVG
-    if (use_scalable) {
-      g_warning ("Cannot enable scalable cards since RSVG support is not compiled in\n");
-      use_scalable = FALSE;
-    }
-#endif
-    theme->use_scalable = use_scalable; 
-    break;
-  }
-  case PROP_THEME_DIRECTORY:
-    theme->theme_dir = g_value_dup_string (value);
-    if (!theme->theme_dir)
-      theme->theme_dir = g_strdup (games_runtime_get_directory (theme->use_scalable ? GAMES_RUNTIME_SCALABLE_CARDS_DIRECTORY
-                                                                                    : GAMES_RUNTIME_PRERENDERED_CARDS_DIRECTORY));
+  /* NOTE! We have to do this here, since it returns the wrong class
+   * (GamesCardThemeClass) when called in games_card_theme_init() !
+   */
+  theme->klass = GAMES_CARD_THEME_GET_CLASS (theme);
 
-    break;
-  }
+  return object;
 }
 
 static void
@@ -604,8 +120,7 @@
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
-  gobject_class->set_property = games_card_theme_set_property;
-  gobject_class->finalize = games_card_theme_finalize;
+  gobject_class->constructor = games_card_theme_constructor;
 
   /**
    * GamesCardTheme:changed:
@@ -624,48 +139,18 @@
                    g_cclosure_marshal_VOID__VOID,
                    G_TYPE_NONE,
                    0, NULL);
-
-  g_object_class_install_property
-    (gobject_class,
-     PROP_SCALABLE,
-     g_param_spec_boolean ("scalable", NULL, NULL,
-                           FALSE,
-                           G_PARAM_WRITABLE |
-                           G_PARAM_STATIC_NAME |
-                           G_PARAM_STATIC_NICK |
-                           G_PARAM_STATIC_BLURB |
-                           G_PARAM_CONSTRUCT_ONLY));
-  g_object_class_install_property
-    (gobject_class,
-     PROP_THEME_DIRECTORY,
-     g_param_spec_string ("theme-directory", NULL, NULL,
-                          NULL,
-                          G_PARAM_WRITABLE |
-                          G_PARAM_STATIC_NAME |
-                          G_PARAM_STATIC_NICK |
-                          G_PARAM_STATIC_BLURB |
-                          G_PARAM_CONSTRUCT_ONLY));
 }
 
-/* public API */
+/* private API */
 
-/**
- * games_card_theme_new:
- * @theme_dir: the directory to load the theme data from, or %NULL to use
- * the default directory
- * @scalable: whether to use scalable themes, or prerendered themes
- *
- * Returns: a new #GamesCardTheme
- */
-GamesCardTheme *
-games_card_theme_new (const char *theme_dir, gboolean scalable)
+void
+_games_card_theme_emit_changed (GamesCardTheme *theme)
 {
-  return g_object_new (GAMES_TYPE_CARD_THEME,
-                       "scalable", scalable,
-                       "theme-directory", theme_dir,
-                       NULL);
+  g_signal_emit (theme, signals[CHANGED], 0);
 }
 
+/* public API */
+
 #if GTK_CHECK_VERSION (2, 10, 0)
 
 /**
@@ -676,28 +161,15 @@
  * Sets the font options to use when drawing the card images.
  */
 void
-games_card_theme_set_font_options (GamesCardTheme * theme,
+games_card_theme_set_font_options (GamesCardTheme *theme,
                                    const cairo_font_options_t *font_options)
 {
   g_return_if_fail (GAMES_IS_CARD_THEME (theme));
 
-  if (font_options &&
-      theme->font_options &&
-      cairo_font_options_equal (font_options, theme->font_options))
+  if (!theme->klass->set_font_options)
     return;
 
-  if (theme->font_options) {
-    cairo_font_options_destroy (theme->font_options);
-  }
-
-  if (font_options) {
-    theme->font_options = cairo_font_options_copy (font_options);
-  } else {
-    theme->font_options = NULL;
-  }
-
-  games_card_theme_clear_source_pixbuf (theme);
-  g_signal_emit (theme, signals[CHANGED], 0);
+  theme->klass->set_font_options (theme, font_options);
 }
 
 #endif /* GTK 2.10.0 */
@@ -705,6 +177,7 @@
 /**
  * games_card_theme_set_theme:
  * @theme:
+ * @theme_dir: the theme directory, or %NULL to use the default
  * @theme_name: the name of the theme to load
  *
  * Loads the card theme @theme_name. If the card theme cannot be loaded,
@@ -716,23 +189,14 @@
  * Returns: %TRUE iff loading the new card theme succeeded
  */
 gboolean
-games_card_theme_set_theme (GamesCardTheme * theme, const gchar * theme_name)
+games_card_theme_set_theme (GamesCardTheme *theme,
+                            const char *theme_dir,
+                            const char *theme_name)
 {
   g_return_val_if_fail (GAMES_IS_CARD_THEME (theme), FALSE);
   g_return_val_if_fail (theme_name != NULL && theme_name[0] != '\0', FALSE);
 
-  if (theme->theme_name != NULL
-      && strcmp (theme_name, theme->theme_name) == 0)
-    return TRUE;
-
-  games_card_theme_clear_source_pixbuf (theme);
-  games_card_theme_clear_theme_data (theme);
-  g_signal_emit (theme, signals[CHANGED], 0);
-
-  theme->card_size.width = theme->card_size.height = theme->slot_size.width =
-    theme->slot_size.width = -1;
-
-  return games_card_theme_load_theme_with_fallback (theme, theme_name);
+  return games_card_theme_load_theme_with_fallback (theme, theme_dir, theme_name);
 }
 
 /**
@@ -742,12 +206,12 @@
  * Returns: the name of the currently loaded card theme, or %NULL if no theme
  * is loaded
  */
-const gchar *
-games_card_theme_get_theme (GamesCardTheme * theme)
+const char *
+games_card_theme_get_theme (GamesCardTheme *theme)
 {
   g_return_val_if_fail (GAMES_IS_CARD_THEME (theme), NULL);
 
-  return theme->theme_name;
+  return theme->klass->get_theme_name (theme);
 }
 
 /**
@@ -766,105 +230,14 @@
  * Returns: %TRUE iff the card size was changed
  */
 gboolean
-games_card_theme_set_size (GamesCardTheme * theme,
-                           gint width, gint height, gdouble proportion)
+games_card_theme_set_size (GamesCardTheme *theme,
+                           int width,
+                           int height,
+                           double proportion)
 {
-  if (!theme->theme_loaded) {
-    g_warning ("Theme not loaded yet; cannot set size!");
-    return FALSE;
-  }
-
-  if ((width == theme->slot_size.width) &&
-      (height == theme->slot_size.height))
-    return FALSE;
-
-  theme->slot_size.width = width;
-  theme->slot_size.height = height;
-
-#ifdef HAVE_RSVG
-  if (theme->use_scalable) {
-    double aspect_ratio, twidth, theight;
-
-    /* Now calculate the card size: find the maximum size that fits
-     * into the given area, preserving the card's aspect ratio.
-     */
-    aspect_ratio = games_card_theme_get_aspect (theme);
-
-    twidth = proportion * width;
-    theight = proportion * height;
-    if (twidth / theight < aspect_ratio) {
-      theight = twidth / aspect_ratio;
-    } else {
-      twidth = theight * aspect_ratio;
-    }
-
-    if (theme->card_size.width == (int) twidth
-        && theme->card_size.height == (int) theight)
-      return FALSE;
-
-    theme->card_size.width = twidth;
-    theme->card_size.height = theight;
-
-  } else
-#endif /* HAVE_RSVG */
-  {
-    guint i;
-    int twidth, theight;
-    CardSize size = { -1, -1 }, fit_size = { -1, -1};
-
-    twidth = FLOAT_TO_INT_CEIL (((double) width) * proportion);
-    theight = FLOAT_TO_INT_CEIL (((double) height) * proportion);
-
-    /* Find the closest prerendered size */
-    for (i = 0; i < theme->theme_data.prerendered.n_card_sizes; ++i) {
-      CardSize info = theme->theme_data.prerendered.card_sizes[i];
-
-      if (info.width > width || info.height > height)
-        continue;
-
-      if (info.width > fit_size.width && info.height > fit_size.height)
-        fit_size = info;
-
-      /* FIXMEchpe */
-      if (info.width <= twidth && info.height <= theight &&
-          info.width > size.width && info.height > size.height)
-        size = info;
-    }
-
-    if (size.width < 0 || size.height < 0)
-      size = fit_size;
-
-    if (size.width > 0 && size.height > 0) {
-      char sizestr[16];
-
-      if (size.width == theme->card_size.width &&
-          size.height == theme->card_size.height)
-        return FALSE;
-
-      g_free (theme->theme_data.prerendered.themesizepath);
-
-      g_snprintf (sizestr, sizeof (sizestr), "%d", size.width);
-      theme->theme_data.prerendered.themesizepath =
-        g_build_filename (theme->theme_dir, theme->theme_name, sizestr, NULL);
-
-      theme->size_available = TRUE;
-      theme->card_size = size;
-    } else {
-      g_warning ("No prerendered size available for %d:%d\n", width, height);
-      theme->size_available = FALSE;
-
-      /* FIXMEchpe: at least use the smallest available size here, or
-       * programme will surely crash when trying to render NULL pixbufs
-       * later on!
-       */
-      return FALSE;
-    }
-  }
-
-  games_card_theme_clear_source_pixbuf (theme);
-  g_signal_emit (theme, signals[CHANGED], 0);
+  g_return_val_if_fail (GAMES_IS_CARD_THEME (theme), FALSE);
 
-  return TRUE;
+  return theme->klass->set_card_size (theme, width, height, proportion);
 }
 
 /**
@@ -874,9 +247,9 @@
  * Returns: the currently selected card size
  */
 CardSize
-games_card_theme_get_size (GamesCardTheme * theme)
+games_card_theme_get_size (GamesCardTheme *theme)
 {
-  return theme->card_size;
+  return theme->klass->get_card_size (theme);
 }
 
 /**
@@ -888,25 +261,9 @@
 double
 games_card_theme_get_aspect (GamesCardTheme * theme)
 {
-  double aspect;
-
   g_return_val_if_fail (GAMES_IS_CARD_THEME (theme), 1.0);
 
-#ifdef HAVE_RSVG
-  if (theme->use_scalable) {
-    aspect =
-      (((double) games_preimage_get_width (theme->theme_data.scalable.cards_preimage))
-       * N_ROWS) /
-      (((double) games_preimage_get_height (theme->theme_data.scalable.cards_preimage))
-       * N_COLS);
-  } else
-#endif
-  {
-    aspect =
-      ((double) theme->card_size.width) / ((double) theme->card_size.height);
-  }
-
-  return aspect;
+  return theme->klass->get_card_aspect (theme);
 }
 
 /**
@@ -933,14 +290,7 @@
   t1 = clock ();
 #endif
 
-#ifdef HAVE_RSVG
-  if (theme->use_scalable) {
-    pixbuf = games_card_theme_render_card (theme, card_id);
-  } else
-#endif /* HAVE_RSVG */
-  {
-    pixbuf = games_card_theme_load_card (theme, card_id);
-  }
+  pixbuf = theme->klass->get_card_pixbuf (theme, card_id);
 
 #ifdef INSTRUMENT_LOADING
   t2 = clock ();

Modified: trunk/libgames-support/games-card-theme.h
==============================================================================
--- trunk/libgames-support/games-card-theme.h	(original)
+++ trunk/libgames-support/games-card-theme.h	Tue Jan  6 18:17:59 2009
@@ -1,6 +1,6 @@
 /*
   Copyright  2004 Callum McKenzie
-  Copyright  2007 Christian Persch
+  Copyright  2007, 2008 Christian Persch
 
   This library is free software; you can redistribute it and'or modify
   it under the terms of the GNU Library General Public License as published
@@ -28,12 +28,20 @@
 
 G_BEGIN_DECLS
 
+#define GAMES_CARD_THEME_ERROR  (g_quark_from_static_string ("games-card-theme"))
+
+typedef enum {
+  GAMES_CARD_THEME_ERROR_GENERIC = 0
+} GamesCardThemeError;
+
+/* GamesCardTheme */
+
 #define GAMES_TYPE_CARD_THEME            (games_card_theme_get_type ())
 #define GAMES_CARD_THEME(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAMES_TYPE_CARD_THEME, GamesCardTheme))
 #define GAMES_CARD_THEME_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAMES_TYPE_CARD_THEME, GamesCardThemeClass))
 #define GAMES_IS_CARD_THEME(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAMES_TYPE_CARD_THEME))
 #define GAMES_IS_CARD_THEME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAMES_TYPE_CARD_THEME))
-#define GAMES_CARD_THEME_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAMES_TYPE_CARD_THEME))
+#define GAMES_CARD_THEME_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAMES_TYPE_CARD_THEME, GamesCardThemeClass))
 
 typedef struct {
   gint width;
@@ -45,29 +53,60 @@
 
 GType games_card_theme_get_type (void);
 
-GamesCardTheme *games_card_theme_new (const char *theme_dir,
-                                      gboolean scalable);
-
 #if GTK_CHECK_VERSION (2, 10, 0)
 void games_card_theme_set_font_options (GamesCardTheme *theme,
                                         const cairo_font_options_t *font_options);
 #endif
 
-gboolean games_card_theme_set_theme (GamesCardTheme * theme,
-                                     const gchar * name);
+gboolean games_card_theme_set_theme (GamesCardTheme *theme,
+                                     const char *theme_dir,
+                                     const char *theme_name);
 
 const gchar *games_card_theme_get_theme (GamesCardTheme * theme);
 
 gboolean games_card_theme_set_size (GamesCardTheme * theme,
-                                    gint width,
-                                    gint height, gdouble proportion);
+                                    int width,
+                                    int height,
+                                    double proportion);
 
 CardSize games_card_theme_get_size (GamesCardTheme * theme);
 
 double games_card_theme_get_aspect (GamesCardTheme * theme);
 
 GdkPixbuf *games_card_theme_get_card_pixbuf (GamesCardTheme * theme,
-                                             gint cardid);
+                                             int cardid);
+
+/* GamesCardThemeSVG */
+
+#define GAMES_TYPE_CARD_THEME_SVG            (games_card_theme_svg_get_type ())
+#define GAMES_CARD_THEME_SVG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAMES_TYPE_CARD_THEME_SVG, GamesCardThemeSVG))
+#define GAMES_CARD_THEME_SVG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAMES_TYPE_CARD_THEME_SVG, GamesCardThemeSVGClass))
+#define GAMES_IS_CARD_THEME_SVG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAMES_TYPE_CARD_THEME_SVG))
+#define GAMES_IS_CARD_THEME_SVG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAMES_TYPE_CARD_THEME_SVG))
+#define GAMES_CARD_THEME_SVG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAMES_TYPE_CARD_THEME_SVG, GamesCardThemeSVGClass))
+
+typedef struct _GamesCardThemeSVGClass GamesCardThemeSVGClass;
+typedef struct _GamesCardThemeSVG      GamesCardThemeSVG;
+
+GType games_card_theme_svg_get_type (void);
+
+GamesCardTheme* games_card_theme_svg_new (void);
+
+/* GamesCardThemeFixed */
+
+#define GAMES_TYPE_CARD_THEME_FIXED            (games_card_theme_fixed_get_type ())
+#define GAMES_CARD_THEME_FIXED(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAMES_TYPE_CARD_THEME_FIXED, GamesCardThemeFixed))
+#define GAMES_CARD_THEME_FIXED_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GAMES_TYPE_CARD_THEME_FIXED, GamesCardThemeFixedClass))
+#define GAMES_IS_CARD_THEME_FIXED(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAMES_TYPE_CARD_THEME_FIXED))
+#define GAMES_IS_CARD_THEME_FIXED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAMES_TYPE_CARD_THEME_FIXED))
+#define GAMES_CARD_THEME_FIXED_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GAMES_TYPE_CARD_THEME_FIXED, GamesCardThemeFixedClass))
+
+typedef struct _GamesCardThemeFixedClass GamesCardThemeFixedClass;
+typedef struct _GamesCardThemeFixed      GamesCardThemeFixed;
+
+GType games_card_theme_fixed_get_type (void);
+
+GamesCardTheme* games_card_theme_fixed_new (void);
 
 G_END_DECLS
 

Modified: trunk/libgames-support/render-cards.c
==============================================================================
--- trunk/libgames-support/render-cards.c	(original)
+++ trunk/libgames-support/render-cards.c	Tue Jan  6 18:17:59 2009
@@ -130,7 +130,7 @@
     goto loser;
   }
 
-  theme = games_card_theme_new (NULL, TRUE);
+  theme = games_card_theme_svg_new ();
 
   if (antialias_set) {
     cairo_font_options_t *font_options;
@@ -142,7 +142,7 @@
     cairo_font_options_destroy (font_options);
   }
 
-  if (!games_card_theme_set_theme (theme, theme_name)) {
+  if (!games_card_theme_set_theme (theme, theme_dir, theme_name)) {
     g_warning ("Failed to load theme '%s'\n", theme_name);
     goto loser;
   }



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