]> Pileus Git - ~andy/gtk/commitdiff
Initial revision
authorOwen Taylor <otaylor@src.gnome.org>
Mon, 7 Feb 2000 02:36:39 +0000 (02:36 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Mon, 7 Feb 2000 02:36:39 +0000 (02:36 +0000)
modules/engines/pixbuf/ChangeLog [new file with mode: 0644]
modules/engines/pixbuf/README [new file with mode: 0644]
modules/engines/pixbuf/pixbuf-draw.c [new file with mode: 0644]
modules/engines/pixbuf/pixbuf-main.c [new file with mode: 0644]
modules/engines/pixbuf/pixbuf-render.c [new file with mode: 0644]
modules/engines/pixbuf/pixbuf.h [new file with mode: 0644]

diff --git a/modules/engines/pixbuf/ChangeLog b/modules/engines/pixbuf/ChangeLog
new file mode 100644 (file)
index 0000000..d73045b
--- /dev/null
@@ -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 (file)
index 0000000..6b48ec6
--- /dev/null
@@ -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 (file)
index 0000000..a540700
--- /dev/null
@@ -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 (file)
index 0000000..1d47a4b
--- /dev/null
@@ -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 (file)
index 0000000..43fa5f4
--- /dev/null
@@ -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 (file)
index 0000000..a72f384
--- /dev/null
@@ -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;