[gnome-games] aisleriot: Fix build with gtk3
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games] aisleriot: Fix build with gtk3
- Date: Thu, 12 Aug 2010 21:24:10 +0000 (UTC)
commit 7ad7aad4652fd286a0a2f15d67258cc96092bb9c
Author: Christian Persch <chpe gnome org>
Date: Thu Aug 12 12:59:43 2010 +0200
aisleriot: Fix build with gtk3
Finish cairo drawing code.
aisleriot/ar-cursor.c | 84 ++++++++-
aisleriot/board-noclutter.c | 309 ++++++++++++++++++-----------
aisleriot/lib/Makefile.am | 15 ++-
aisleriot/lib/ar-card-surface-cache.c | 349 +++++++++++++++++++++++++++++++++
aisleriot/lib/ar-card-surface-cache.h | 74 +++++++
aisleriot/lib/ar-card-theme-private.h | 2 +
aisleriot/lib/ar-card-theme.c | 60 ++++++
aisleriot/lib/ar-card-theme.h | 7 +-
configure.in | 3 +
libgames-support/games-preimage.c | 111 +++++++----
libgames-support/games-preimage.h | 10 +
11 files changed, 865 insertions(+), 159 deletions(-)
---
diff --git a/aisleriot/ar-cursor.c b/aisleriot/ar-cursor.c
index 00f7e49..b10ae98 100644
--- a/aisleriot/ar-cursor.c
+++ b/aisleriot/ar-cursor.c
@@ -20,10 +20,57 @@
#include "ar-cursor.h"
+#include <gtk/gtk.h>
+
#ifndef HAVE_HILDON
/* These cursors borrowed from EOG */
/* FIXMEchpe use themeable cursors here! */
+
+#if GTK_CHECK_VERSION (2, 90, 6)
+
+#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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0xb0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00,
+ 0xe0, 0xff, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 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,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00,
+ 0xc0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00,
+ 0xf0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00,
+ 0x80, 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
+ 0x60, 0x36, 0x00, 0x00, 0x60, 0x36, 0x00, 0x00, 0xc0, 0x36, 0x01, 0x00, 0xc0, 0xb6, 0x01, 0x00,
+ 0x80, 0xbf, 0x01, 0x00, 0x98, 0xff, 0x01, 0x00, 0xb8, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00,
+ 0xe0, 0xff, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x3f, 0x00, 0x00,
+ 0xf0, 0x7f, 0x00, 0x00, 0xf0, 0x7f, 0x01, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x03, 0x00,
+ 0xd8, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00,
+ 0xf0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00,
+ 0x80, 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#else
+
#define hand_closed_data_width 20
#define hand_closed_data_height 20
static const char hand_closed_data_bits[] = {
@@ -64,6 +111,8 @@ static const char hand_open_mask_bits[] = {
0x80, 0x7f, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+#endif /* GTK 2.90.6 */
+
static GdkCursor *
ar_cursor_new_from_data (GdkWindow *window,
const char *data,
@@ -71,14 +120,47 @@ ar_cursor_new_from_data (GdkWindow *window,
{
const GdkColor fg = { 0, 65535, 65535, 65535 };
const GdkColor bg = { 0, 0, 0, 0 };
+ GdkCursor *cursor;
GdkPixmap *source;
GdkPixmap *mask;
- GdkCursor *cursor;
+#if GTK_CHECK_VERSION (2, 90, 6)
+ cairo_surface_t *image;
+ cairo_t *cr;
+
+ /* Yeah, hard-coded sizes are bad. */
+ source = gdk_pixmap_new (window, 20, 20, 1);
+
+ cr = gdk_cairo_create (source );
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ image = cairo_image_surface_create_for_data ((guchar *) data,
+ CAIRO_FORMAT_A1,
+ 20, 20, 4);
+ cairo_set_source_surface (cr, image, 0, 0);
+ cairo_surface_destroy (image);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ /* Yeah, hard-coded sizes are bad. */
+ mask = gdk_pixmap_new (window, 20, 20, 1);
+
+ cr = gdk_cairo_create (mask);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ image = cairo_image_surface_create_for_data ((guchar *) mask_data,
+ CAIRO_FORMAT_A1,
+ 20, 20, 4);
+ cairo_set_source_surface (cr, image, 0, 0);
+ cairo_surface_destroy (image);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+#else
/* 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);
+#endif /* GTK 2.90.6 */
+
cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 10, 10);
g_object_unref (source);
diff --git a/aisleriot/board-noclutter.c b/aisleriot/board-noclutter.c
index cbff1b7..53c426b 100644
--- a/aisleriot/board-noclutter.c
+++ b/aisleriot/board-noclutter.c
@@ -28,6 +28,10 @@
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
+#if GTK_CHECK_VERSION (2, 90, 6)
+#define CAIRO_DRAWING
+#endif
+
#include <libgames-support/games-files.h>
#include <libgames-support/games-glib-compat.h>
#include <libgames-support/games-gtk-compat.h>
@@ -37,13 +41,14 @@
#include "conf.h"
#include "game.h"
-#include "ar-card-images.h"
#include "ar-cursor.h"
#include "ar-pixbuf-utils.h"
#include "ar-style-gtk.h"
-#if GTK_CHECK_VERSION (2, 90, 6)
-#define CAIRO_DRAWING
+#ifdef CAIRO_DRAWING
+#include "ar-card-surface-cache.h"
+#else
+#include "ar-card-images.h"
#endif
#define AISLERIOT_BOARD_GET_PRIVATE(board)(G_TYPE_INSTANCE_GET_PRIVATE ((board), AISLERIOT_TYPE_BOARD, AisleriotBoardPrivate))
@@ -70,6 +75,9 @@
#define PIXBUF_DRAWING_LIKELIHOOD(cond) (cond)
#endif /* HAVE_HILDON */
+/* FIXMEchpe */
+#define HIGHLIGHT_ALPHA (0.5)
+
#define I_(string) g_intern_static_string (string)
typedef enum {
@@ -116,10 +124,16 @@ struct _AisleriotBoardPrivate
int xbaseoffset;
/* Cards cache */
+#ifdef CAIRO_DRAWING
+ ArCardSurfaceCache *card_cache;
+ cairo_surface_t *slot_surface;
+#else
ArCardImages *images;
/* ArSlot */
gpointer slot_image; /* either a GdkPixbuf or GdkPixmap, depending on drawing mode */
+#endif
+
/* Button press */
int last_click_x;
@@ -721,10 +735,14 @@ slot_update_card_images_full (AisleriotBoard *board,
int highlight_start_card_id)
{
AisleriotBoardPrivate *priv = board->priv;
- ArCardImages *images = priv->images;
GPtrArray *card_images;
guint n_cards, first_exposed_card_id, i;
guint8 *cards;
+#ifdef CAIRO_DRAWING
+ ArCardSurfaceCache *card_cache = priv->card_cache;
+#else
+ ArCardImages *images = priv->images;
+#endif
card_images = slot->card_images;
g_ptr_array_set_size (card_images, 0);
@@ -745,9 +763,15 @@ slot_update_card_images_full (AisleriotBoard *board,
g_ptr_array_add (card_images, NULL);
}
-#ifndef CAIRO_DRAWING
+#ifdef CAIRO_DRAWING
+ for (i = first_exposed_card_id; i < n_cards; ++i) {
+ Card card = CARD (cards[i]);
+
+ g_ptr_array_add (card_images,
+ ar_card_surface_cache_get_card_surface (card_cache, card));
+ }
+#else
if (PIXBUF_DRAWING_LIKELIHOOD (priv->use_pixbuf_drawing)) {
-#endif
for (i = first_exposed_card_id; i < n_cards; ++i) {
Card card = CARD (cards[i]);
gboolean is_highlighted;
@@ -757,7 +781,6 @@ slot_update_card_images_full (AisleriotBoard *board,
g_ptr_array_add (card_images,
ar_card_images_get_card_pixbuf (images, card, is_highlighted));
}
-#ifndef CAIRO_DRAWING
} else {
for (i = first_exposed_card_id; i < n_cards; ++i) {
Card card = CARD (cards[i]);
@@ -769,7 +792,7 @@ slot_update_card_images_full (AisleriotBoard *board,
ar_card_images_get_card_pixmap (images, card, is_highlighted));
}
}
-#endif /* !CAIRO_DRAWING */
+#endif /* CAIRO_DRAWING */
}
static void
@@ -811,6 +834,9 @@ aisleriot_board_setup_geometry (AisleriotBoard *board)
guint i, n_slots;
CardSize card_size;
gboolean size_changed;
+#ifdef CAIRO_DRAWING
+ ArCardTheme *theme;
+#endif
/* Nothing to do yet */
if (aisleriot_game_get_state (priv->game) <= GAME_LOADED)
@@ -822,12 +848,24 @@ aisleriot_board_setup_geometry (AisleriotBoard *board)
priv->xslotstep = ((double) priv->allocation.width) / priv->width;
priv->yslotstep = ((double) priv->allocation.height) / priv->height;
- size_changed = ar_card_images_set_size (priv->images,
- priv->xslotstep,
- priv->yslotstep,
- priv->card_slot_ratio);
+#ifdef CAIRO_DRAWING
+ theme = ar_style_get_card_theme (priv->style);
+ if (theme == NULL)
+ return;
+ size_changed = ar_card_theme_set_size (theme,
+ priv->xslotstep,
+ priv->yslotstep,
+ priv->card_slot_ratio);
+ ar_card_theme_get_size (theme, &card_size);
+#else
+ size_changed = ar_card_images_set_size (priv->images,
+ priv->xslotstep,
+ priv->yslotstep,
+ priv->card_slot_ratio);
ar_card_images_get_size (priv->images, &card_size);
+#endif
+
priv->card_size = card_size;
/* If the cards are too far apart, bunch them in the middle. */
@@ -847,18 +885,18 @@ aisleriot_board_setup_geometry (AisleriotBoard *board)
priv->xoffset = (priv->xslotstep - card_size.width) / 2;
priv->yoffset = (priv->yslotstep - card_size.height) / 2;
-#ifndef CAIRO_DRAWING
+#ifdef CAIRO_DRAWING
+ priv->slot_surface = ar_card_surface_cache_get_slot_surface (priv->card_cache);
+#else
if (PIXBUF_DRAWING_LIKELIHOOD (priv->use_pixbuf_drawing)) {
-#endif
priv->slot_image = ar_card_images_get_slot_pixbuf (priv->images, FALSE);
-#ifndef CAIRO_DRAWING
} else {
priv->slot_image = ar_card_images_get_slot_pixmap (priv->images, FALSE);
}
gdk_gc_set_clip_mask (priv->slot_gc, ar_card_images_get_slot_mask (priv->images));
gdk_gc_set_clip_mask (priv->draw_gc, ar_card_images_get_card_mask (priv->images));
-#endif /* !CAIRO_DRAWING */
+#endif /* CAIRO_DRAWING */
/* NOTE! Updating the slots checks that geometry is set, so
* we set it to TRUE already.
@@ -890,8 +928,7 @@ drag_begin (AisleriotBoard *board)
int delta, height, width;
int x, y;
GdkPixmap *moving_pixmap;
- GdkBitmap *card_mask;
- GdkBitmap *moving_mask;
+ GdkPixmap *moving_mask;
int num_moving_cards;
guint i;
GByteArray *cards;
@@ -903,6 +940,7 @@ drag_begin (AisleriotBoard *board)
#else
const GdkColor masked = { 0, 0, 0, 0 };
const GdkColor unmasked = { 1, 0xffff, 0xffff, 0xffff };
+ GdkBitmap *card_mask;
GdkGC *gc1, *gc2;
gboolean use_pixbuf_drawing = priv->use_pixbuf_drawing;
#endif /* CAIRO_DRAWING */
@@ -986,17 +1024,12 @@ drag_begin (AisleriotBoard *board)
cr2 = gdk_cairo_create (moving_mask);
cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr2);
- cairo_set_operator (cr2, CAIRO_OPERATOR_OVER);
- cairo_set_source_rgba (cr2, 1., 1., 1., 0.);
+ cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgb (cr2, 0., 0., 0.);
- card_mask = ar_card_images_get_card_mask (priv->images);
-
-// gdk_cairo_set_source_pixmap (cr1, card_mask, 0, 0);
-// gdk_cairo_set_source_pixmap (cr2, card_mask, 0, 0);
-
- //FIXME?;
#else
+
gc1 = gdk_gc_new (moving_pixmap);
gc2 = gdk_gc_new (moving_mask);
@@ -1025,26 +1058,24 @@ drag_begin (AisleriotBoard *board)
Card hcard = CARD (priv->moving_cards->data[i]);
#ifdef CAIRO_DRAWING
- GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
- pixbuf = ar_card_images_get_card_pixbuf (priv->images, hcard, FALSE);
- if (!pixbuf)
+ surface = ar_card_surface_cache_get_card_surface (priv->card_cache, hcard);
+ if (surface == NULL)
goto next;
- #if 0
- gdk_draw_pixbuf (moving_pixmap, gc1,
- pixbuf,
- 0, 0, x, y, width, height,
- GDK_RGB_DITHER_NONE, 0, 0);
- gdk_draw_rectangle (moving_mask, gc2, TRUE,
- x, y, width, height);
- #endif
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_matrix_init_translate (&matrix, -x, -y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_set_source (cr1, pattern);
- gdk_cairo_set_source_pixbuf (cr1, pixbuf, x, y);
cairo_paint (cr1);
- gdk_cairo_set_source_pixmap (cr2, card_mask, x, y);
- cairo_paint (cr2);
+ cairo_mask (cr2, pattern);
+
+ cairo_pattern_destroy (pattern);
#else /* !CAIRO_DRAWING */
gdk_gc_set_clip_origin (gc1, x, y);
@@ -2382,22 +2413,19 @@ static void
aisleriot_board_realize (GtkWidget *widget)
{
AisleriotBoard *board = AISLERIOT_BOARD (widget);
- AisleriotBoardPrivate *priv = board->priv;
- GdkDisplay *display;
- GdkWindow *window;
GTK_WIDGET_CLASS (aisleriot_board_parent_class)->realize (widget);
- window = gtk_widget_get_window (widget);
-
- display = gtk_widget_get_display (widget);
-
- ar_card_images_set_drawable (priv->images, window);
-
#ifndef CAIRO_DRAWING
{
+ AisleriotBoardPrivate *priv = board->priv;
+ GdkWindow *window;
GdkColor baize_color;
+ window = gtk_widget_get_window (widget);
+
+ ar_card_images_set_drawable (priv->images, window);
+
priv->draw_gc = gdk_gc_new (window);
priv->bg_gc = gdk_gc_new (window);
@@ -2409,12 +2437,21 @@ aisleriot_board_realize (GtkWidget *widget)
}
#endif /* !CAIRO_DRAWING */
-#ifndef HAVE_HILDON
+#ifndef HAVE_HILDON
+{
+ AisleriotBoardPrivate *priv = board->priv;
+ GdkWindow *window;
+ GdkDisplay *display;
+
+ window = gtk_widget_get_window (widget);
+ display = gtk_widget_get_display (widget);
+
/* Create cursors */
priv->cursor[AR_CURSOR_DEFAULT] = gdk_cursor_new_for_display (display, GDK_LEFT_PTR);
priv->cursor[AR_CURSOR_OPEN] = ar_cursor_new (window, AR_CURSOR_OPEN);
priv->cursor[AR_CURSOR_CLOSED] = ar_cursor_new (window, AR_CURSOR_CLOSED);
priv->cursor[AR_CURSOR_DROPPABLE] = gdk_cursor_new_for_display (display, GDK_DOUBLE_ARROW); /* FIXMEchpe: better cursor */
+}
#endif /* !HAVE_HILDON */
aisleriot_board_setup_geometry (board);
@@ -2431,13 +2468,18 @@ aisleriot_board_unrealize (GtkWidget *widget)
priv->geometry_set = FALSE;
-#ifndef CAIRO_DRAWING
+#ifdef CAIRO_DRAWING
+ priv->slot_surface = NULL;
+#else
g_object_unref (priv->draw_gc);
priv->draw_gc = NULL;
g_object_unref (priv->bg_gc);
priv->bg_gc = NULL;
g_object_unref (priv->slot_gc);
priv->slot_gc = NULL;
+
+ ar_card_images_set_drawable (priv, NULL);
+ priv->slot_image = NULL;
#endif
#ifndef HAVE_HILDON
@@ -2447,12 +2489,8 @@ aisleriot_board_unrealize (GtkWidget *widget)
}
#endif /* !HAVE_HILDON*/
- ar_card_images_set_drawable (priv->images, NULL);
-
clear_state (board);
- priv->slot_image = NULL;
-
GTK_WIDGET_CLASS (aisleriot_board_parent_class)->unrealize (widget);
}
@@ -2485,9 +2523,14 @@ aisleriot_board_sync_style (ArStyle *style,
theme = ar_style_get_card_theme (style);
if (theme != NULL) {
priv->geometry_set = FALSE;
- priv->slot_image = NULL;
+#ifdef CAIRO_DRAWING
+ priv->slot_surface = NULL;
+ ar_card_surface_cache_set_theme (priv->card_cache, theme);
+#else
+ priv->slot_image = NULL;
ar_card_images_set_theme (priv->images, theme);
+#endif
update_geometry |= TRUE;
queue_redraw |= TRUE;
@@ -2555,12 +2598,15 @@ aisleriot_board_sync_style (ArStyle *style,
}
if (pspec_name == NULL || pspec_name == I_(AR_STYLE_PROP_SELECTION_COLOR)) {
+#ifndef CAIRO_DRAWING
GdkColor selection_color;
ar_style_get_selection_color (priv->style, &selection_color);
ar_card_images_set_selection_color (priv->images, &selection_color);
/* FIXMEchpe: update the cached images in the selection slot!! */
+#endif
+
redraw_selection = TRUE;
}
@@ -3136,6 +3182,9 @@ aisleriot_board_expose_event (GtkWidget *widget,
guint n_exposed_slots;
GdkWindow *window;
GdkColor color;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
window = gtk_widget_get_window (widget);
@@ -3167,7 +3216,10 @@ aisleriot_board_expose_event (GtkWidget *widget,
g_print ("Exposing area %d:%d@(%d,%d) ", event->area.width, event->area.height,
event->area.x, event->area.y);
for (i = 0; i < n_rects; ++i) {
- g_print ("[Rect %d:%d@(%d,%d)] ", rects[i].width, rects[i].height, rects[i].x, rects[i].y);
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+ g_print ("[Rect %d:%d@(%d,%d)] ", rect.width, rect.height, rect.x, rect.y);
}
g_print ("\n");
}
@@ -3186,11 +3238,6 @@ aisleriot_board_expose_event (GtkWidget *widget,
for (i = 0; i < n_rects; ++i) {
rect = &rects[i];
-#if 0
- gdk_draw_rectangle (window, priv->bg_gc, TRUE,
- rect->x, rect->y,
- rect->width, rect->height);
-#endif
cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
}
g_free (rects);
@@ -3234,10 +3281,15 @@ aisleriot_board_expose_event (GtkWidget *widget,
/* First draw the slots. Otherwise they'll overlap on cards
* (e.g. in Elevator, after a card was removed).
*/
+ if (priv->slot_surface == NULL)
+ goto draw_cards;
+
+ pattern = cairo_pattern_create_for_surface (priv->slot_surface);
+ cairo_set_source (cr, pattern);
+
for (i = 0; i < n_exposed_slots; ++i) {
ArSlot *hslot = exposed_slots[i];
int x, y;
- GdkPixbuf *pixbuf;
/* FIXMEchpe: if ((hslot->length - hslot->exposed) >= 0) ?? */
if (hslot->cards->len > 0)
@@ -3247,29 +3299,26 @@ aisleriot_board_expose_event (GtkWidget *widget,
x = hslot->rect.x;
y = hslot->rect.y;
- #if 0
- gdk_gc_set_clip_origin (priv->slot_gc, x, y);
- #endif
+ cairo_matrix_init_translate (&matrix, -x, -y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_paint (cr);
- if (G_LIKELY (hslot != highlight_slot)) {
- pixbuf = priv->slot_image;
- } else {
- pixbuf = ar_card_images_get_slot_pixbuf (priv->images,
- priv->show_highlight);
+ if (G_UNLIKELY (hslot == highlight_slot)) {
+ cairo_save (cr);
+ ar_style_get_selection_color (priv->style, &color);
+ cairo_set_source_rgba (cr,
+ color.red / 65535.,
+ color.green / 65535.,
+ color.blue / 65535.,
+ HIGHLIGHT_ALPHA);
+ cairo_mask (cr, pattern);
+ cairo_restore (cr);
}
+ }
- if (!pixbuf)
- continue;
-
- #if 0
- gdk_draw_pixbuf (window, priv->slot_gc, pixbuf, 0, 0, x, y,
- priv->card_size.width, priv->card_size.height,
- GDK_RGB_DITHER_NONE, 0, 0);
- #endif
+ cairo_pattern_destroy (pattern);
- gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
- cairo_paint (cr);
- }
+draw_cards:
/* Now draw the cards */
for (i = 0; i < n_exposed_slots; ++i) {
@@ -3277,13 +3326,22 @@ aisleriot_board_expose_event (GtkWidget *widget,
GByteArray *cards = hslot->cards;
gpointer *card_images = hslot->card_images->pdata;
GdkRectangle card_rect;
- GdkPixbuf *pixbuf;
guint j, n_cards;
+ int highlight_start_card_id = G_MAXINT;
n_cards = cards->len;
if (n_cards == 0)
continue;
+ if (G_UNLIKELY (hslot == priv->highlight_slot &&
+ priv->show_highlight)) {
+ highlight_start_card_id = hslot->cards->len - 1;
+ } else if (G_UNLIKELY (hslot == priv->selection_slot &&
+ priv->selection_start_card_id >= 0 &&
+ priv->show_selection)) {
+ highlight_start_card_id = priv->selection_start_card_id;
+ }
+
card_rect.x = hslot->rect.x;
card_rect.y = hslot->rect.y;
card_rect.width = priv->card_size.width;
@@ -3308,20 +3366,30 @@ aisleriot_board_expose_event (GtkWidget *widget,
goto next;
#endif
- pixbuf = card_images[j];
- if (!pixbuf)
+ surface = card_images[j];
+ if (surface == NULL)
goto next;
- #if 0
- gdk_gc_set_clip_origin (priv->draw_gc, card_rect.x, card_rect.y);
- gdk_draw_pixbuf (window, priv->draw_gc, pixbuf,
- 0, 0, card_rect.x, card_rect.y, -1, -1,
- GDK_RGB_DITHER_NONE, 0, 0);
- #endif
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_matrix_init_translate (&matrix, -card_rect.x, -card_rect.y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
- gdk_cairo_set_source_pixbuf (cr, pixbuf, card_rect.x, card_rect.y);
cairo_paint (cr);
+ if (G_UNLIKELY (j >= highlight_start_card_id)) {
+ cairo_save (cr);
+ ar_style_get_selection_color (priv->style, &color);
+ cairo_set_source_rgba (cr,
+ color.red / 65535.,
+ color.green / 65535.,
+ color.blue / 65535.,
+ HIGHLIGHT_ALPHA);
+ cairo_mask (cr, pattern);
+ cairo_restore (cr);
+ }
+
next:
card_rect.x += hslot->pixeldx;
@@ -3339,25 +3407,23 @@ aisleriot_board_expose_event (GtkWidget *widget,
#endif
{
GdkRectangle card_rect;
- GdkPixbuf *pixbuf;
+ cairo_pattern_t *pattern;
get_rect_by_slot_and_card (board,
priv->show_card_slot,
priv->show_card_id,
1, &card_rect);
- pixbuf = priv->show_card_slot->card_images->pdata[priv->show_card_id];
- if (!pixbuf)
+ surface = priv->show_card_slot->card_images->pdata[priv->show_card_id];
+ if (surface == NULL)
goto draw_focus;
- #if 0
- gdk_gc_set_clip_origin (priv->draw_gc, card_rect.x, card_rect.y);
- gdk_draw_pixbuf (window, priv->draw_gc, pixbuf,
- 0, 0, card_rect.x, card_rect.y, -1, -1,
- GDK_RGB_DITHER_NONE, 0, 0);
- #endif
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_matrix_init_translate (&matrix, -card_rect.x, -card_rect.y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
- gdk_cairo_set_source_pixbuf (cr, pixbuf, card_rect.x, card_rect.y);
cairo_paint (cr);
}
@@ -3368,7 +3434,9 @@ draw_focus:
priv->focus_slot != NULL &&
gtk_widget_has_focus (widget))) {
GdkRectangle focus_rect;
+ double line_width;
+ g_print ("focus!\n");
/* Check whether this needs to be drawn */
#if GTK_CHECK_VERSION (2, 90, 5)
if (cairo_region_contains_rectangle (region, &priv->focus_rect) == CAIRO_REGION_OVERLAP_OUT)
@@ -3388,24 +3456,25 @@ draw_focus:
&focus_rect);
}
- #if 0
- gtk_paint_focus (gtk_widget_get_style (widget),
- window,
- gtk_widget_get_state (widget),
- &priv->focus_rect,
- widget,
- NULL /* FIXME ? */,
- focus_rect.x,
- focus_rect.y,
- focus_rect.width,
- focus_rect.height);
- #endif
- // FIXMEchpe
+ line_width = ar_style_get_focus_line_width (priv->style);
+ cairo_set_source_rgb (cr, 1., 1., 1.); /* FIXME focus line colour? */
+ cairo_set_line_width (cr, line_width);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+
+ cairo_rectangle (cr,
+ focus_rect.x + line_width / 2., focus_rect.y + line_width / 2.,
+ focus_rect.width - line_width, focus_rect.height - line_width);
+ cairo_stroke (cr);
}
expose_done:
#endif /* ENABLE_KEYNAV */
+ #if DEBUG_DRAWING
+ if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
+ g_print ("expose-event cairo status %d\n", cairo_status (cr));
+ }
+ #endif
cairo_destroy (cr);
/* Parent class has no expose handler, no need to chain up */
@@ -3752,9 +3821,11 @@ aisleriot_board_init (AisleriotBoard *board)
priv->moving_cards = g_byte_array_sized_new (SLOT_CARDS_N_PREALLOC);
- priv->images = ar_card_images_new ();
#ifdef CAIRO_DRAWING
- ar_card_images_set_cache_mode (priv->images, CACHE_PIXBUFS);
+ priv->card_cache = ar_card_surface_cache_new ();
+ // FIXMEchpe connect changed handler
+#else
+ priv->images = ar_card_images_new ();
#endif
gtk_widget_set_events (widget,
@@ -3812,7 +3883,11 @@ aisleriot_board_finalize (GObject *object)
g_byte_array_free (priv->moving_cards, TRUE);
+#ifdef CAIRO_DRAWING
+ g_object_unref (priv->card_cache);
+#else
g_object_unref (priv->images);
+#endif
G_OBJECT_CLASS (aisleriot_board_parent_class)->finalize (object);
}
diff --git a/aisleriot/lib/Makefile.am b/aisleriot/lib/Makefile.am
index 2df7958..833daba 100644
--- a/aisleriot/lib/Makefile.am
+++ b/aisleriot/lib/Makefile.am
@@ -5,8 +5,6 @@ noinst_LTLIBRARIES = libaisleriot.la
libaisleriot_la_SOURCES = \
ar-card.c \
ar-card.h \
- ar-card-images.c \
- ar-card-images.h \
ar-card-private.h \
ar-card-theme.c \
ar-card-theme.h \
@@ -17,6 +15,19 @@ libaisleriot_la_SOURCES = \
ar-pixbuf-utils.h \
$(NULL)
+if HAVE_GTK_2
+libaisleriot_la_SOURCES += \
+ ar-card-images.c \
+ ar-card-images.h \
+ $(NULL)
+endif
+
+# FIXME conditional
+libaisleriot_la_SOURCES += \
+ ar-card-surface-cache.c \
+ ar-card-surface-cache.h \
+ $(NULL)
+
if HAVE_CLUTTER
libaisleriot_la_SOURCES += \
ar-card-textures-cache.c \
diff --git a/aisleriot/lib/ar-card-surface-cache.c b/aisleriot/lib/ar-card-surface-cache.c
new file mode 100644
index 0000000..db89059
--- /dev/null
+++ b/aisleriot/lib/ar-card-surface-cache.c
@@ -0,0 +1,349 @@
+/*
+ Copyright © 2008 Neil Roberts
+ Copyright © 2008, 2010 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 <libgames-support/games-debug.h>
+
+#include "ar-card-surface-cache.h"
+#include "ar-card-private.h"
+
+struct _ArCardSurfaceCachePrivate
+{
+ ArCardTheme *theme;
+ guint theme_changed_id;
+
+ cairo_surface_t **cards;
+
+#ifdef GNOME_ENABLE_DEBUG
+ guint n_calls;
+ guint cache_hits;
+#endif
+};
+
+enum
+{
+ PROP_0,
+ PROP_THEME
+};
+
+/* This is an invalid value for a cairo_surface_t *, and distinct from COGL_INVALID_HANDLE */
+#define FAILED_SURFACE ((gpointer) 0x1)
+#define IS_FAILED_SURFACE(ptr) (G_UNLIKELY ((ptr) == FAILED_SURFACE))
+
+/* Logging */
+#ifdef GNOME_ENABLE_DEBUG
+#define LOG_CALL(obj) obj->priv->n_calls++
+#define LOG_CACHE_HIT(obj) obj->priv->cache_hits++
+#define LOG_CACHE_MISS(obj)
+#else
+#define LOG_CALL(obj)
+#define LOG_CACHE_HIT(obj)
+#define LOG_CACHE_MISS(obj)
+#endif /* GNOME_ENABLE_DEBUG */
+
+static void ar_card_surface_cache_dispose (GObject *object);
+static void ar_card_surface_cache_finalize (GObject *object);
+
+G_DEFINE_TYPE (ArCardSurfaceCache, ar_card_surface_cache, G_TYPE_OBJECT);
+
+#define AR_CARD_SURFACE_CACHE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), AR_TYPE_CARD_SURFACE_CACHE, ArCardSurfaceCachePrivate))
+
+/* Helper functions */
+
+static void
+ar_card_surface_cache_clear (ArCardSurfaceCache *cache)
+{
+ ArCardSurfaceCachePrivate *priv = cache->priv;
+ int i;
+
+ _games_debug_print (GAMES_DEBUG_CARD_CACHE,
+ "ar_card_surface_cache_clear\n");
+
+ for (i = 0; i < AR_CARDS_TOTAL; i++) {
+ cairo_surface_t *surface = priv->cards[i];
+
+ if (surface != NULL &&
+ !IS_FAILED_SURFACE (surface)) {
+ cairo_surface_destroy (surface);
+ }
+
+ priv->cards[i] = NULL;
+ }
+}
+
+static void
+ar_card_surface_cache_unset_theme (ArCardSurfaceCache *cache)
+{
+ ArCardSurfaceCachePrivate *priv = cache->priv;
+
+ if (priv->theme) {
+ g_signal_handler_disconnect (priv->theme, priv->theme_changed_id);
+ g_object_unref (priv->theme);
+ priv->theme = NULL;
+ priv->theme_changed_id = 0;
+ }
+}
+
+/* Class implementation */
+
+static void
+ar_card_surface_cache_init (ArCardSurfaceCache *self)
+{
+ ArCardSurfaceCachePrivate *priv;
+
+ priv = self->priv = AR_CARD_SURFACE_CACHE_GET_PRIVATE (self);
+
+ priv->cards = g_malloc0 (sizeof (cairo_surface_t*) * AR_CARDS_TOTAL);
+}
+
+static void
+ar_card_surface_cache_dispose (GObject *object)
+{
+ ArCardSurfaceCache *cache = AR_CARD_SURFACE_CACHE (object);
+
+ ar_card_surface_cache_clear (cache);
+ ar_card_surface_cache_unset_theme (cache);
+
+ G_OBJECT_CLASS (ar_card_surface_cache_parent_class)->dispose (object);
+}
+
+static void
+ar_card_surface_cache_finalize (GObject *object)
+{
+ ArCardSurfaceCache *cache = AR_CARD_SURFACE_CACHE (object);
+ ArCardSurfaceCachePrivate *priv = cache->priv;
+
+ g_free (priv->cards);
+
+#ifdef GNOME_ENABLE_DEBUG
+ _GAMES_DEBUG_IF (GAMES_DEBUG_CARD_CACHE) {
+ _games_debug_print (GAMES_DEBUG_CARD_CACHE,
+ "ArCardSurfaceCache %p statistics: %u calls with %u hits and %u misses for a hit/total of %.3f\n",
+ cache, priv->n_calls, priv->cache_hits, priv->n_calls - priv->cache_hits,
+ priv->n_calls > 0 ? (double) priv->cache_hits / (double) priv->n_calls : 0.0);
+ }
+#endif
+
+ G_OBJECT_CLASS (ar_card_surface_cache_parent_class)->finalize (object);
+}
+
+static void
+ar_card_surface_cache_set_property (GObject *self,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ArCardSurfaceCache *cache = AR_CARD_SURFACE_CACHE (self);
+
+ switch (property_id) {
+ case PROP_THEME:
+ ar_card_surface_cache_set_theme (cache, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ar_card_surface_cache_get_property (GObject *self,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ArCardSurfaceCache *cache = AR_CARD_SURFACE_CACHE (self);
+
+ switch (property_id) {
+ case PROP_THEME:
+ g_value_set_object (value, ar_card_surface_cache_get_theme (cache));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ar_card_surface_cache_class_init (ArCardSurfaceCacheClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = ar_card_surface_cache_dispose;
+ gobject_class->finalize = ar_card_surface_cache_finalize;
+ gobject_class->set_property = ar_card_surface_cache_set_property;
+ gobject_class->get_property = ar_card_surface_cache_get_property;
+
+ g_type_class_add_private (klass, sizeof (ArCardSurfaceCachePrivate));
+
+ g_object_class_install_property (gobject_class,
+ PROP_THEME,
+ g_param_spec_object ("theme", NULL, NULL,
+ AR_TYPE_CARD_THEME,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+/* Public API */
+
+/**
+ * ar_card_surface_cache_new:
+ *
+ * Returns: a new #ArCardSurfaceCache object
+ */
+ArCardSurfaceCache *
+ar_card_surface_cache_new (void)
+{
+ return g_object_new (AR_TYPE_CARD_SURFACE_CACHE, NULL);
+}
+
+/**
+ * ar_card_surface_cache_drop:
+ * @images: a #ArCardImages
+ *
+ * Clears the image cache.
+ */
+void
+ar_card_surface_cache_drop (ArCardSurfaceCache *cache)
+{
+ g_return_if_fail (AR_IS_CARD_SURFACE_CACHE (cache));
+
+ ar_card_surface_cache_clear (cache);
+}
+
+/**
+ * ar_card_surface_cache_set_theme:
+ * @cache:
+ * @theme:
+ *
+ * Sets the card theme.
+ */
+void
+ar_card_surface_cache_set_theme (ArCardSurfaceCache *cache,
+ ArCardTheme *theme)
+{
+ ArCardSurfaceCachePrivate *priv = cache->priv;
+
+ g_return_if_fail (AR_IS_CARD_SURFACE_CACHE (cache));
+ g_return_if_fail (theme == NULL || AR_IS_CARD_THEME (theme));
+
+ if (priv->theme == theme)
+ return;
+
+ ar_card_surface_cache_clear (cache);
+ ar_card_surface_cache_unset_theme (cache);
+
+ priv->theme = theme;
+ if (theme) {
+ g_object_ref (theme);
+
+ priv->theme_changed_id = g_signal_connect_swapped (theme, "changed",
+ G_CALLBACK (ar_card_surface_cache_clear),
+ cache);
+ }
+
+ g_object_notify (G_OBJECT (cache), "theme");
+}
+
+/**
+ * ar_card_surface_cache_get_theme:
+ * @cache:
+ *
+ * Returns: the the card theme of @cache
+ */
+ArCardTheme *
+ar_card_surface_cache_get_theme (ArCardSurfaceCache *cache)
+{
+ g_return_val_if_fail (AR_IS_CARD_SURFACE_CACHE (cache), NULL);
+
+ return cache->priv->theme;
+}
+
+/**
+ * ar_card_surface_cache_get_card_surface_by_id:
+ * @cache:
+ * @card_id:
+ *
+ * Returns: a cached #cairo_surface_t for @card_id.
+ */
+cairo_surface_t *
+ar_card_surface_cache_get_card_surface_by_id (ArCardSurfaceCache *cache,
+ guint card_id)
+{
+ ArCardSurfaceCachePrivate *priv = cache->priv;
+ cairo_surface_t *surface;
+
+ g_return_val_if_fail (card_id < AR_CARDS_TOTAL , NULL);
+
+ LOG_CALL (cache);
+
+ surface = priv->cards[card_id];
+ if (IS_FAILED_SURFACE (surface)) {
+ LOG_CACHE_HIT (cache);
+ return NULL;
+ }
+
+ if (surface == NULL) {
+ LOG_CACHE_MISS (cache);
+
+ surface = ar_card_theme_get_card_surface (priv->theme, card_id);
+ if (surface == NULL) {
+ priv->cards[card_id] = FAILED_SURFACE;
+ return NULL;
+ }
+
+ priv->cards[card_id] = surface; /* adopts */
+ } else {
+ LOG_CACHE_HIT (cache);
+ }
+
+ return surface;
+}
+
+/**
+ * ar_card_surface_cache_get_card_surface:
+ * @cache:
+ * @card:
+ * @highlighted:
+ *
+ * Returns: a cached #cairo_surface_t for @card.
+ */
+cairo_surface_t *
+ar_card_surface_cache_get_card_surface (ArCardSurfaceCache *cache,
+ Card card)
+{
+ guint card_id = _ar_card_to_index (card);
+
+ return ar_card_surface_cache_get_card_surface_by_id (cache, card_id);
+}
+
+/**
+ * ar_card_surface_cache_get_slot_surface:
+ * @cache:
+ * @highlighted:
+ *
+ * Returns: a cached #cairo_surface_t * for the slot.
+ */
+cairo_surface_t *
+ar_card_surface_cache_get_slot_surface (ArCardSurfaceCache *cache)
+{
+ return ar_card_surface_cache_get_card_surface_by_id (cache, AR_CARD_SLOT);
+}
diff --git a/aisleriot/lib/ar-card-surface-cache.h b/aisleriot/lib/ar-card-surface-cache.h
new file mode 100644
index 0000000..3e14f6d
--- /dev/null
+++ b/aisleriot/lib/ar-card-surface-cache.h
@@ -0,0 +1,74 @@
+/*
+ Copyright © 2008 Neil Roberts
+ Copyright © 2008, 2010 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 AR_CARD_SURFACE_CACHE_H
+#define AR_CARD_SURFACE_CACHE_H
+
+#include <glib-object.h>
+#include <cairo.h>
+
+#include "ar-card.h"
+#include "ar-card-theme.h"
+
+G_BEGIN_DECLS
+
+#define AR_TYPE_CARD_SURFACE_CACHE (ar_card_surface_cache_get_type())
+#define AR_CARD_SURFACE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AR_TYPE_CARD_SURFACE_CACHE, ArCardSurfaceCache))
+#define AR_CARD_SURFACE_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AR_TYPE_CARD_SURFACE_CACHE, ArCardSurfaceCacheClass))
+#define AR_IS_CARD_SURFACE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AR_TYPE_CARD_SURFACE_CACHE))
+#define AR_IS_CARD_SURFACE_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AR_TYPE_CARD_SURFACE_CACHE))
+#define AR_CARD_SURFACE_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), AR_TYPE_CARD_SURFACE_CACHE, ArCardSurfaceCacheClass))
+
+typedef struct _ArCardSurfaceCache ArCardSurfaceCache;
+typedef struct _ArCardSurfaceCacheClass ArCardSurfaceCacheClass;
+typedef struct _ArCardSurfaceCachePrivate ArCardSurfaceCachePrivate;
+
+struct _ArCardSurfaceCacheClass
+{
+ GObjectClass parent_class;
+};
+
+struct _ArCardSurfaceCache
+{
+ GObject parent;
+
+ ArCardSurfaceCachePrivate *priv;
+};
+
+GType ar_card_surface_cache_get_type (void);
+
+ArCardSurfaceCache *ar_card_surface_cache_new (void);
+
+void ar_card_surface_cache_drop (ArCardSurfaceCache *cache);
+
+void ar_card_surface_cache_set_theme (ArCardSurfaceCache *cache,
+ ArCardTheme *theme);
+
+ArCardTheme *ar_card_surface_cache_get_theme (ArCardSurfaceCache *cache);
+
+cairo_surface_t *ar_card_surface_cache_get_card_surface (ArCardSurfaceCache *cache,
+ Card card);
+
+cairo_surface_t *ar_card_surface_cache_get_card_surface_by_id (ArCardSurfaceCache *cache,
+ guint card_id);
+
+cairo_surface_t *ar_card_surface_cache_get_slot_surface (ArCardSurfaceCache *cache);
+
+G_END_DECLS
+
+#endif /* AR_CARD_SURFACE_CACHE_H */
diff --git a/aisleriot/lib/ar-card-theme-private.h b/aisleriot/lib/ar-card-theme-private.h
index 5943520..71aba3c 100644
--- a/aisleriot/lib/ar-card-theme-private.h
+++ b/aisleriot/lib/ar-card-theme-private.h
@@ -83,6 +83,8 @@ struct _ArCardThemeClass {
int card_id);
#if GTK_CHECK_VERSION (2, 10, 0)
+ cairo_surface_t* (* get_card_surface) (ArCardTheme *theme,
+ int card_id);
void (* set_font_options) (ArCardTheme *theme,
const cairo_font_options_t *font_options);
#endif
diff --git a/aisleriot/lib/ar-card-theme.c b/aisleriot/lib/ar-card-theme.c
index fdba51a..443c1ba 100644
--- a/aisleriot/lib/ar-card-theme.c
+++ b/aisleriot/lib/ar-card-theme.c
@@ -112,6 +112,33 @@ ar_card_theme_class_get_theme_info (ArCardThemeClass *klass,
return NULL;
}
+#if GTK_CHECK_VERSION (2, 10,0)
+static cairo_surface_t *
+ar_card_theme_class_real_get_card_surface (ArCardTheme *theme,
+ int cardid)
+{
+ GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ pixbuf = ar_card_theme_get_card_pixbuf (theme, cardid);
+ if (pixbuf == NULL)
+ return NULL;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf));
+ cr = cairo_create (surface);
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ g_object_unref (pixbuf);
+
+ return surface;
+}
+#endif /* GTK 2.10 */
+
static void
ar_card_theme_class_init (ArCardThemeClass * klass)
{
@@ -123,6 +150,10 @@ ar_card_theme_class_init (ArCardThemeClass * klass)
klass->get_theme_info = ar_card_theme_class_get_theme_info;
+#if GTK_CHECK_VERSION (2, 10,0)
+ klass->get_card_surface = ar_card_theme_class_real_get_card_surface;
+#endif
+
g_object_class_install_property
(gobject_class,
PROP_THEME_INFO,
@@ -333,6 +364,35 @@ ar_card_theme_get_card_pixbuf (ArCardTheme *theme,
return pixbuf;
}
+#if GTK_CHECK_VERSION (2, 10,0)
+/**
+* ar_card_theme_get_card_surface:
+* @theme:
+* @card_id:
+*
+* Returns a #cairo_surface_t for the selected card using the currently loaded
+* theme and the currently selected size.
+*
+* Returns: a new #cairo_surface_t, or %NULL if there was an error
+*/
+cairo_surface_t *
+ar_card_theme_get_card_surface (ArCardTheme *theme,
+ int cardid)
+{
+ cairo_surface_t *surface = NULL;
+
+ g_return_val_if_fail ((cardid >= 0) && (cardid < AR_CARDS_TOTAL), NULL);
+
+ _games_profile_start ("loading card %d from theme %s", cardid, theme->theme_info->display_name);
+
+ surface = theme->klass->get_card_surface (theme, cardid);
+
+ _games_profile_end ("loading card %d from theme %s", cardid, theme->theme_info->display_name);
+
+ return surface;
+}
+#endif /* GTK 2.10 */
+
/* ArCardThemeInfo impl */
static int
diff --git a/aisleriot/lib/ar-card-theme.h b/aisleriot/lib/ar-card-theme.h
index 53dba54..dce2b18 100644
--- a/aisleriot/lib/ar-card-theme.h
+++ b/aisleriot/lib/ar-card-theme.h
@@ -93,7 +93,12 @@ void ar_card_theme_get_size (ArCardTheme *theme,
double ar_card_theme_get_aspect (ArCardTheme * theme);
GdkPixbuf *ar_card_theme_get_card_pixbuf (ArCardTheme * theme,
- int cardid);
+ int cardid);
+
+#if GTK_CHECK_VERSION (2, 10,0)
+cairo_surface_t *ar_card_theme_get_card_surface (ArCardTheme *theme,
+ int cardid);
+#endif
G_END_DECLS
diff --git a/configure.in b/configure.in
index fd60098..3c0af82 100644
--- a/configure.in
+++ b/configure.in
@@ -332,6 +332,9 @@ esac
AC_SUBST([GTK_API_VERSION])
AC_SUBST([GTK_API_MAJOR_VERSION])
+AM_CONDITIONAL([HAVE_GTK_2],[test "$GTK_API_VERSION" = "2.0"])
+AM_CONDITIONAL([HAVE_GTK_3],[test "$GTK_API_VERSION" = "3.0"])
+
# Win32 platform
AC_CANONICAL_HOST
diff --git a/libgames-support/games-preimage.c b/libgames-support/games-preimage.c
index 35d7606..1cf4e1b 100644
--- a/libgames-support/games-preimage.c
+++ b/libgames-support/games-preimage.c
@@ -158,6 +158,67 @@ cairo_pixels_to_pixbuf (guint8 * pixels, int rowstride, int height)
}
/**
+ * games_preimage_render_cairo_sub:
+ * @preimage:
+ * @cr:
+ * @node: a SVG node ID (starting with "#"), or %NULL
+ * @width: the width of the clip region
+ * @height: the height of the clip region
+ * @xoffset: the x offset of the clip region
+ * @yoffset: the y offset of the clip region
+ * @xzoom: the x zoom factor
+ * @yzoom: the y zoom factor
+ *
+ * Creates a #GdkPixbuf with the dimensions @width by @height,
+ * and renders the subimage of @preimage specified by @node to it,
+ * transformed by @xzoom, @yzoom and offset by @xoffset and @yoffset,
+ * clipped to @width and @height.
+ * If @node is NULL, the whole image is rendered into tha clip region.
+ *
+ * Returns: %TRUE, of %FALSE if there was an error or @preimage
+ * isn't a scalable SVG image
+ */
+gboolean
+games_preimage_render_cairo_sub (GamesPreimage * preimage,
+ cairo_surface_t *surface,
+ const char *node,
+ int width,
+ int height,
+ double xoffset,
+ double yoffset,
+ double xzoom,
+ double yzoom)
+{
+ cairo_t *cx;
+ cairo_matrix_t matrix;
+ gboolean success;
+
+ if (!preimage->scalable)
+ return FALSE;
+
+ cx = cairo_create (surface);
+
+ if (preimage->font_options) {
+ cairo_set_antialias (cx, cairo_font_options_get_antialias (preimage->font_options));
+
+ cairo_set_font_options (cx, preimage->font_options);
+ }
+
+ cairo_matrix_init_identity (&matrix);
+ cairo_matrix_scale (&matrix, xzoom, yzoom);
+ cairo_matrix_translate (&matrix, xoffset, yoffset);
+
+ cairo_set_matrix (cx, &matrix);
+
+ rsvg_handle_render_cairo_sub (preimage->rsvg_handle, cx, node);
+
+ success = (cairo_status (cx) == CAIRO_STATUS_SUCCESS);
+ cairo_destroy (cx);
+
+ return success;
+}
+
+/**
* games_preimage_render_sub:
* @preimage:
* @node: a SVG node ID (starting with "#"), or %NULL
@@ -185,12 +246,9 @@ games_preimage_render_sub (GamesPreimage * preimage,
double xoffset,
double yoffset, double xzoom, double yzoom)
{
- GdkPixbuf *pixbuf = NULL;
int rowstride;
guint8 *data;
cairo_surface_t *surface;
- cairo_t *cx;
- cairo_matrix_t matrix;
if (!preimage->scalable)
return NULL;
@@ -208,47 +266,24 @@ games_preimage_render_sub (GamesPreimage * preimage,
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
width, height, rowstride);
- if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
+ if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS ||
+ !games_preimage_render_cairo_sub (preimage, surface, node, width, height,
+ xoffset, yoffset, xzoom, yzoom)) {
+ cairo_surface_destroy (surface);
g_free (data);
return NULL;
}
- cx = cairo_create (surface);
-
- if (preimage->font_options) {
- cairo_set_antialias (cx, cairo_font_options_get_antialias (preimage->font_options));
-
- cairo_set_font_options (cx, preimage->font_options);
- }
-
- cairo_matrix_init_identity (&matrix);
- cairo_matrix_scale (&matrix, xzoom, yzoom);
- cairo_matrix_translate (&matrix, xoffset, yoffset);
-
- cairo_set_matrix (cx, &matrix);
-
- rsvg_handle_render_cairo_sub (preimage->rsvg_handle, cx, node);
-
- cairo_pixels_to_pixbuf (data, rowstride, height);
-
- if (cairo_status (cx) == CAIRO_STATUS_SUCCESS) {
- pixbuf = gdk_pixbuf_new_from_data (data,
- GDK_COLORSPACE_RGB,
- TRUE,
- 8,
- width, height,
- rowstride,
- (GdkPixbufDestroyNotify) g_free, NULL);
- data = NULL;
- }
-
- cairo_destroy (cx);
-
cairo_surface_destroy (surface);
+ cairo_pixels_to_pixbuf (data, rowstride, height);
- g_free (data);
-
- return pixbuf;
+ return gdk_pixbuf_new_from_data (data,
+ GDK_COLORSPACE_RGB,
+ TRUE,
+ 8,
+ width, height,
+ rowstride,
+ (GdkPixbufDestroyNotify) g_free, NULL);
}
#endif /* HAVE_RSVG */
diff --git a/libgames-support/games-preimage.h b/libgames-support/games-preimage.h
index f44ea1a..8c821dc 100644
--- a/libgames-support/games-preimage.h
+++ b/libgames-support/games-preimage.h
@@ -59,6 +59,16 @@ GdkPixbuf *games_preimage_render_sub (GamesPreimage * preimage,
double yoffset,
double xzoom, double yzoom);
+gboolean games_preimage_render_cairo_sub (GamesPreimage * preimage,
+ cairo_surface_t *surface,
+ const char *node,
+ int width,
+ int height,
+ double xoffset,
+ double yoffset,
+ double xzoom,
+ double yzoom);
+
gboolean games_preimage_is_scalable (GamesPreimage * preimage);
gint games_preimage_get_width (GamesPreimage * preimage);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]