summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@src.gnome.org>2000-02-07 02:36:39 +0000
committerOwen Taylor <otaylor@src.gnome.org>2000-02-07 02:36:39 +0000
commit1ac1bfb99545e15464148db33fc6acb079d2b40d (patch)
tree6c1aa6f06722bf5456fa503bbd84353d92ad57a9
parent45cb0268b92536ebcc420054e5fac5bffcf4b709 (diff)
downloadgdk-pixbuf-1ac1bfb99545e15464148db33fc6acb079d2b40d.tar.gz
Initial revision
-rw-r--r--modules/engines/pixbuf/ChangeLog88
-rw-r--r--modules/engines/pixbuf/README17
-rw-r--r--modules/engines/pixbuf/pixbuf-draw.c1038
-rw-r--r--modules/engines/pixbuf/pixbuf-main.c878
-rw-r--r--modules/engines/pixbuf/pixbuf-render.c356
-rw-r--r--modules/engines/pixbuf/pixbuf.h172
6 files changed, 2549 insertions, 0 deletions
diff --git a/modules/engines/pixbuf/ChangeLog b/modules/engines/pixbuf/ChangeLog
new file mode 100644
index 000000000..d73045b61
--- /dev/null
+++ b/modules/engines/pixbuf/ChangeLog
@@ -0,0 +1,88 @@
+Sun Feb 6 21:34:30 2000 Owen Taylor <otaylor@redhat.com>
+
+ * Started ChangeLog for pixbuf engine, check sources
+ into CVS.
+
+========== ChangeLog for pixmap engine ===================
+
+1999-11-22 Martin Baulig <martin@home-of-linux.org>
+
+ * pixmap_theme_main.c (theme_duplicate_style): Really copy the
+ `src_data->img_list', not just the pointer that points to it.
+
+Tue Oct 5 15:13:29 1999 Owen Taylor <otaylor@redhat.com>
+
+ * pixmap_theme_draw.c (apply_theme_image): Don't set
+ background pixmap on pixmaps.
+
+1999-02-14 Raja R Harinath <harinath@cs.umn.edu>
+
+ * Theme/gtk/Makefile.am.in (Makefile.am): Handle the case when
+ files are deleted.
+
+Thu Feb 11 21:16:53 1999 Owen Taylor <otaylor@redhat.com>
+
+ * pixmap_theme_main.c (theme_data_unref): Free the
+ theme data structure as well as the contents.
+
+1999-02-03 Raja R Harinath <harinath@cs.umn.edu>
+
+ * Theme/gtk/Makefile.am.in: New file. Theme/gtk/Makefile.am is
+ generated from this file when new *.png files are added.
+
+1999-01-23 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * pixmap_theme_main.c (theme_init): Turn on pixmap cache.
+
+Mon Jan 18 13:37:23 1999 Owen Taylor <otaylor@redhat.com>
+
+ * Theme/gtk/gtkrc: Give buttons a gray background
+ color so they look a little less funny when initially
+ drawing.
+
+Wed Jan 13 18:58:25 1999 Owen Taylor <otaylor@redhat.com>
+
+ * pixmap_theme_draw.c: Fixed pervasive mis-bracketing
+ that was causing drawing if the drawn region and
+ clipping region did NOT intersect, and a couple
+ of errors in computing source and destination
+ regions.
+
+1998-11-09 Federico Mena Quintero <federico@nuclecu.unam.mx>
+
+ * pixmap_theme_draw.c: #include <math.h>
+
+1998-11-07 Raja R Harinath <harinath@cs.umn.edu>
+
+ * Theme/gtk/Makefile.am (theme_DATA):
+ Update to new directory contents.
+ * configure.in: Remove.
+
+Fri Nov 6 17:26:12 1998 Owen Taylor <otaylor@redhat.com>
+
+ * pixmap_theme_main.c: Removed some debugging
+ printf's.
+
+ * Theme/gtk/notebook1.c Theme/gtk/menubar.png: new
+ bigger pixmaps to reduce pixelation.
+
+ * Theme/gtk/gtkrc: Reorganized to use several styles
+ instead of one huge style. Change clist backgrounds
+ to be prettier.
+
+Thu Nov 5 10:23:46 1998 Owen Taylor <otaylor@redhat.com>
+
+ * pixmap_theme_draw.c (draw_shadow_gap): Fixed hard-coded
+ gap_side of '0'.
+
+Mon Nov 2 14:46:02 1998 Owen Taylor <otaylor@redhat.com>
+
+ * pixmap_theme_draw.c (apply_theme_image_shadow_gap): Removed
+ several hundred lines of duplicated code with a bit of
+ reoriganization.
+
+Wed Oct 28 16:18:04 1998 Owen Taylor <otaylor@redhat.com>
+
+ * pixmap_theme_main.c (theme_symbols): Removed lots
+ and lots of white space.
+
diff --git a/modules/engines/pixbuf/README b/modules/engines/pixbuf/README
new file mode 100644
index 000000000..6b48ec67c
--- /dev/null
+++ b/modules/engines/pixbuf/README
@@ -0,0 +1,17 @@
+The code in this directory is a GTK+ theme engine based on the earlier
+pixmap theme engine.
+
+The config files are meant to be compatible, but instead of rendering
+using Imlib, it renders using GdkPixbuf. This makes the memory
+management much more understandable, and also allows us to use
+GdkPixbuf's high quality scaling.
+
+Most of the code was reworked/rewritten in the process to make it more
+understandable and maintainable.
+
+There are lots of bugs here, a considersable number of bugs. But it's
+cleaned up a great deal from the older pixmap engine. Please don't
+make it uglier again.
+
+Owen Taylor <otaylor@redhat.com>
+6 February 2000 \ No newline at end of file
diff --git a/modules/engines/pixbuf/pixbuf-draw.c b/modules/engines/pixbuf/pixbuf-draw.c
new file mode 100644
index 000000000..a540700cb
--- /dev/null
+++ b/modules/engines/pixbuf/pixbuf-draw.c
@@ -0,0 +1,1038 @@
+/* GTK+ Pixbuf Engine
+ * Copyright (C) 1998-2000 Red Hat Software
+ *
+ * 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 of the License, 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by Owen Taylor <otaylor@redhat.com>, based on code by
+ * Carsten Haitzler <raster@rasterman.com>
+ */
+
+#include "pixmap_theme.h"
+#include <math.h>
+#include "pixmap_theme.h"
+
+static ThemeImage *
+match_theme_image(GtkStyle *style,
+ ThemeMatchData *match_data)
+{
+ GList *tmp_list;
+
+ tmp_list = ((ThemeData *)style->engine_data)->img_list;
+
+ while (tmp_list)
+ {
+ guint flags;
+ ThemeImage *image = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ if (match_data->function != image->match_data.function)
+ continue;
+
+ flags = match_data->flags & image->match_data.flags;
+
+ if (flags != image->match_data.flags) /* Required components not present */
+ continue;
+
+ if ((flags & THEME_MATCH_STATE) &&
+ match_data->state != image->match_data.state)
+ continue;
+
+ if ((flags & THEME_MATCH_SHADOW) &&
+ match_data->shadow != image->match_data.shadow)
+ continue;
+
+ if ((flags & THEME_MATCH_ARROW_DIRECTION) &&
+ match_data->arrow_direction != image->match_data.arrow_direction)
+ continue;
+
+ if ((flags & THEME_MATCH_ORIENTATION) &&
+ match_data->orientation != image->match_data.orientation)
+ continue;
+
+ if ((flags & THEME_MATCH_GAP_SIDE) &&
+ match_data->gap_side != image->match_data.gap_side)
+ continue;
+
+ if (image->match_data.detail &&
+ (!image->match_data.detail ||
+ strcmp (match_data->detail, image->match_data.detail) != 0))
+ continue;
+
+ return image;
+ }
+
+ return NULL;
+}
+
+static void
+draw_simple_image(GtkStyle *style,
+ GdkWindow *window,
+ GdkRectangle *area,
+ GtkWidget *widget,
+ ThemeMatchData *match_data,
+ gboolean draw_center,
+ gboolean allow_setbg,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeImage *image;
+ gboolean setbg = FALSE;
+
+ if ((width == -1) && (height == -1))
+ {
+ gdk_window_get_size(window, &width, &height);
+ if (allow_setbg)
+ setbg = TRUE;
+ }
+ else if (width == -1)
+ gdk_window_get_size(window, &width, NULL);
+ else if (height == -1)
+ gdk_window_get_size(window, NULL, &height);
+
+ if (!(match_data->flags & THEME_MATCH_ORIENTATION))
+ {
+ match_data->flags |= THEME_MATCH_ORIENTATION;
+
+ if (height > width)
+ match_data->orientation = GTK_ORIENTATION_VERTICAL;
+ else
+ match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
+ }
+
+ image = match_theme_image(style, match_data);
+ if (image)
+ {
+ if (image->background)
+ {
+ GdkBitmap *mask = NULL;
+
+ if (image->background->stretch && setbg &&
+ gdk_window_get_type (window) != GDK_WINDOW_PIXMAP)
+ {
+ GdkPixbuf *pixbuf = theme_pixbuf_get_pixbuf (image->background);
+ if (pixbuf && pixbuf->art_pixbuf->has_alpha)
+ mask = gdk_pixmap_new (window, width, height, 1);
+ }
+
+ theme_pixbuf_render (image->background,
+ window, mask, area,
+ draw_center ? COMPONENT_ALL : COMPONENT_ALL | COMPONENT_CENTER,
+ FALSE,
+ x, y, width, height);
+
+ if (mask)
+ {
+ gdk_window_shape_combine_mask (window, mask, 0, 0);
+ gdk_pixmap_unref (mask);
+ }
+ }
+
+ if (image->overlay && draw_center)
+ theme_pixbuf_render (image->overlay,
+ window, NULL, area, COMPONENT_ALL,
+ TRUE,
+ x, y, width, height);
+ }
+}
+
+static void
+draw_gap_image(GtkStyle *style,
+ GdkWindow *window,
+ GdkRectangle *area,
+ GtkWidget *widget,
+ ThemeMatchData *match_data,
+ gboolean draw_center,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ GtkPositionType gap_side,
+ gint gap_x,
+ gint gap_width)
+{
+ ThemeImage *image;
+ gboolean setbg = FALSE;
+
+ if ((width == -1) && (height == -1))
+ {
+ gdk_window_get_size(window, &width, &height);
+ setbg = TRUE;
+ }
+ else if (width == -1)
+ gdk_window_get_size(window, &width, NULL);
+ else if (height == -1)
+ gdk_window_get_size(window, NULL, &height);
+
+ if (!(match_data->flags & THEME_MATCH_ORIENTATION))
+ {
+ match_data->flags |= THEME_MATCH_ORIENTATION;
+
+ if (height > width)
+ match_data->orientation = GTK_ORIENTATION_VERTICAL;
+ else
+ match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
+ }
+
+ match_data->flags |= THEME_MATCH_GAP_SIDE;
+ match_data->gap_side = gap_side;
+
+ image = match_theme_image(style, match_data);
+ if (image)
+ {
+ gint thickness;
+ GdkRectangle r1, r2, r3;
+ GdkPixbuf *pixbuf = NULL;
+ guint components = COMPONENT_ALL;
+
+ if (!draw_center)
+ components |= COMPONENT_CENTER;
+
+ if (image->gap_start)
+ pixbuf = theme_pixbuf_get_pixbuf (image->gap_start);
+
+ switch (gap_side)
+ {
+ case GTK_POS_TOP:
+ if (pixbuf)
+ thickness = pixbuf->art_pixbuf->height;
+ else
+ thickness = style->klass->ythickness;
+
+ if (!draw_center)
+ components |= COMPONENT_NORTH_WEST | COMPONENT_NORTH | COMPONENT_NORTH_EAST;
+
+ r1.x = x;
+ r1.y = y;
+ r1.width = gap_x;
+ r1.height = thickness;
+ r2.x = x + gap_x;
+ r2.y = y;
+ r2.width = gap_width;
+ r2.height = thickness;
+ r3.x = x + gap_x + gap_width;
+ r3.y = y;
+ r3.width = width - (gap_x + gap_width);
+ r3.height = thickness;
+ break;
+
+ case GTK_POS_BOTTOM:
+ if (pixbuf)
+ thickness = pixbuf->art_pixbuf->height;
+ else
+ thickness = style->klass->ythickness;
+
+ if (!draw_center)
+ components |= COMPONENT_SOUTH_WEST | COMPONENT_SOUTH | COMPONENT_SOUTH_EAST;
+
+ r1.x = x;
+ r1.y = y + height - thickness;
+ r1.width = gap_x;
+ r1.height = thickness;
+ r2.x = x + gap_x;
+ r2.y = y + height - thickness;
+ r2.width = gap_width;
+ r2.height = thickness;
+ r3.x = x + gap_x + gap_width;
+ r3.y = y + height - thickness;
+ r3.width = width - (gap_x + gap_width);
+ r3.height = thickness;
+ break;
+
+ case GTK_POS_LEFT:
+ if (pixbuf)
+ thickness = pixbuf->art_pixbuf->width;
+ else
+ thickness = style->klass->xthickness;
+
+ if (!draw_center)
+ components |= COMPONENT_NORTH_WEST | COMPONENT_WEST | COMPONENT_SOUTH_WEST;
+
+ r1.x = x;
+ r1.y = y;
+ r1.width = thickness;
+ r1.height = gap_x;
+ r2.x = x;
+ r2.y = y + gap_x;
+ r2.width = thickness;
+ r2.height = gap_width;
+ r3.x = x;
+ r3.y = y + gap_x + gap_width;
+ r3.width = thickness;
+ r3.height = height - (gap_x + gap_width);
+ break;
+
+ case GTK_POS_RIGHT:
+ if (pixbuf)
+ thickness = pixbuf->art_pixbuf->width;
+ else
+ thickness = style->klass->xthickness;
+
+ if (!draw_center)
+ components |= COMPONENT_NORTH_EAST | COMPONENT_EAST | COMPONENT_SOUTH_EAST;
+
+ r1.x = x + width - thickness;
+ r1.y = y;
+ r1.width = thickness;
+ r1.height = gap_x;
+ r2.x = x + width - thickness;
+ r2.y = y + gap_x;
+ r2.width = thickness;
+ r2.height = gap_width;
+ r3.x = x + width - thickness;
+ r3.y = y + gap_x + gap_width;
+ r3.width = thickness;
+ r3.height = height - (gap_x + gap_width);
+ break;
+ }
+
+ if (image->background)
+ theme_pixbuf_render (image->background,
+ window, NULL, area, components, FALSE,
+ x, y, width, height);
+ if (image->gap_start)
+ theme_pixbuf_render (image->gap_start,
+ window, NULL, area, COMPONENT_ALL, FALSE,
+ r1.x, r1.y, r1.width, r1.height);
+ if (image->gap)
+ theme_pixbuf_render (image->gap,
+ window, NULL, area, COMPONENT_ALL, FALSE,
+ r2.x, r2.y, r2.width, r2.height);
+ if (image->gap_end)
+ theme_pixbuf_render (image->gap_end,
+ window, NULL, area, COMPONENT_ALL, FALSE,
+ r3.x, r3.y, r3.width, r3.height);
+ }
+}
+
+static void
+draw_hline(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x1,
+ gint x2,
+ gint y)
+{
+ ThemeImage *image;
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_HLINE;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
+ match_data.state = state;
+ match_data.orientation = GTK_ORIENTATION_HORIZONTAL;
+
+ image = match_theme_image(style, &match_data);
+ if (image)
+ {
+ if (image->background)
+ theme_pixbuf_render (image->background,
+ window, NULL, area, COMPONENT_ALL, FALSE,
+ x1, y, (x2 - x1) + 1, 2);
+ }
+}
+
+static void
+draw_vline(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint y1,
+ gint y2,
+ gint x)
+{
+ ThemeImage *image;
+ ThemeMatchData match_data;
+
+ g_return_if_fail (style != NULL);
+ g_return_if_fail (window != NULL);
+
+ match_data.function = TOKEN_D_VLINE;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
+ match_data.state = state;
+ match_data.orientation = GTK_ORIENTATION_VERTICAL;
+
+ image = match_theme_image(style, &match_data);
+ if (image)
+ {
+ if (image->background)
+ theme_pixbuf_render (image->background,
+ window, NULL, area, COMPONENT_ALL, FALSE,
+ x, y1, 2, (y2 - y1) + 1);
+ }
+}
+
+static void
+draw_shadow(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_SHADOW;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, FALSE, FALSE,
+ x, y, width, height);
+}
+
+static void
+draw_polygon(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ GdkPoint * points,
+ gint npoints,
+ gint fill)
+{
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif /* M_PI */
+#ifndef M_PI_4
+#define M_PI_4 0.78539816339744830962
+#endif /* M_PI_4 */
+
+ static const gdouble pi_over_4 = M_PI_4;
+ static const gdouble pi_3_over_4 = M_PI_4 * 3;
+
+ GdkGC *gc3;
+ GdkGC *gc4;
+ gdouble angle;
+ gint i;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+ g_return_if_fail(points != NULL);
+
+ switch (shadow)
+ {
+ case GTK_SHADOW_IN:
+ gc3 = style->light_gc[state];
+ gc4 = style->black_gc;
+ break;
+ case GTK_SHADOW_OUT:
+ gc3 = style->black_gc;
+ gc4 = style->light_gc[state];
+ break;
+ default:
+ return;
+ }
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle(gc3, area);
+ gdk_gc_set_clip_rectangle(gc4, area);
+ }
+ if (fill)
+ gdk_draw_polygon(window, style->bg_gc[state], TRUE, points, npoints);
+
+ npoints--;
+
+ for (i = 0; i < npoints; i++)
+ {
+ if ((points[i].x == points[i + 1].x) &&
+ (points[i].y == points[i + 1].y))
+ angle = 0;
+ else
+ angle = atan2(points[i + 1].y - points[i].y,
+ points[i + 1].x - points[i].x);
+
+ if ((angle > -pi_3_over_4) && (angle < pi_over_4))
+ gdk_draw_line(window, gc3,
+ points[i].x, points[i].y,
+ points[i + 1].x, points[i + 1].y);
+ else
+ gdk_draw_line(window, gc4,
+ points[i].x, points[i].y,
+ points[i + 1].x, points[i + 1].y);
+ }
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle(gc3, NULL);
+ gdk_gc_set_clip_rectangle(gc4, NULL);
+ }
+}
+
+static void
+draw_arrow(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ GtkArrowType arrow_direction,
+ gint fill,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_ARROW;
+ match_data.detail = detail;
+ match_data.flags = (THEME_MATCH_SHADOW |
+ THEME_MATCH_STATE |
+ THEME_MATCH_ARROW_DIRECTION);
+ match_data.shadow = shadow;
+ match_data.state = state;
+ match_data.arrow_direction = arrow_direction;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_diamond(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_DIAMOND;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_oval(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_OVAL;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_string(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ const gchar * string)
+{
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ if (state == GTK_STATE_INSENSITIVE)
+ {
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle(style->white_gc, area);
+ gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
+ }
+
+ gdk_draw_string(window, style->font, style->fg_gc[state], x, y, string);
+
+ if (area)
+ {
+ gdk_gc_set_clip_rectangle(style->white_gc, NULL);
+ gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
+ }
+ }
+ else
+ {
+ gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
+ gdk_draw_string(window, style->font, style->fg_gc[state], x, y, string);
+ gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
+ }
+}
+
+static void
+draw_box(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_BOX;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_flat_box(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_FLAT_BOX;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_check(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_CHECK;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_option(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_OPTION;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_cross(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_CROSS;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_ramp(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ GtkArrowType arrow_direction,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_RAMP;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_tab(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_TAB;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_shadow_gap(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ GtkPositionType gap_side,
+ gint gap_x,
+ gint gap_width)
+{
+ ThemeMatchData match_data;
+
+ match_data.function = TOKEN_D_SHADOW_GAP;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.flags = (THEME_MATCH_SHADOW |
+ THEME_MATCH_STATE |
+ THEME_MATCH_ORIENTATION);
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_gap_image (style, window, area, widget, &match_data, FALSE,
+ x, y, width, height, gap_side, gap_x, gap_width);
+}
+
+static void
+draw_box_gap(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ GtkPositionType gap_side,
+ gint gap_x,
+ gint gap_width)
+{
+ ThemeMatchData match_data;
+
+ match_data.function = TOKEN_D_BOX_GAP;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
+ match_data.flags = (THEME_MATCH_SHADOW |
+ THEME_MATCH_STATE |
+ THEME_MATCH_ORIENTATION);
+ match_data.shadow = shadow;
+ match_data.state = state;
+
+ draw_gap_image (style, window, area, widget, &match_data, TRUE,
+ x, y, width, height, gap_side, gap_x, gap_width);
+}
+
+static void
+draw_extension(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ GtkPositionType gap_side)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ /* Why? */
+ if (width >=0)
+ width++;
+ if (height >=0)
+ height++;
+
+ match_data.function = TOKEN_D_EXTENSION;
+ match_data.detail = detail;
+ match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE | THEME_MATCH_GAP_SIDE;
+ match_data.shadow = shadow;
+ match_data.state = state;
+ match_data.gap_side = gap_side;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+static void
+draw_focus(GtkStyle * style,
+ GdkWindow * window,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ /* Why? */
+ if (width >=0)
+ width++;
+ if (height >=0)
+ height++;
+
+ match_data.function = TOKEN_D_FOCUS;
+ match_data.detail = detail;
+ match_data.flags = 0;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, FALSE,
+ x, y, width, height);
+}
+
+static void
+draw_slider(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ GtkOrientation orientation)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ match_data.function = TOKEN_D_SLIDER;
+ match_data.detail = detail;
+ match_data.flags = (THEME_MATCH_SHADOW |
+ THEME_MATCH_STATE |
+ THEME_MATCH_ORIENTATION);
+ match_data.shadow = shadow;
+ match_data.state = state;
+ match_data.orientation = orientation;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);}
+
+
+static void
+draw_handle(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state,
+ GtkShadowType shadow,
+ GdkRectangle * area,
+ GtkWidget * widget,
+ gchar * detail,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ GtkOrientation orientation)
+{
+ ThemeMatchData match_data;
+
+ g_return_if_fail (style != NULL);
+ g_return_if_fail (window != NULL);
+
+ match_data.function = TOKEN_D_HANDLE;
+ match_data.detail = detail;
+ match_data.flags = (THEME_MATCH_SHADOW |
+ THEME_MATCH_STATE |
+ THEME_MATCH_ORIENTATION);
+ match_data.shadow = shadow;
+ match_data.state = state;
+ match_data.orientation = orientation;
+
+ draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
+ x, y, width, height);
+}
+
+GtkStyleClass pixmap_default_class =
+{
+ 2,
+ 2,
+ draw_hline,
+ draw_vline,
+ draw_shadow,
+ draw_polygon,
+ draw_arrow,
+ draw_diamond,
+ draw_oval,
+ draw_string,
+ draw_box,
+ draw_flat_box,
+ draw_check,
+ draw_option,
+ draw_cross,
+ draw_ramp,
+ draw_tab,
+ draw_shadow_gap,
+ draw_box_gap,
+ draw_extension,
+ draw_focus,
+ draw_slider,
+ draw_handle
+};
+
diff --git a/modules/engines/pixbuf/pixbuf-main.c b/modules/engines/pixbuf/pixbuf-main.c
new file mode 100644
index 000000000..1d47a4bbd
--- /dev/null
+++ b/modules/engines/pixbuf/pixbuf-main.c
@@ -0,0 +1,878 @@
+/* GTK+ Pixbuf Engine
+ * Copyright (C) 1998-2000 Red Hat Software
+ *
+ * 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 of the License, 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by Owen Taylor <otaylor@redhat.com>, based on code by
+ * Carsten Haitzler <raster@rasterman.com>
+ */
+
+#include "pixmap_theme.h"
+#include "pixmap_theme.h"
+#include <gmodule.h>
+
+/* Theme functions to export */
+void theme_init(GtkThemeEngine * engine);
+void theme_exit(void);
+
+static struct
+ {
+ gchar *name;
+ guint token;
+ }
+theme_symbols[] =
+{
+ { "image", TOKEN_IMAGE },
+ { "function", TOKEN_FUNCTION },
+ { "file", TOKEN_FILE },
+ { "stretch", TOKEN_STRETCH },
+ { "recolorable", TOKEN_RECOLORABLE },
+ { "border", TOKEN_BORDER },
+ { "detail", TOKEN_DETAIL },
+ { "state", TOKEN_STATE },
+ { "shadow", TOKEN_SHADOW },
+ { "gap_side", TOKEN_GAP_SIDE },
+ { "gap_file", TOKEN_GAP_FILE },
+ { "gap_border", TOKEN_GAP_BORDER },
+ { "gap_start_file", TOKEN_GAP_START_FILE },
+ { "gap_start_border", TOKEN_GAP_START_BORDER },
+ { "gap_end_file", TOKEN_GAP_END_FILE },
+ { "gap_end_border", TOKEN_GAP_END_BORDER },
+ { "overlay_file", TOKEN_OVERLAY_FILE },
+ { "overlay_border", TOKEN_OVERLAY_BORDER },
+ { "overlay_stretch", TOKEN_OVERLAY_STRETCH },
+ { "arrow_direction", TOKEN_ARROW_DIRECTION },
+ { "orientation", TOKEN_ORIENTATION },
+
+ { "HLINE", TOKEN_D_HLINE },
+ { "VLINE", TOKEN_D_VLINE },
+ { "SHADOW", TOKEN_D_SHADOW },
+ { "POLYGON", TOKEN_D_POLYGON },
+ { "ARROW", TOKEN_D_ARROW },
+ { "DIAMOND", TOKEN_D_DIAMOND },
+ { "OVAL", TOKEN_D_OVAL },
+ { "STRING", TOKEN_D_STRING },
+ { "BOX", TOKEN_D_BOX },
+ { "FLAT_BOX", TOKEN_D_FLAT_BOX },
+ { "CHECK", TOKEN_D_CHECK },
+ { "OPTION", TOKEN_D_OPTION },
+ { "CROSS", TOKEN_D_CROSS },
+ { "RAMP", TOKEN_D_RAMP },
+ { "TAB", TOKEN_D_TAB },
+ { "SHADOW_GAP", TOKEN_D_SHADOW_GAP },
+ { "BOX_GAP", TOKEN_D_BOX_GAP },
+ { "EXTENSION", TOKEN_D_EXTENSION },
+ { "FOCUS", TOKEN_D_FOCUS },
+ { "SLIDER", TOKEN_D_SLIDER },
+ { "ENTRY", TOKEN_D_ENTRY },
+ { "HANDLE", TOKEN_D_HANDLE },
+
+ { "TRUE", TOKEN_TRUE },
+ { "FALSE", TOKEN_FALSE },
+
+ { "TOP", TOKEN_TOP },
+ { "UP", TOKEN_UP },
+ { "BOTTOM", TOKEN_BOTTOM },
+ { "DOWN", TOKEN_DOWN },
+ { "LEFT", TOKEN_LEFT },
+ { "RIGHT", TOKEN_RIGHT },
+
+ { "NORMAL", TOKEN_NORMAL },
+ { "ACTIVE", TOKEN_ACTIVE },
+ { "PRELIGHT", TOKEN_PRELIGHT },
+ { "SELECTED", TOKEN_SELECTED },
+ { "INSENSITIVE", TOKEN_INSENSITIVE },
+
+ { "NONE", TOKEN_NONE },
+ { "IN", TOKEN_IN },
+ { "OUT", TOKEN_OUT },
+ { "ETCHED_IN", TOKEN_ETCHED_IN },
+ { "ETCHED_OUT", TOKEN_ETCHED_OUT },
+ { "HORIZONTAL", TOKEN_HORIZONTAL },
+ { "VERTICAL", TOKEN_VERTICAL },
+};
+
+static guint n_theme_symbols = sizeof(theme_symbols) / sizeof(theme_symbols[0]);
+
+static guint
+theme_parse_file(GScanner *scanner,
+ ThemePixbuf **theme_pb)
+{
+ guint token;
+ gchar *pixmap;
+
+ /* Skip 'blah_file' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_STRING)
+ return G_TOKEN_STRING;
+
+ if (!*theme_pb)
+ *theme_pb = theme_pixbuf_new ();
+
+ pixmap = gtk_rc_find_pixmap_in_path(scanner, scanner->value.v_string);
+ if (pixmap)
+ {
+ theme_pixbuf_set_filename (*theme_pb, pixmap);
+ g_free (pixmap);
+ }
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_border (GScanner *scanner,
+ ThemePixbuf **theme_pb)
+{
+ guint token;
+ gint left, right, top, bottom;
+
+ /* Skip 'blah_border' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_LEFT_CURLY)
+ return G_TOKEN_LEFT_CURLY;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+ left = scanner->value.v_int;
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_COMMA)
+ return G_TOKEN_COMMA;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+ right = scanner->value.v_int;
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_COMMA)
+ return G_TOKEN_COMMA;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+ top = scanner->value.v_int;
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_COMMA)
+ return G_TOKEN_COMMA;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+ bottom = scanner->value.v_int;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_RIGHT_CURLY)
+ return G_TOKEN_RIGHT_CURLY;
+
+ if (!*theme_pb)
+ *theme_pb = theme_pixbuf_new ();
+
+ theme_pixbuf_set_border (*theme_pb, left, right, top, bottom);
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_stretch(GScanner *scanner,
+ ThemePixbuf **theme_pb)
+{
+ guint token;
+ gboolean stretch;
+
+ /* Skip 'blah_stretch' */
+ token = g_scanner_get_next_token(scanner);
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token == TOKEN_TRUE)
+ stretch = TRUE;
+ else if (token == TOKEN_FALSE)
+ stretch = FALSE;
+ else
+ return TOKEN_TRUE;
+
+ if (!*theme_pb)
+ *theme_pb = theme_pixbuf_new ();
+
+ theme_pixbuf_set_stretch (*theme_pb, stretch);
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_recolorable(GScanner * scanner,
+ ThemeImage * data)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_RECOLORABLE)
+ return TOKEN_RECOLORABLE;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token == TOKEN_TRUE)
+ data->recolorable = 1;
+ else if (token == TOKEN_FALSE)
+ data->recolorable = 0;
+ else
+ return TOKEN_TRUE;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_function(GScanner * scanner,
+ ThemeImage *data)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_FUNCTION)
+ return TOKEN_FUNCTION;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if ((token >= TOKEN_D_HLINE) && (token <= TOKEN_D_HANDLE))
+ data->match_data.function = token;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_detail(GScanner * scanner,
+ ThemeImage * data)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_DETAIL)
+ return TOKEN_DETAIL;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_STRING)
+ return G_TOKEN_STRING;
+
+ if (data->match_data.detail)
+ g_free (data->match_data.detail);
+
+ data->match_data.detail = g_strdup(scanner->value.v_string);
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_state(GScanner * scanner,
+ ThemeImage * data)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_STATE)
+ return TOKEN_STATE;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token == TOKEN_NORMAL)
+ data->match_data.state = GTK_STATE_NORMAL;
+ else if (token == TOKEN_ACTIVE)
+ data->match_data.state = GTK_STATE_ACTIVE;
+ else if (token == TOKEN_PRELIGHT)
+ data->match_data.state = GTK_STATE_PRELIGHT;
+ else if (token == TOKEN_SELECTED)
+ data->match_data.state = GTK_STATE_SELECTED;
+ else if (token == TOKEN_INSENSITIVE)
+ data->match_data.state = GTK_STATE_INSENSITIVE;
+ else
+ return TOKEN_NORMAL;
+
+ data->match_data.flags |= THEME_MATCH_STATE;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_shadow(GScanner * scanner,
+ ThemeImage * data)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_SHADOW)
+ return TOKEN_SHADOW;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token == TOKEN_NONE)
+ data->match_data.shadow = GTK_SHADOW_NONE;
+ else if (token == TOKEN_IN)
+ data->match_data.shadow = GTK_SHADOW_IN;
+ else if (token == TOKEN_OUT)
+ data->match_data.shadow = GTK_SHADOW_OUT;
+ else if (token == TOKEN_ETCHED_IN)
+ data->match_data.shadow = GTK_SHADOW_ETCHED_IN;
+ else if (token == TOKEN_ETCHED_OUT)
+ data->match_data.shadow = GTK_SHADOW_ETCHED_OUT;
+ else
+ return TOKEN_NONE;
+
+ data->match_data.flags |= THEME_MATCH_SHADOW;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_arrow_direction(GScanner * scanner,
+ ThemeImage * data)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_ARROW_DIRECTION)
+ return TOKEN_ARROW_DIRECTION;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token == TOKEN_UP)
+ data->match_data.arrow_direction = GTK_ARROW_UP;
+ else if (token == TOKEN_DOWN)
+ data->match_data.arrow_direction = GTK_ARROW_DOWN;
+ else if (token == TOKEN_LEFT)
+ data->match_data.arrow_direction = GTK_ARROW_LEFT;
+ else if (token == TOKEN_RIGHT)
+ data->match_data.arrow_direction = GTK_ARROW_RIGHT;
+ else
+ return TOKEN_UP;
+
+ data->match_data.flags |= THEME_MATCH_ARROW_DIRECTION;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_gap_side(GScanner * scanner,
+ ThemeImage * data)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_GAP_SIDE)
+ return TOKEN_GAP_SIDE;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+
+ if (token == TOKEN_TOP)
+ data->match_data.gap_side = GTK_POS_TOP;
+ else if (token == TOKEN_BOTTOM)
+ data->match_data.gap_side = GTK_POS_BOTTOM;
+ else if (token == TOKEN_LEFT)
+ data->match_data.gap_side = GTK_POS_LEFT;
+ else if (token == TOKEN_RIGHT)
+ data->match_data.gap_side = GTK_POS_RIGHT;
+ else
+ return TOKEN_TOP;
+
+ data->match_data.flags |= THEME_MATCH_GAP_SIDE;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_orientation(GScanner * scanner,
+ ThemeImage * data)
+{
+ guint token;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_ORIENTATION)
+ return TOKEN_ORIENTATION;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_EQUAL_SIGN)
+ return G_TOKEN_EQUAL_SIGN;
+
+ token = g_scanner_get_next_token(scanner);
+
+ if (token == TOKEN_HORIZONTAL)
+ data->match_data.orientation = GTK_ORIENTATION_HORIZONTAL;
+ else if (token == TOKEN_VERTICAL)
+ data->match_data.orientation = GTK_ORIENTATION_VERTICAL;
+ else
+ return TOKEN_HORIZONTAL;
+
+ data->match_data.flags |= THEME_MATCH_ORIENTATION;
+
+ return G_TOKEN_NONE;
+}
+
+static void
+theme_image_ref (ThemeImage *data)
+{
+ data->refcount++;
+}
+
+static void
+theme_image_unref (ThemeImage *data)
+{
+ data->refcount--;
+ if (data->refcount == 0)
+ {
+ if (data->match_data.detail)
+ g_free (data->match_data.detail);
+ if (data->background)
+ theme_pixbuf_destroy (data->background);
+ if (data->overlay)
+ theme_pixbuf_destroy (data->overlay);
+ if (data->gap_start)
+ theme_pixbuf_destroy (data->gap_start);
+ if (data->gap)
+ theme_pixbuf_destroy (data->gap);
+ if (data->gap_end)
+ theme_pixbuf_destroy (data->gap_end);
+ g_free (data);
+ }
+}
+
+static void
+theme_data_ref (ThemeData *theme_data)
+{
+ theme_data->refcount++;
+}
+
+static void
+theme_data_unref (ThemeData *theme_data)
+{
+ theme_data->refcount--;
+ if (theme_data->refcount == 0)
+ {
+ g_list_foreach (theme_data->img_list, (GFunc) theme_image_unref, NULL);
+ g_list_free (theme_data->img_list);
+ g_free (theme_data);
+ }
+}
+
+static guint
+theme_parse_image(GScanner *scanner,
+ ThemeData *theme_data,
+ ThemeImage **data_return)
+{
+ guint token;
+ ThemeImage *data;
+
+ data = NULL;
+ token = g_scanner_get_next_token(scanner);
+ if (token != TOKEN_IMAGE)
+ return TOKEN_IMAGE;
+
+ token = g_scanner_get_next_token(scanner);
+ if (token != G_TOKEN_LEFT_CURLY)
+ return G_TOKEN_LEFT_CURLY;
+
+ data = g_malloc(sizeof(ThemeImage));
+
+ data->refcount = 1;
+
+ data->background = NULL;
+ data->overlay = NULL;
+ data->gap_start = NULL;
+ data->gap = NULL;
+ data->gap_end = NULL;
+
+ data->recolorable = FALSE;
+
+ data->match_data.function = 0;
+ data->match_data.detail = NULL;
+ data->match_data.flags = 0;
+
+ token = g_scanner_peek_next_token(scanner);
+ while (token != G_TOKEN_RIGHT_CURLY)
+ {
+ switch (token)
+ {
+ case TOKEN_FUNCTION:
+ token = theme_parse_function(scanner, data);
+ break;
+ case TOKEN_RECOLORABLE:
+ token = theme_parse_recolorable(scanner, data);
+ break;
+ case TOKEN_DETAIL:
+ token = theme_parse_detail(scanner, data);
+ break;
+ case TOKEN_STATE:
+ token = theme_parse_state(scanner, data);
+ break;
+ case TOKEN_SHADOW:
+ token = theme_parse_shadow(scanner, data);
+ break;
+ case TOKEN_GAP_SIDE:
+ token = theme_parse_gap_side(scanner, data);
+ break;
+ case TOKEN_ARROW_DIRECTION:
+ token = theme_parse_arrow_direction(scanner, data);
+ break;
+ case TOKEN_ORIENTATION:
+ token = theme_parse_orientation(scanner, data);
+ break;
+ case TOKEN_FILE:
+ token = theme_parse_file(scanner, &data->background);
+ break;
+ case TOKEN_BORDER:
+ token = theme_parse_border(scanner, &data->background);
+ break;
+ case TOKEN_STRETCH:
+ token = theme_parse_stretch(scanner, &data->background);
+ break;
+ case TOKEN_GAP_FILE:
+ token = theme_parse_file(scanner, &data->gap);
+ break;
+ case TOKEN_GAP_BORDER:
+ token = theme_parse_border(scanner, &data->gap);
+ break;
+ case TOKEN_GAP_START_FILE:
+ token = theme_parse_file(scanner, &data->gap_start);
+ break;
+ case TOKEN_GAP_START_BORDER:
+ token = theme_parse_border(scanner, &data->gap_start);
+ break;
+ case TOKEN_GAP_END_FILE:
+ token = theme_parse_file(scanner, &data->gap_end);
+ break;
+ case TOKEN_GAP_END_BORDER:
+ token = theme_parse_border(scanner, &data->gap_end);
+ break;
+ case TOKEN_OVERLAY_FILE:
+ token = theme_parse_file(scanner, &data->overlay);
+ break;
+ case TOKEN_OVERLAY_BORDER:
+ token = theme_parse_border(scanner, &data->overlay);
+ break;
+ case TOKEN_OVERLAY_STRETCH:
+ token = theme_parse_stretch(scanner, &data->overlay);
+ break;
+ default:
+ g_scanner_get_next_token(scanner);
+ token = G_TOKEN_RIGHT_CURLY;
+ break;
+ }
+ if (token != G_TOKEN_NONE)
+ {
+ /* error - cleanup for exit */
+ theme_image_unref (data);
+ *data_return = NULL;
+ return token;
+ }
+ token = g_scanner_peek_next_token(scanner);
+ }
+
+ token = g_scanner_get_next_token(scanner);
+
+ if (token != G_TOKEN_RIGHT_CURLY)
+ {
+ /* error - cleanup for exit */
+ theme_image_unref (data);
+ *data_return = NULL;
+ return G_TOKEN_RIGHT_CURLY;
+ }
+
+ /* everything is fine now - insert yer cruft */
+ *data_return = data;
+ return G_TOKEN_NONE;
+}
+
+static guint
+theme_parse_rc_style(GScanner * scanner,
+ GtkRcStyle * rc_style)
+{
+ static GQuark scope_id = 0;
+ ThemeData *theme_data;
+ guint old_scope;
+ guint token;
+ gint i;
+ ThemeImage *img;
+
+ /* Set up a new scope in this scanner. */
+
+ if (!scope_id)
+ scope_id = g_quark_from_string("theme_engine");
+
+ /* If we bail out due to errors, we *don't* reset the scope, so the
+ * error messaging code can make sense of our tokens.
+ */
+ old_scope = g_scanner_set_scope(scanner, scope_id);
+
+ /* Now check if we already added our symbols to this scope
+ * (in some previous call to theme_parse_rc_style for the
+ * same scanner.
+ */
+
+ if (!g_scanner_lookup_symbol(scanner, theme_symbols[0].name))
+ {
+ g_scanner_freeze_symbol_table(scanner);
+ for (i = 0; i < n_theme_symbols; i++)
+ g_scanner_scope_add_symbol(scanner, scope_id,
+ theme_symbols[i].name,
+ GINT_TO_POINTER(theme_symbols[i].token));
+ g_scanner_thaw_symbol_table(scanner);
+ }
+
+ /* We're ready to go, now parse the top level */
+
+ theme_data = g_new(ThemeData, 1);
+ theme_data->img_list = NULL;
+ theme_data->refcount = 1;
+
+ token = g_scanner_peek_next_token(scanner);
+ while (token != G_TOKEN_RIGHT_CURLY)
+ {
+ switch (token)
+ {
+ case TOKEN_IMAGE:
+ img = NULL;
+ token = theme_parse_image(scanner, theme_data, &img);
+ break;
+ default:
+ g_scanner_get_next_token(scanner);
+ token = G_TOKEN_RIGHT_CURLY;
+ break;
+ }
+
+ if (token != G_TOKEN_NONE)
+ {
+ g_list_foreach (theme_data->img_list, (GFunc)theme_image_unref, NULL);
+ g_list_free (theme_data->img_list);
+ g_free (theme_data);
+ return token;
+ }
+ else
+ {
+ theme_data->img_list = g_list_append(theme_data->img_list, img);
+ }
+ token = g_scanner_peek_next_token(scanner);
+ }
+
+ g_scanner_get_next_token(scanner);
+
+ rc_style->engine_data = theme_data;
+ g_scanner_set_scope(scanner, old_scope);
+
+ return G_TOKEN_NONE;
+}
+
+static void
+theme_merge_rc_style(GtkRcStyle * dest,
+ GtkRcStyle * src)
+{
+ ThemeData *src_data = src->engine_data;
+ ThemeData *dest_data = dest->engine_data;
+ GList *tmp_list1, *tmp_list2;
+
+ if (!dest_data)
+ {
+ dest_data = g_new(ThemeData, 1);
+ dest_data->img_list = NULL;
+ dest_data->refcount = 1;
+ dest->engine_data = dest_data;
+ }
+
+ if (src_data->img_list)
+ {
+ /* Copy src image list and append to dest image list */
+
+ tmp_list2 = g_list_last (dest_data->img_list);
+ tmp_list1 = src_data->img_list;
+
+ while (tmp_list1)
+ {
+ if (tmp_list2)
+ {
+ tmp_list2->next = g_list_alloc();
+ tmp_list2->next->data = tmp_list1->data;
+ tmp_list2->next->prev = tmp_list2;
+
+ tmp_list2 = tmp_list2->next;
+ }
+ else
+ {
+ dest_data->img_list = g_list_append (NULL, tmp_list1->data);
+ tmp_list2 = dest_data->img_list;
+ }
+
+ theme_data_ref (tmp_list1->data);
+ tmp_list1 = tmp_list1->next;
+ }
+ }
+}
+
+static void
+theme_rc_style_to_style(GtkStyle * style,
+ GtkRcStyle * rc_style)
+{
+ ThemeData *data = rc_style->engine_data;
+
+ style->klass = &pixmap_default_class;
+ style->engine_data = data;
+ theme_data_ref (data);
+}
+
+static void
+theme_duplicate_style(GtkStyle * dest,
+ GtkStyle * src)
+{
+ ThemeData *src_data = src->engine_data;
+ ThemeData *dest_data;
+
+ dest_data = g_new(ThemeData, 1);
+ dest_data->img_list = g_list_copy (src_data->img_list);
+ g_list_foreach (dest_data->img_list, (GFunc)theme_image_ref, NULL);
+
+ dest->klass = &pixmap_default_class;
+ dest->engine_data = dest_data;
+ theme_data_ref (dest_data);
+}
+
+static void
+theme_realize_style(GtkStyle * style)
+{
+}
+
+static void
+theme_unrealize_style(GtkStyle * style)
+{
+}
+
+static void
+theme_destroy_rc_style(GtkRcStyle * rc_style)
+{
+ theme_data_unref (rc_style->engine_data);
+}
+
+static void
+theme_destroy_style(GtkStyle * style)
+{
+ theme_data_unref (style->engine_data);
+}
+
+static void
+theme_set_background(GtkStyle * style,
+ GdkWindow * window,
+ GtkStateType state_type)
+{
+ GdkPixmap *pixmap;
+ gint parent_relative;
+
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(window != NULL);
+
+ if (style->bg_pixmap[state_type])
+ {
+ if (style->bg_pixmap[state_type] == (GdkPixmap *) GDK_PARENT_RELATIVE)
+ {
+ pixmap = NULL;
+ parent_relative = TRUE;
+ }
+ else
+ {
+ pixmap = style->bg_pixmap[state_type];
+ parent_relative = FALSE;
+ }
+
+ gdk_window_set_back_pixmap(window, pixmap, parent_relative);
+ }
+ else
+ gdk_window_set_background(window, &style->bg[state_type]);
+}
+
+void
+theme_init(GtkThemeEngine * engine)
+{
+ engine->parse_rc_style = theme_parse_rc_style;
+ engine->merge_rc_style = theme_merge_rc_style;
+ engine->rc_style_to_style = theme_rc_style_to_style;
+ engine->duplicate_style = theme_duplicate_style;
+ engine->realize_style = theme_realize_style;
+ engine->unrealize_style = theme_unrealize_style;
+ engine->destroy_rc_style = theme_destroy_rc_style;
+ engine->destroy_style = theme_destroy_style;
+ engine->set_background = theme_set_background;
+
+ gdk_rgb_init();
+
+ /*
+ * We enable the caches unconditionally (the -1 is used
+ * to inform gnome-libs to ignore its setting for the
+ * cache
+ */
+#if 0
+ gtk_widget_push_visual(gdk_imlib_get_visual());
+ gtk_widget_push_colormap(gdk_imlib_get_colormap());
+#endif /* 0 */
+}
+
+void
+theme_exit(void)
+{
+}
+
+/* The following function will be called by GTK+ when the module
+ * is loaded and checks to see if we are compatible with the
+ * version of GTK+ that loads us.
+ */
+G_MODULE_EXPORT const gchar* g_module_check_init (GModule *module);
+const gchar*
+g_module_check_init (GModule *module)
+{
+ return gtk_check_version (GTK_MAJOR_VERSION,
+ GTK_MINOR_VERSION,
+ GTK_MICRO_VERSION - GTK_INTERFACE_AGE);
+}
diff --git a/modules/engines/pixbuf/pixbuf-render.c b/modules/engines/pixbuf/pixbuf-render.c
new file mode 100644
index 000000000..43fa5f4a1
--- /dev/null
+++ b/modules/engines/pixbuf/pixbuf-render.c
@@ -0,0 +1,356 @@
+/* GTK+ Pixbuf Engine
+ * Copyright (C) 1998-2000 Red Hat Software
+ *
+ * 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 of the License, 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by Owen Taylor <otaylor@redhat.com>, based on code by
+ * Carsten Haitzler <raster@rasterman.com>
+ */
+
+#include "pixmap_theme.h"
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+GCache *pixbuf_cache = NULL;
+
+static void
+pixbuf_render (GdkPixbuf *src,
+ GdkWindow *window,
+ GdkBitmap *mask,
+ GdkRectangle *clip_rect,
+ gint src_x,
+ gint src_y,
+ gint src_width,
+ gint src_height,
+ gint dest_x,
+ gint dest_y,
+ gint dest_width,
+ gint dest_height)
+{
+ GdkPixbuf *tmp_pixbuf;
+ GdkRectangle rect;
+ int x_offset, y_offset;
+ art_u32 bg_color = 0xffffff;
+
+ if (dest_width <= 0 || dest_height <= 0)
+ return;
+
+ rect.x = dest_x;
+ rect.y = dest_y;
+ rect.width = dest_width;
+ rect.height = dest_height;
+
+ /* FIXME: we need the full mask, not a partial mask; the following is, however,
+ * horribly expensive
+ */
+ if (!mask && clip_rect && !gdk_rectangle_intersect (clip_rect, &rect, &rect))
+ return;
+
+ if (dest_width != src->art_pixbuf->width ||
+ dest_height != src->art_pixbuf->height)
+ {
+ ArtPixBuf *partial_src_art;
+ GdkPixbuf *partial_src_gdk;
+
+ if (src->art_pixbuf->n_channels == 3)
+ {
+ partial_src_art =
+ art_pixbuf_new_const_rgb (src->art_pixbuf->pixels + src_y * src->art_pixbuf->rowstride + src_x * src->art_pixbuf->n_channels,
+ src_width,
+ src_height,
+ src->art_pixbuf->rowstride);
+ }
+ else
+ {
+ partial_src_art =
+ art_pixbuf_new_const_rgba (src->art_pixbuf->pixels + src_y * src->art_pixbuf->rowstride + src_x * src->art_pixbuf->n_channels,
+ src_width,
+ src_height,
+ src->art_pixbuf->rowstride);
+ }
+
+ partial_src_gdk = gdk_pixbuf_new_from_art_pixbuf (partial_src_art);
+ tmp_pixbuf = gdk_pixbuf_new (ART_PIX_RGB, src->art_pixbuf->has_alpha, 8, rect.width, rect.height);
+
+ if (mask)
+ {
+ gdk_pixbuf_scale (partial_src_gdk, tmp_pixbuf, 0, 0, rect.width, rect.height,
+ dest_x - rect.x, dest_y - rect.y,
+ (double)dest_width / src_width, (double)dest_height / src_height,
+ ART_FILTER_BILINEAR);
+ }
+ else
+ {
+ gdk_pixbuf_composite_color (partial_src_gdk, tmp_pixbuf, 0, 0, rect.width, rect.height,
+ dest_x - rect.x, dest_y - rect.y,
+ (double)dest_width / src_width, (double)dest_height / src_height,
+ ART_FILTER_BILINEAR, 255, 0, 0, 16, bg_color, bg_color);
+ }
+
+ gdk_pixbuf_unref (partial_src_gdk);
+
+ x_offset = 0;
+ y_offset = 0;
+ }
+ else
+ {
+ tmp_pixbuf = src;
+ gdk_pixbuf_ref (tmp_pixbuf);
+
+ x_offset = src_x + rect.x - dest_x;
+ y_offset = src_y + rect.y - dest_y;
+ }
+
+ if (mask)
+ {
+ GdkGC *tmp_gc;
+
+ gdk_pixbuf_render_threshold_alpha (tmp_pixbuf, mask,
+ x_offset, y_offset,
+ rect.x, rect.y,
+ rect.width, rect.height,
+ 128);
+
+ tmp_gc = gdk_gc_new (window);
+ gdk_pixbuf_render_to_drawable (tmp_pixbuf, window, tmp_gc,
+ x_offset, y_offset,
+ rect.x, rect.y,
+ rect.width, rect.height,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+ gdk_gc_unref (tmp_gc);
+ }
+ else
+ gdk_pixbuf_render_to_drawable_alpha (tmp_pixbuf, window,
+ x_offset, y_offset,
+ rect.x, rect.y,
+ rect.width, rect.height,
+ GDK_PIXBUF_ALPHA_BILEVEL, 128,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+ gdk_pixbuf_unref (tmp_pixbuf);
+}
+
+ThemePixbuf *
+theme_pixbuf_new (void)
+{
+ ThemePixbuf *result = g_new (ThemePixbuf, 1);
+ result->filename = NULL;
+ result->pixbuf = NULL;
+
+ result->stretch = TRUE;
+ result->border_left = 0;
+ result->border_right = 0;
+ result->border_bottom = 0;
+ result->border_top = 0;
+
+ return result;
+}
+
+void
+theme_pixbuf_destroy (ThemePixbuf *theme_pb)
+{
+ if (theme_pb->pixbuf)
+ g_cache_remove (pixbuf_cache, theme_pb->pixbuf);
+}
+
+void
+theme_pixbuf_set_filename (ThemePixbuf *theme_pb,
+ const char *filename)
+{
+ if (theme_pb->pixbuf)
+ {
+ g_cache_remove (pixbuf_cache, theme_pb->pixbuf);
+ theme_pb->pixbuf = NULL;
+ }
+
+ if (theme_pb->filename)
+ g_free (theme_pb->filename);
+
+ theme_pb->filename = g_strdup (filename);
+}
+
+void
+theme_pixbuf_set_border (ThemePixbuf *theme_pb,
+ gint left,
+ gint right,
+ gint top,
+ gint bottom)
+{
+ theme_pb->border_left = left;
+ theme_pb->border_right = right;
+ theme_pb->border_top = top;
+ theme_pb->border_bottom = bottom;
+}
+
+void
+theme_pixbuf_set_stretch (ThemePixbuf *theme_pb,
+ gboolean stretch)
+{
+ theme_pb->stretch = stretch;
+}
+
+GdkPixbuf *
+pixbuf_cache_value_new (gchar *filename)
+{
+ GdkPixbuf *result = gdk_pixbuf_new_from_file (filename);
+ if (!result)
+ g_warning("Pixbuf theme: Cannot load pixmap file %s\n", filename);
+
+ return result;
+}
+
+GdkPixbuf *
+theme_pixbuf_get_pixbuf (ThemePixbuf *theme_pb)
+{
+ if (!theme_pb->pixbuf)
+ {
+ if (!pixbuf_cache)
+ pixbuf_cache = g_cache_new ((GCacheNewFunc)pixbuf_cache_value_new,
+ (GCacheDestroyFunc)gdk_pixbuf_unref,
+ (GCacheDupFunc)g_strdup,
+ (GCacheDestroyFunc)g_free,
+ g_str_hash, g_direct_hash, g_str_equal);
+
+ theme_pb->pixbuf = g_cache_insert (pixbuf_cache, theme_pb->filename);
+ }
+
+ return theme_pb->pixbuf;
+}
+
+void
+theme_pixbuf_render (ThemePixbuf *theme_pb,
+ GdkWindow *window,
+ GdkBitmap *mask,
+ GdkRectangle *clip_rect,
+ guint component_mask,
+ gboolean center,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkPixbuf *pixbuf = theme_pixbuf_get_pixbuf (theme_pb);
+ gint src_x[4], src_y[4], dest_x[4], dest_y[4];
+
+ if (!pixbuf)
+ return;
+
+ if (theme_pb->stretch)
+ {
+ src_x[0] = 0;
+ src_x[1] = theme_pb->border_left;
+ src_x[2] = pixbuf->art_pixbuf->width - theme_pb->border_right;
+ src_x[3] = pixbuf->art_pixbuf->width;
+
+ src_y[0] = 0;
+ src_y[1] = theme_pb->border_top;
+ src_y[2] = pixbuf->art_pixbuf->height - theme_pb->border_bottom;
+ src_y[3] = pixbuf->art_pixbuf->height;
+
+ dest_x[0] = x;
+ dest_x[1] = x + theme_pb->border_left;
+ dest_x[2] = x + width - theme_pb->border_right;
+ dest_x[3] = x + width;
+
+ dest_y[0] = y;
+ dest_y[1] = y + theme_pb->border_top;
+ dest_y[2] = y + height - theme_pb->border_bottom;
+ dest_y[3] = y + height;
+
+ if (component_mask & COMPONENT_ALL)
+ component_mask = (COMPONENT_ALL - 1) & ~component_mask;
+
+#define RENDER_COMPONENT(X1,X2,Y1,Y2) \
+ pixbuf_render (pixbuf, window, mask, clip_rect, \
+ src_x[X1], src_y[Y1], \
+ src_x[X2] - src_x[X1], src_y[Y2] - src_y[Y1], \
+ dest_x[X1], dest_y[Y1], \
+ dest_x[X2] - dest_x[X1], dest_y[Y2] - dest_y[Y1]);
+
+ if (component_mask & COMPONENT_NORTH_WEST)
+ RENDER_COMPONENT (0, 1, 0, 1);
+
+ if (component_mask & COMPONENT_NORTH)
+ RENDER_COMPONENT (1, 2, 0, 1);
+
+ if (component_mask & COMPONENT_NORTH_EAST)
+ RENDER_COMPONENT (2, 3, 0, 1);
+
+ if (component_mask & COMPONENT_WEST)
+ RENDER_COMPONENT (0, 1, 1, 2);
+
+ if (component_mask & COMPONENT_CENTER)
+ RENDER_COMPONENT (1, 2, 1, 2);
+
+ if (component_mask & COMPONENT_EAST)
+ RENDER_COMPONENT (2, 3, 1, 2);
+
+ if (component_mask & COMPONENT_SOUTH_WEST)
+ RENDER_COMPONENT (0, 1, 2, 3);
+
+ if (component_mask & COMPONENT_SOUTH)
+ RENDER_COMPONENT (1, 2, 2, 3);
+
+ if (component_mask & COMPONENT_SOUTH_EAST)
+ RENDER_COMPONENT (2, 3, 2, 3);
+ }
+ else
+ {
+ if (center)
+ {
+ x += (width - pixbuf->art_pixbuf->width) / 2;
+ y += (height - pixbuf->art_pixbuf->height) / 2;
+
+ pixbuf_render (pixbuf, window, NULL, clip_rect,
+ 0, 0,
+ pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height,
+ x, y,
+ pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height);
+ }
+ else
+ {
+ GdkPixmap *tmp_pixmap;
+ GdkGC *tmp_gc;
+ GdkGCValues gc_values;
+
+ tmp_pixmap = gdk_pixmap_new (window,
+ pixbuf->art_pixbuf->width,
+ pixbuf->art_pixbuf->height,
+ -1);
+ tmp_gc = gdk_gc_new (tmp_pixmap);
+ gdk_pixbuf_render_to_drawable (pixbuf, tmp_pixmap, tmp_gc,
+ 0, 0,
+ 0, 0,
+ pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+ gdk_gc_unref (tmp_gc);
+
+ gc_values.fill = GDK_TILED;
+ gc_values.tile = tmp_pixmap;
+ tmp_gc = gdk_gc_new_with_values (window,
+ &gc_values, GDK_GC_FILL | GDK_GC_TILE);
+ if (clip_rect)
+ gdk_draw_rectangle (window, tmp_gc, TRUE,
+ clip_rect->x, clip_rect->y, clip_rect->width, clip_rect->height);
+ else
+ gdk_draw_rectangle (window, tmp_gc, TRUE, x, y, width, height);
+
+ gdk_gc_unref (tmp_gc);
+ gdk_pixmap_unref (tmp_pixmap);
+ }
+ }
+}
diff --git a/modules/engines/pixbuf/pixbuf.h b/modules/engines/pixbuf/pixbuf.h
new file mode 100644
index 000000000..a72f384b0
--- /dev/null
+++ b/modules/engines/pixbuf/pixbuf.h
@@ -0,0 +1,172 @@
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+/* internals */
+
+typedef struct _ThemeData ThemeData;
+typedef struct _ThemeImage ThemeImage;
+typedef struct _ThemeMatchData ThemeMatchData;
+typedef struct _ThemePixbuf ThemePixbuf;
+
+enum
+{
+ TOKEN_IMAGE = G_TOKEN_LAST + 1,
+ TOKEN_FUNCTION,
+ TOKEN_FILE,
+ TOKEN_STRETCH,
+ TOKEN_RECOLORABLE,
+ TOKEN_BORDER,
+ TOKEN_DETAIL,
+ TOKEN_STATE,
+ TOKEN_SHADOW,
+ TOKEN_GAP_SIDE,
+ TOKEN_GAP_FILE,
+ TOKEN_GAP_BORDER,
+ TOKEN_GAP_START_FILE,
+ TOKEN_GAP_START_BORDER,
+ TOKEN_GAP_END_FILE,
+ TOKEN_GAP_END_BORDER,
+ TOKEN_OVERLAY_FILE,
+ TOKEN_OVERLAY_BORDER,
+ TOKEN_OVERLAY_STRETCH,
+ TOKEN_ARROW_DIRECTION,
+ TOKEN_D_HLINE,
+ TOKEN_D_VLINE,
+ TOKEN_D_SHADOW,
+ TOKEN_D_POLYGON,
+ TOKEN_D_ARROW,
+ TOKEN_D_DIAMOND,
+ TOKEN_D_OVAL,
+ TOKEN_D_STRING,
+ TOKEN_D_BOX,
+ TOKEN_D_FLAT_BOX,
+ TOKEN_D_CHECK,
+ TOKEN_D_OPTION,
+ TOKEN_D_CROSS,
+ TOKEN_D_RAMP,
+ TOKEN_D_TAB,
+ TOKEN_D_SHADOW_GAP,
+ TOKEN_D_BOX_GAP,
+ TOKEN_D_EXTENSION,
+ TOKEN_D_FOCUS,
+ TOKEN_D_SLIDER,
+ TOKEN_D_ENTRY,
+ TOKEN_D_HANDLE,
+ TOKEN_TRUE,
+ TOKEN_FALSE,
+ TOKEN_TOP,
+ TOKEN_UP,
+ TOKEN_BOTTOM,
+ TOKEN_DOWN,
+ TOKEN_LEFT,
+ TOKEN_RIGHT,
+ TOKEN_NORMAL,
+ TOKEN_ACTIVE,
+ TOKEN_PRELIGHT,
+ TOKEN_SELECTED,
+ TOKEN_INSENSITIVE,
+ TOKEN_NONE,
+ TOKEN_IN,
+ TOKEN_OUT,
+ TOKEN_ETCHED_IN,
+ TOKEN_ETCHED_OUT,
+ TOKEN_ORIENTATION,
+ TOKEN_HORIZONTAL,
+ TOKEN_VERTICAL,
+};
+
+typedef enum
+{
+ COMPONENT_NORTH_WEST = 1 << 0,
+ COMPONENT_NORTH = 1 << 1,
+ COMPONENT_NORTH_EAST = 1 << 2,
+ COMPONENT_WEST = 1 << 3,
+ COMPONENT_CENTER = 1 << 4,
+ COMPONENT_EAST = 1 << 5,
+ COMPONENT_SOUTH_EAST = 1 << 6,
+ COMPONENT_SOUTH = 1 << 7,
+ COMPONENT_SOUTH_WEST = 1 << 8,
+ COMPONENT_ALL = 1 << 9
+} ThemePixbufComponent;
+
+typedef enum {
+ THEME_MATCH_GAP_SIDE = 1 << 0,
+ THEME_MATCH_ORIENTATION = 1 << 1,
+ THEME_MATCH_STATE = 1 << 2,
+ THEME_MATCH_SHADOW = 1 << 3,
+ THEME_MATCH_ARROW_DIRECTION = 1 << 4
+} ThemeMatchFlags;
+
+struct _ThemeData
+{
+ guint refcount;
+ GList *img_list;
+};
+
+struct _ThemePixbuf
+{
+ gchar *filename;
+ GdkPixbuf *pixbuf;
+ gboolean stretch;
+ gint border_left;
+ gint border_right;
+ gint border_bottom;
+ gint border_top;
+};
+
+struct _ThemeMatchData
+{
+ guint function; /* Mandatory */
+ gchar *detail;
+
+ ThemeMatchFlags flags;
+
+ GtkPositionType gap_side;
+ GtkOrientation orientation;
+ GtkStateType state;
+ GtkShadowType shadow;
+ GtkArrowType arrow_direction;
+};
+
+struct _ThemeImage
+{
+ guint refcount;
+
+ ThemePixbuf *background;
+ ThemePixbuf *overlay;
+ ThemePixbuf *gap_start;
+ ThemePixbuf *gap;
+ ThemePixbuf *gap_end;
+
+ gchar recolorable;
+
+ ThemeMatchData match_data;
+};
+
+
+ThemePixbuf *theme_pixbuf_new (void);
+void theme_pixbuf_destroy (ThemePixbuf *theme_pb);
+void theme_pixbuf_set_filename (ThemePixbuf *theme_pb,
+ const char *filename);
+GdkPixbuf * theme_pixbuf_get_pixbuf (ThemePixbuf *theme_pb);
+void theme_pixbuf_set_border (ThemePixbuf *theme_pb,
+ gint left,
+ gint right,
+ gint top,
+ gint bottom);
+void theme_pixbuf_set_stretch (ThemePixbuf *theme_pb,
+ gboolean stretch);
+void theme_pixbuf_render (ThemePixbuf *theme_pb,
+ GdkWindow *window,
+ GdkBitmap *mask,
+ GdkRectangle *clip_rect,
+ guint component_mask,
+ gboolean center,
+ gint dest_x,
+ gint dest_y,
+ gint dest_width,
+ gint dest_height);
+
+
+
+extern GtkStyleClass pixmap_default_class;