]> Pileus Git - ~andy/gtk/commitdiff
Move more text widget headers into the private header list
authorHavoc Pennington <hp@redhat.com>
Tue, 26 Sep 2000 20:22:17 +0000 (20:22 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Tue, 26 Sep 2000 20:22:17 +0000 (20:22 +0000)
2000-09-26  Havoc Pennington  <hp@redhat.com>

* gtk/Makefile.am (gtk_private_h_sources): Move more text widget
headers into the private header list

* Makefile.am (pkgconfig_DATA): install pkg-config files

* configure.in: add pkg-config files

* gdk-2.0.pc.in, gdk-pixbuf.pc.in, gtk+-2.0.pc.in: pkg-config files

* gtk/gtkwindow.c (gtk_window_read_rcfiles): Invalidate
outstanding icon caches on theme change.

* gtk/gtkiconfactory.h, gtk/gtkiconfactory.c: New icon system. Three
important types:

(GtkIconSource): Specification for creating a pixbuf
appropriate for a direction/state/size triplet from
a source pixbuf or filename

(GtkIconSet): List of GtkIconSource objects that are used to
create the "same" icon (e.g. an OK button icon), and cache for
rendered icons

(GtkIconFactory): Hash from stock ID to GtkIconSet; used to look
up the icon set for a given stock ID.  GTK maintains a stack of
GtkIconFactory to search, and applications or libraries can add
additional icon factories on top of the stack

        * gtk/gtkrc.h, gtk/gtkrc.c: When loading an RcStyle, parse
the set of GtkIconSource specified for a given stock ID into
a GtkIconSet, and put the GtkIconSet into a GtkIconFactory for the
RcStyle, under the specified stock ID.

* gtk/gtkstyle.h, gtk/gtkstyle.c: Add a virtual function
render_icon used to derive a GdkPixbuf from a GtkIconSource.
This allows people to theme how prelight, insensitive, etc. are
done.

(gtk_style_lookup_icon_set): Look up a stock ID in the list of
icon factories for a style, and return the resulting
icon set if any.

(gtk_style_render_icon): Render an icon using the render_icon
method in the GtkStyleClass.

* gtk/gtkwidget.h, gtk/gtkwidget.c (gtk_widget_render_icon):
Use the style for a given widget to look up a stock ID, get the
icon set, and render an icon using the render_icon method
of the style

* gtk/gtkstock.h, gtk/gtkstock.c: Header with the GtkStockItem type
(contains information about a stock item), the built-in stock item
IDs, and functions to add/lookup stock items.

* gtk/stock-icons/*: Stock icons that come with GTK

* gtk/gtkbutton.h, gtk/gtkbutton.c (gtk_button_new_stock): Returns
a button based on a GtkStockItem
(gtk_button_new_accel): Takes a uline string and accel group, and
installs the accelerator.

* gtk/gtkimage.h, gtk/gtkimage.c: Make this into a generic
image-display widget.

71 files changed:
Makefile.am
configure.in
gdk-2.0.pc.in [new file with mode: 0644]
gdk-pixbuf.pc.in [new file with mode: 0644]
gdk-pixbuf/ChangeLog
gdk-pixbuf/Makefile.am
gdk-pixbuf/gdk-pixbuf-data.c
gdk-pixbuf/gdk-pixbuf-private.h
gdk-pixbuf/gdk-pixbuf-util.c
gdk-pixbuf/gdk-pixbuf.h
gdk-pixbuf/make-inline-pixbuf.c [new file with mode: 0644]
gtk+-2.0.pc.in [new file with mode: 0644]
gtk/Makefile.am
gtk/gtk.h
gtk/gtkbutton.c
gtk/gtkbutton.h
gtk/gtkiconfactory.c [new file with mode: 0644]
gtk/gtkiconfactory.h [new file with mode: 0644]
gtk/gtkimage.c
gtk/gtkimage.h
gtk/gtkrc.c
gtk/gtkrc.h
gtk/gtkstock.c [new file with mode: 0644]
gtk/gtkstock.h [new file with mode: 0644]
gtk/gtkstyle.c
gtk/gtkstyle.h
gtk/gtkwidget.c
gtk/gtkwidget.h
gtk/stock-icons/Makefile.am [new file with mode: 0644]
gtk/stock-icons/dialog_error.png [new file with mode: 0644]
gtk/stock-icons/dialog_error_48.png [new file with mode: 0644]
gtk/stock-icons/dialog_info.png [new file with mode: 0644]
gtk/stock-icons/dialog_info_48.png [new file with mode: 0644]
gtk/stock-icons/dialog_question.png [new file with mode: 0644]
gtk/stock-icons/dialog_question_48.png [new file with mode: 0644]
gtk/stock-icons/dialog_warning.png [new file with mode: 0644]
gtk/stock-icons/dialog_warning_48.png [new file with mode: 0644]
gtk/stock-icons/stock_apply_20.png [new file with mode: 0644]
gtk/stock-icons/stock_button_apply.png [new file with mode: 0644]
gtk/stock-icons/stock_button_apply_24.png [new file with mode: 0644]
gtk/stock-icons/stock_button_cancel.png [new file with mode: 0644]
gtk/stock-icons/stock_button_cancel_24.png [new file with mode: 0644]
gtk/stock-icons/stock_button_close.png [new file with mode: 0644]
gtk/stock-icons/stock_button_close_24.png [new file with mode: 0644]
gtk/stock-icons/stock_button_no.png [new file with mode: 0644]
gtk/stock-icons/stock_button_no_24.png [new file with mode: 0644]
gtk/stock-icons/stock_button_ok.png [new file with mode: 0644]
gtk/stock-icons/stock_button_ok_24.png [new file with mode: 0644]
gtk/stock-icons/stock_button_yes.png [new file with mode: 0644]
gtk/stock-icons/stock_button_yes_24.png [new file with mode: 0644]
gtk/stock-icons/stock_cancel_20.png [new file with mode: 0644]
gtk/stock-icons/stock_close.png [new file with mode: 0644]
gtk/stock-icons/stock_close_20.png [new file with mode: 0644]
gtk/stock-icons/stock_close_24.png [new file with mode: 0644]
gtk/stock-icons/stock_dialog_error_48.png [new file with mode: 0644]
gtk/stock-icons/stock_dialog_info_48.png [new file with mode: 0644]
gtk/stock-icons/stock_dialog_question_48.png [new file with mode: 0644]
gtk/stock-icons/stock_dialog_warning_48.png [new file with mode: 0644]
gtk/stock-icons/stock_exit.png [new file with mode: 0644]
gtk/stock-icons/stock_exit_24.png [new file with mode: 0644]
gtk/stock-icons/stock_help.png [new file with mode: 0644]
gtk/stock-icons/stock_help_24.png [new file with mode: 0644]
gtk/stock-icons/stock_new.png [new file with mode: 0644]
gtk/stock-icons/stock_new_24.png [new file with mode: 0644]
gtk/stock-icons/stock_no_20.png [new file with mode: 0644]
gtk/stock-icons/stock_ok_20.png [new file with mode: 0644]
gtk/stock-icons/stock_open.png [new file with mode: 0644]
gtk/stock-icons/stock_open_24.png [new file with mode: 0644]
gtk/stock-icons/stock_save.png [new file with mode: 0644]
gtk/stock-icons/stock_save_24.png [new file with mode: 0644]
gtk/stock-icons/stock_yes_20.png [new file with mode: 0644]

index fbab5ecd6de696e8b84ff6f0e166e1d8ff7bd34e..0b42c1c0e1ac23f01f67b0fc87703dc975dfc2d4 100644 (file)
@@ -112,6 +112,9 @@ EXTRA_DIST =                        \
        examples/spinbutton/Makefile  \
        examples/find-examples.sh
 
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA= gdk-pixbuf.pc gdk-2.0.pc gtk+-2.0.pc
+
 dist-hook: gtk+.spec
        if test -e $(srcdir)/INSTALL.in && test -e $(srcdir)/README.in ; then \
             CONFIG_FILES="INSTALL:$(srcdir)/INSTALL.in README:$(srcdir)/README.in" \
index d33a4fe30901729fa3ef297dfb3b67c954f37228..5b1dca127b7d0bc220bca29e418f393a8490abf5 100644 (file)
@@ -1005,6 +1005,9 @@ gtk+.spec
 docs/gtk-config.1
 Makefile
 gtk-config-2.0
+gdk-pixbuf.pc
+gdk-2.0.pc
+gtk+-2.0.pc
 po/Makefile.in
 build/Makefile
 build/win32/Makefile
@@ -1031,6 +1034,7 @@ gdk/linux-fb/Makefile
 gtk/Makefile
 gtk/makefile.mingw
 gtk/gtkcompat.h
+gtk/stock-icons/Makefile
 modules/Makefile
 modules/linux-fb/Makefile
 ], [chmod +x gtk-config-2.0])
diff --git a/gdk-2.0.pc.in b/gdk-2.0.pc.in
new file mode 100644 (file)
index 0000000..0dc0332
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+target=@gdktarget@
+
+Name: GDK
+Description: GIMP Drawing Kit
+Version: @VERSION@
+Requires: gdk-pixbuf,pangox
+Libs: -L${libdir} @more_ldflags@ -lgdk-${target}-1.3 @more_libs@ @GDK_WLIBS@
+Cflags: -I${includedir}/gtk-2.0 -I${libdir}/gtk-2.0/include @more_cflags@
diff --git a/gdk-pixbuf.pc.in b/gdk-pixbuf.pc.in
new file mode 100644 (file)
index 0000000..96afc3d
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GdkPixbuf
+Description: Image loading and scaling
+Version: @VERSION@
+Requires: gobject-2.0,gmodule-2.0
+Libs: -L${libdir} -lgdk_pixbuf-1.3 @INTLLIBS@ @MATH_LIB@
+Cflags: -I${includedir}
index e8bb33219d1089df16374c3ce4ce0e7fded57b08..8a85fb836fb8b3058b53f7856cf3d79f54d80077 100644 (file)
@@ -1,3 +1,23 @@
+2000-09-26  Havoc Pennington  <hp@redhat.com>
+
+       * gdk-pixbuf-util.c (gdk_pixbuf_saturate_and_pixelate): Add this
+       function here, instead of putting it in a private GTK+ file.
+
+       * gdk-pixbuf-private.h (GdkPixbufInlineFormat): include an 
+       enum here for the known formats of inlined pixbufs.
+       Also, #define our file magic here.
+
+2000-06-23  Havoc Pennington  <hp@redhat.com>
+
+       * make-inline-pixbuf.c: Small program that creates C variable
+       declarations of inline pixbuf data. This can be read 
+       by gdk_pixbuf_new_from_inline.
+
+       * gdk-pixbuf.h (gdk_pixbuf_new_from_inline): New function to read
+       inline pixbuf data and create a pixbuf from it. 
+
+       * gdk-pixbuf-data.c (gdk_pixbuf_new_from_inline): implement here
+
 2000-09-07  Tor Lillqvist  <tml@iki.fi>
 
        * makefile.mingw.in: Use own version number for gdk-pixbuf DLLs,
@@ -27,6 +47,7 @@
        * io-wbmp.c: Some bug fixes - now tested to work.
 
 2000-07-27  Elliot Lee  <sopwith@redhat.com>
+
        * gdk-pixbuf-io.h, gdk-pixbuf-io.c: Add gdk_pixbuf_get_named_module() function to facilitate above change
        * io-wbmp.c, pixbufloader_wbmp.defs, gdk-pixbuf-io.c, Makefile: Implement loader for WBMP format.
        * io-bmp.c: Don't malloc a temporary buffer - use stack instead.
@@ -91,7 +112,7 @@ Thu Jul  6 11:49:47 2000  Owen Taylor  <otaylor@redhat.com>
 
        * Makefile.am (libgdk_pixbuf_la_LDFLAGS): Use GTK+ version
        soname scheme for gdk-pixbuf.
-
+       
 2000-06-21  Havoc Pennington  <hp@pobox.com>
 
        * gdk-pixbuf.c: Convert GdkPixbuf to GObject, leaving it opaque
index 4628de1cca3b2e0f481d5bb04d30f468a0c3b908..2247e657e3b49108c09e5d33194a05d32f436f9f 100644 (file)
@@ -148,6 +148,12 @@ LDADDS = libgdk_pixbuf-1.3.la $(GLIB_LIBS) $(STATIC_LIB_DEPS)
 
 test_gdk_pixbuf_LDADD = $(LDADDS)
 
+bin_PROGRAMS=make-inline-pixbuf
+
+make_inline_pixbuf_SOURCES=make-inline-pixbuf.c
+
+make_inline_pixbuf_LDADD = $(LDADDS)
+
 GDK_PIXBUF_LIBS = $(GLIB_LIBS)
 
 #
index 62634d214efeecbf56b6f1e741604f91b9f253be..94db20f37617ae46fb53499a74852075ece79b72 100644 (file)
@@ -23,6 +23,8 @@
 #include <config.h>
 #include "gdk-pixbuf.h"
 #include "gdk-pixbuf-private.h"
+#include <stdlib.h>
+#include <string.h>
 
 \f
 
@@ -75,3 +77,175 @@ gdk_pixbuf_new_from_data (const guchar *data, GdkColorspace colorspace, gboolean
 
        return pixbuf;
 }
+
+static guint32
+read_int (const guchar **p)
+{
+        guint32 num;
+
+        /* Note most significant bytes are first in the byte stream */
+        num =
+          (*p)[3]         |
+          ((*p)[2] << 8)  |
+          ((*p)[1] << 16) |
+          ((*p)[0] << 24);
+
+        *p += 4;
+
+        return num;
+}
+
+static gboolean
+read_bool (const guchar **p)
+{
+        gboolean val = **p != 0;
+        
+        ++(*p);
+        
+        return val;
+}
+
+static GdkPixbuf*
+read_raw_inline (const guchar *data, gboolean copy_pixels, int length)
+{
+        GdkPixbuf *pixbuf;
+        const guchar *p = data;
+        guint32 rowstride, width, height, colorspace,
+                n_channels, bits_per_sample;
+        gboolean has_alpha;
+        
+        if (length >= 0 && length < 12) {
+                /* Not enough buffer to hold the width/height/rowstride */
+                return NULL;
+        }
+
+        rowstride = read_int (&p);
+        width = read_int (&p);
+        height = read_int (&p);
+
+        if (rowstride < width)
+                return NULL; /* bad data from untrusted source. */
+
+        /* rowstride >= width, so we can trust width */
+        
+        length -= 12;
+
+        /* There's some better way like G_MAXINT/height > rowstride
+         * but I'm not sure it works, so stick to this for now.
+         */
+        if (((double)height) * ((double)rowstride) > (double)G_MAXINT)
+                return NULL; /* overflow */
+        
+        if (length >= 0 &&
+            length < (height * rowstride + 13)) {
+                /* Not enough buffer to hold the remaining header
+                 * information plus the data.
+                 */
+                
+                return NULL;
+        }
+        
+        /* Read the remaining 13 bytes of header information */
+            
+        has_alpha = read_bool (&p) != FALSE;
+        colorspace = read_int (&p);
+        n_channels = read_int (&p);
+        bits_per_sample = read_int (&p);
+
+        if (colorspace != GDK_COLORSPACE_RGB)
+                return NULL;
+
+        if (bits_per_sample != 8)
+                return NULL;
+
+        if (has_alpha && n_channels != 4)
+                return NULL;
+
+        if (!has_alpha && n_channels != 3)
+                return NULL;
+
+        if (copy_pixels) {
+                guchar *pixels;
+                gint dest_rowstride;
+                gint row;
+                
+                pixbuf = gdk_pixbuf_new (colorspace,
+                                         has_alpha, bits_per_sample,
+                                         width, height);
+
+                pixels = gdk_pixbuf_get_pixels (pixbuf);
+                dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+       
+                for (row = 0; row < height; row++) {
+                        memcpy (pixels, p, rowstride);
+                        pixels += dest_rowstride;
+                        p += rowstride;
+                }
+        } else {
+                pixbuf = gdk_pixbuf_new_from_data (p,
+                                                   colorspace,
+                                                   has_alpha,
+                                                   bits_per_sample,
+                                                   width, height,
+                                                   rowstride,
+                                                   NULL, NULL);
+        }
+
+        return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_new_from_inline:
+ * @data: An inlined GdkPixbuf
+ * @copy_pixels: whether to copy the pixels out of the inline data, or to use them in-place
+ *
+ * Create a #GdkPixbuf from a custom format invented to store pixbuf
+ * data in C program code. This library comes with a program called "make-inline-pixbuf"
+ * that can write out a variable definition containing an inlined pixbuf.
+ * This is useful if you want to ship a program with images, but
+ * don't want to depend on any external files.
+ * 
+ * The inline data format contains the pixels in #GdkPixbuf's native
+ * format.  Since the inline pixbuf is read-only static data, you
+ * don't need to copy it unless you intend to write to it.
+ * 
+ * Return value: A newly-created #GdkPixbuf structure with a reference count of
+ * 1.
+ **/
+GdkPixbuf*
+gdk_pixbuf_new_from_inline   (const guchar *inline_pixbuf,
+                              gboolean      copy_pixels,
+                              int           length)
+{
+        const guchar *p;
+        GdkPixbuf *pixbuf;
+        GdkPixbufInlineFormat format;
+
+        if (length >= 0 && length < 8) {
+                /* not enough bytes to contain even the magic number
+                 * and format code.
+                 */
+                return NULL;
+        }
+        
+        p = inline_pixbuf;
+
+        if (read_int (&p) != GDK_PIXBUF_INLINE_MAGIC_NUMBER) {
+                return NULL;
+        }
+
+        format = read_int (&p);
+
+        switch (format)
+        {
+        case GDK_PIXBUF_INLINE_RAW:
+                pixbuf = read_raw_inline (p, copy_pixels, length - 8);
+                break;
+
+        default:
+                return NULL;
+        }
+
+        return pixbuf;
+}
+
index 1b14e3cccd662272c63ddd233752b73fb2c3f946..e8eb7248a46f6ee75eaf87beab236d0dd5c5c9e3 100644 (file)
@@ -117,4 +117,14 @@ struct _GdkPixbufAnimationClass {
 
 \f
 
+#define GDK_PIXBUF_INLINE_MAGIC_NUMBER 0x47646B50 /* 'GdkP' */
+
+typedef enum
+{
+  GDK_PIXBUF_INLINE_RAW = 0,
+  GDK_PIXBUF_INLINE_RLE = 1
+} GdkPixbufInlineFormat;
+
+
+
 #endif
index 848aadd141d45304b86f007f1ec7a7c7513d61d1..db8ca758e5fc7cc75c81be738a81eef4f0f232f1 100644 (file)
@@ -131,3 +131,102 @@ gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
                          1.0, 1.0,
                          GDK_INTERP_NEAREST);
 }
+
+
+
+#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
+
+/**
+ * gdk_pixbuf_saturate_and_pixelate:
+ * @src: source image
+ * @dest: place to write modified version of @src
+ * @saturation: saturation factor
+ * @pixelate: whether to pixelate
+ *
+ * Modifies saturation and optionally pixelates @src, placing the
+ * result in @dest. @src and @dest may be the same pixbuf with no ill
+ * effects.  If @saturation is 1.0 then saturation is not changed. If
+ * it's less than 1.0, saturation is reduced (the image is darkened);
+ * if greater than 1.0, saturation is increased (the image is
+ * brightened). If @pixelate is TRUE, then pixels are faded in a
+ * checkerboard pattern to create a pixelated image. @src and @dest
+ * must have the same image format, size, and rowstride.
+ * 
+ **/
+void
+gdk_pixbuf_saturate_and_pixelate(const GdkPixbuf *src,
+                                 GdkPixbuf *dest,
+                                 gfloat saturation,
+                                 gboolean pixelate)
+{
+        /* NOTE that src and dest MAY be the same pixbuf! */
+  
+        g_return_if_fail (GDK_IS_PIXBUF (src));
+        g_return_if_fail (GDK_IS_PIXBUF (dest));
+        g_return_if_fail (gdk_pixbuf_get_height (src) == gdk_pixbuf_get_height (dest));
+        g_return_if_fail (gdk_pixbuf_get_width (src) == gdk_pixbuf_get_width (dest));
+        g_return_if_fail (gdk_pixbuf_get_rowstride (src) == gdk_pixbuf_get_rowstride (dest));
+        g_return_if_fail (gdk_pixbuf_get_colorspace (src) == gdk_pixbuf_get_colorspace (dest));
+  
+        if (saturation == 1.0 && !pixelate) {
+                if (dest != src)
+                        memcpy (gdk_pixbuf_get_pixels (dest),
+                                gdk_pixbuf_get_pixels (src),
+                                gdk_pixbuf_get_height (src) * gdk_pixbuf_get_rowstride (src));
+
+                return;
+        } else {
+                gint i, j;
+                gint width, height, has_alpha, rowstride;
+                guchar *target_pixels;
+                guchar *original_pixels;
+                guchar *current_pixel;
+                guchar intensity;
+
+                has_alpha = gdk_pixbuf_get_has_alpha (src);
+                width = gdk_pixbuf_get_width (src);
+                height = gdk_pixbuf_get_height (src);
+                rowstride = gdk_pixbuf_get_rowstride (src);
+                
+                target_pixels = gdk_pixbuf_get_pixels (dest);
+                original_pixels = gdk_pixbuf_get_pixels (src);
+
+                for (i = 0; i < height; i++) {
+                        for (j = 0; j < width; j++) {
+                                current_pixel = original_pixels + i*rowstride + j*(has_alpha?4:3);
+                                intensity = INTENSITY (*(current_pixel), *(current_pixel + 1), *(current_pixel + 2));
+                                if (pixelate && (i+j)%2 == 0) {
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3)) = intensity/2 + 127;
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) = intensity/2 + 127;
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) = intensity/2 + 127;
+                                } else if (pixelate) {
+#define DARK_FACTOR 0.7
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3)) =
+                                                (guchar) (((1.0 - saturation) * intensity
+                                                           + saturation * (*(current_pixel)))) * DARK_FACTOR;
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) =
+                                                (guchar) (((1.0 - saturation) * intensity
+                                                           + saturation * (*(current_pixel + 1)))) * DARK_FACTOR;
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) =
+                                                (guchar) (((1.0 - saturation) * intensity
+                                                           + saturation * (*(current_pixel + 2)))) * DARK_FACTOR;
+                                } else {
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3)) =
+                                                (guchar) ((1.0 - saturation) * intensity
+                                                          + saturation * (*(current_pixel)));
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) =
+                                                (guchar) ((1.0 - saturation) * intensity
+                                                          + saturation * (*(current_pixel + 1)));
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) =
+                                                (guchar) ((1.0 - saturation) * intensity
+                                                          + saturation * (*(current_pixel + 2)));
+                                }
+              
+                                if (has_alpha)
+                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 3) = *(current_pixel + 3);
+                        }
+                }
+
+                return;
+        }
+}
index a7074fd50ab6288e59aaf97cf32dae9a408dda7e..aaaad7fda2bdbca259171886825724015d400653 100644 (file)
@@ -36,7 +36,10 @@ extern "C" {
 
 \f
 
-/* Color spaces; right now only RGB is supported */
+/* Color spaces; right now only RGB is supported.
+ * Note that these values are encoded in inline pixbufs
+ * as ints, so don't reorder them
+ */
 typedef enum {
        GDK_COLORSPACE_RGB
 } GdkColorspace;
@@ -103,6 +106,11 @@ GdkPixbuf *gdk_pixbuf_new_from_data (const guchar *data,
 
 GdkPixbuf *gdk_pixbuf_new_from_xpm_data (const char **data);
 
+/* Read an inline pixbuf */
+GdkPixbuf *gdk_pixbuf_new_from_inline   (const guchar *inline_pixbuf,
+                                         gboolean      copy_pixels,
+                                         int           length);
+
 /* Adding an alpha channel */
 GdkPixbuf *gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf, gboolean substitute_color,
                                 guchar r, guchar g, guchar b);
@@ -114,6 +122,12 @@ void gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
                           GdkPixbuf *dest_pixbuf,
                           int dest_x, int dest_y);
 
+/* Brighten/darken and optionally make it pixelated-looking */
+void gdk_pixbuf_saturate_and_pixelate (const GdkPixbuf *src,
+                                       GdkPixbuf       *dest,
+                                       gfloat           saturation,
+                                       gboolean         pixelate);
+
 \f
 
 /* Rendering to a drawable */
diff --git a/gdk-pixbuf/make-inline-pixbuf.c b/gdk-pixbuf/make-inline-pixbuf.c
new file mode 100644 (file)
index 0000000..daf0a7e
--- /dev/null
@@ -0,0 +1,213 @@
+/* Program to convert an image file to inline C data
+ *
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * Developed by Havoc Pennington <hp@redhat.com>
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include "gdk-pixbuf-private.h"
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+void
+output_int (FILE *outfile, guint32 num, const char *comment)
+{
+  guchar bytes[4];
+
+  /* Note, most significant bytes first */
+  bytes[0] = num >> 24;
+  bytes[1] = num >> 16;
+  bytes[2] = num >> 8;
+  bytes[3] = num;
+
+  fprintf(outfile, "  /* %s (%u) */\n  0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,\n",
+          comment, num,
+          bytes[0], bytes[1], bytes[2], bytes[3]);  
+}
+
+void
+output_bool (FILE *outfile, gboolean val, const char *comment)
+{
+  fprintf(outfile, "  /* %s (%s) */\n  0x%.2x,\n",
+          comment,
+          val ? "TRUE" : "FALSE",
+          val ? 1 : 0);
+}
+
+void
+output_pixbuf (FILE *outfile, gboolean ext_symbols,
+               const char *varname,
+               GdkPixbuf *pixbuf)
+{
+  const char *modifier;
+  const guchar *p;
+  const guchar *end;
+  gboolean has_alpha;
+  int column;
+  
+  modifier = "static ";
+  if (ext_symbols)
+    modifier = "";
+  
+  fprintf (outfile, "%sconst guchar ", modifier);
+  fputs (varname, outfile);
+  fputs ("[] =\n", outfile);
+  fputs ("{\n", outfile);
+
+  p = gdk_pixbuf_get_pixels (pixbuf);
+  end = p + gdk_pixbuf_get_rowstride (pixbuf) * gdk_pixbuf_get_height (pixbuf);
+  has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+
+  /* Sync the order of writing with the order of reading in
+   * gdk-pixbuf-data.c
+   */
+  output_int (outfile, GDK_PIXBUF_INLINE_MAGIC_NUMBER, "File magic");
+  output_int (outfile, GDK_PIXBUF_INLINE_RAW, "Format of following stuff");
+  output_int (outfile, gdk_pixbuf_get_rowstride (pixbuf), "Rowstride");
+  output_int (outfile, gdk_pixbuf_get_width (pixbuf), "Width");
+  output_int (outfile, gdk_pixbuf_get_height (pixbuf), "Height");
+
+  output_bool (outfile, has_alpha, "Has an alpha channel");
+
+  output_int (outfile, gdk_pixbuf_get_colorspace (pixbuf), "Colorspace (0 == RGB, no other options implemented)");
+
+  output_int (outfile, gdk_pixbuf_get_n_channels (pixbuf), "Number of channels");
+
+  output_int (outfile, gdk_pixbuf_get_bits_per_sample (pixbuf), "Bits per sample");
+
+  fputs ("  /* Image data */\n", outfile);
+  
+  /* Copy the data in the pixbuf */
+  column = 0;
+  while (p != end)
+    {
+      guchar r, g, b, a;
+      
+      r = *p;
+      ++p;
+      g = *p;
+      ++p;
+      b = *p;
+      ++p;
+      if (has_alpha)
+        {
+          a = *p;
+          ++p;
+        }
+      else
+        a = 0;
+
+      
+      if (has_alpha)
+        fprintf(outfile, "  0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x", r, g, b, a);
+      else
+        fprintf(outfile, "  0x%.2x, 0x%.2x, 0x%.2x", r, g, b);
+
+      if (p != end)
+        fputs (",", outfile);
+      else
+        fputs ("\n", outfile);
+      
+      ++column;
+      
+      if (column > 2)
+        {
+          fputs ("\n", outfile);
+          column = 0;
+        }
+    }
+
+  fputs ("};\n\n", outfile);
+}
+
+void
+usage (void)
+{
+  fprintf (stderr, "Usage: make-inline-pixbuf [--extern-symbols] OUTFILE varname1 imagefile1 varname2 imagefile2 ...\n");
+  exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+  gboolean ext_symbols = FALSE;
+  FILE *outfile;
+  int i;
+  
+  gdk_pixbuf_init ();
+  
+  if (argc < 4)
+    usage ();
+
+  i = 1;
+  if (strcmp (argv[i], "--extern-symbols") == 0)
+    {
+      ext_symbols = TRUE;
+      ++i;
+      if (argc < 5)
+        usage ();
+    }
+
+  outfile = fopen (argv[i], "w");
+  if (outfile == NULL)
+    {
+      fprintf (stderr, "Failed to open output file `%s': %s\n",
+               argv[i], strerror (errno));
+      exit (1);
+    }
+
+  ++i;
+
+  fputs ("/* This file was automatically generated by the make-inline-pixbuf program.\n"
+         " * It contains inline RGB image data.\n"
+         " */\n\n", outfile);
+
+  /* Check for matched pairs of images/names */
+  if (((argc - i) % 2) != 0)
+    usage ();
+  
+  while (i < argc)
+    {
+      GdkPixbuf *pixbuf;
+
+      g_assert ((i + 1) < argc);
+      
+      pixbuf = gdk_pixbuf_new_from_file (argv[i+1]);
+
+      if (pixbuf == NULL)
+        {
+          fprintf (stderr, "Failed to open image file `%s': %s\n",
+                   argv[i+1], strerror (errno));
+
+          exit (1);
+        }
+
+      output_pixbuf (outfile, ext_symbols, argv[i], pixbuf);
+      
+      gdk_pixbuf_unref (pixbuf);
+      
+      i += 2;
+    }
+  
+  fclose (outfile);
+
+  return 0;
+}
diff --git a/gtk+-2.0.pc.in b/gtk+-2.0.pc.in
new file mode 100644 (file)
index 0000000..ddf6c4b
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+target=@gdktarget@
+
+Name: GTK+
+Description: GIMP Tool Kit
+Version: @VERSION@
+Requires: gdk-2.0
+Libs: -L${libdir} -lgtk-${target}-1.3
+Cflags: -I${includedir}
index 274ecc36ad5c02e02a1aa60580d95010968383c9..173ef56a924595b7997e34cfb4d1e69cc2d84bd4 100644 (file)
@@ -1,5 +1,7 @@
 ## Makefile.am for gtk+/gtk
 
+SUBDIRS=stock-icons
+
 INCLUDES = @STRIP_BEGIN@ \
        -DG_LOG_DOMAIN=\"Gtk\"                          \
        -DGTK_DISABLE_COMPAT_H                          \
@@ -96,6 +98,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \
        gtkhscrollbar.h         \
        gtkhseparator.h         \
        gtkhsv.h                \
+       gtkiconfactory.h        \
        gtkimage.h              \
        gtkimcontext.h          \
        gtkimmulticontext.h     \
@@ -141,6 +144,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \
        gtkspinbutton.h         \
        gtkstyle.h              \
        gtkstatusbar.h          \
+       gtkstock.h              \
        gtktable.h              \
        gtktearoffmenuitem.h    \
        gtktextbuffer.h         \
@@ -178,16 +182,18 @@ gtk_public_h_sources = @STRIP_BEGIN@ \
 # interface)
 
 gtk_semipublic_h_sources = @STRIP_BEGIN@ \
-       gtktextbtree.h          \
-       gtktextchild.h          \
        gtktextdisplay.h        \
        gtktextlayout.h         \
-       gtktextsegment.h        \
-       gtktexttypes.h          \
 @STRIP_END@    
 
 # GTK+ header files that don't get installed
 gtk_private_h_sources = @STRIP_BEGIN@ \
+       gtktextbtree.h          \
+       gtktextchild.h          \
+       gtktextsegment.h        \
+       gtktexttypes.h          \
+       gtktextiterprivate.h    \
+       gtktextmarkprivate.h    \
        gtktexttagprivate.h     \
 @STRIP_END@
 
@@ -238,6 +244,7 @@ gtk_c_sources = @STRIP_BEGIN@ \
        gtkhscrollbar.c         \
        gtkhseparator.c         \
        gtkhsv.c                \
+       gtkiconfactory.c        \
        gtkimage.c              \
        gtkimcontext.c          \
        gtkimcontextsimple.c    \
@@ -283,6 +290,7 @@ gtk_c_sources = @STRIP_BEGIN@ \
        gtksignal.c             \
        gtksocket.c             \
        gtkspinbutton.c         \
+       gtkstock.c              \
        gtkstyle.c              \
        gtkstatusbar.c          \
        gtktable.c              \
index 25765fdd3bd145d6cec674df995eb70cf8c1a58e..2e2bd5138260ce9f9e31180afebf8975794d3675 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -75,6 +75,7 @@
 #include <gtk/gtkhscale.h>
 #include <gtk/gtkhscrollbar.h>
 #include <gtk/gtkhseparator.h>
+#include <gtk/gtkiconfactory.h>
 #include <gtk/gtkimage.h>
 #include <gtk/gtkimcontext.h>
 #include <gtk/gtkimmulticontext.h>
 #include <gtk/gtksignal.h>
 #include <gtk/gtksocket.h>
 #include <gtk/gtkspinbutton.h>
+#include <gtk/gtkstock.h>
 #include <gtk/gtkstyle.h>
 #include <gtk/gtkstatusbar.h>
 #include <gtk/gtktable.h>
index 802873e00878d38a46a9d89a4fdb104bff978006..394688496b15667aec3846c0344bb74d53912035 100644 (file)
 #include "gtklabel.h"
 #include "gtkmain.h"
 #include "gtksignal.h"
-
+#include "gtkimage.h"
+#include "gtkhbox.h"
+#include "gtkstock.h"
+#include "gtkiconfactory.h"
 
 #define CHILD_SPACING     1
 #define DEFAULT_LEFT_POS  4
@@ -45,6 +48,7 @@ enum {
   LEAVE,
   LAST_SIGNAL
 };
+
 enum {
   ARG_0,
   ARG_LABEL,
@@ -311,6 +315,93 @@ gtk_button_new_with_label (const gchar *label)
   return button;
 }
 
+GtkWidget*
+gtk_button_new_stock (const gchar   *stock_id,
+                      GtkAccelGroup *accel_group)
+{
+  GtkWidget *button;
+  GtkStockItem item;
+
+  if (gtk_stock_lookup (stock_id, &item))
+    {
+      GtkWidget *label;
+      GtkWidget *image;
+      GtkWidget *hbox;
+      guint keyval;
+      
+      button = gtk_button_new ();
+
+      label = gtk_label_new (NULL);
+      keyval = gtk_label_parse_uline (GTK_LABEL (label),
+                                      item.label);
+
+      if (keyval && accel_group)
+        {
+          gtk_widget_add_accelerator (button,
+                                      "clicked",
+                                      accel_group,
+                                      keyval,
+                                      GDK_MOD1_MASK,
+                                      GTK_ACCEL_LOCKED);
+        }
+
+      /* Also add the stock accelerator if one was specified. */
+      if (item.keyval && accel_group)
+        {
+          gtk_widget_add_accelerator (button,
+                                      "clicked",
+                                      accel_group,
+                                      item.keyval,
+                                      item.modifier,
+                                      GTK_ACCEL_LOCKED);
+        }
+
+      image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+      hbox = gtk_hbox_new (FALSE, 0);
+
+      gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 2);
+      gtk_box_pack_end (GTK_BOX (hbox), label, TRUE, TRUE, 2);
+      
+      gtk_container_add (GTK_CONTAINER (button), hbox);
+      gtk_widget_show_all (hbox);
+    }
+  else
+    {
+      button = gtk_button_new_accel (stock_id, accel_group);
+    }
+  
+  return button;
+}
+
+GtkWidget*
+gtk_button_new_accel (const gchar   *uline_label,
+                      GtkAccelGroup *accel_group)
+{
+  GtkWidget *button;
+  GtkWidget *label;
+  guint keyval;
+
+  button = gtk_button_new ();
+  
+  label = gtk_label_new (NULL);
+  keyval = gtk_label_parse_uline (GTK_LABEL (label), uline_label);
+
+  if (keyval && accel_group)
+    {
+      gtk_widget_add_accelerator (button,
+                                  "clicked",
+                                  accel_group,
+                                  keyval,
+                                  GDK_MOD1_MASK,
+                                  GTK_ACCEL_LOCKED);
+    }
+  
+  gtk_container_add (GTK_CONTAINER (button), label);
+  gtk_widget_show (label);
+
+  return button;
+}
+
 void
 gtk_button_pressed (GtkButton *button)
 {
index a55460e03c08ff5430704ec08f883d6945df07e3..0d8c676d09667a9e72f9908e98294bc128f0b9f7 100644 (file)
@@ -75,7 +75,11 @@ struct _GtkButtonClass
 
 GtkType        gtk_button_get_type       (void) G_GNUC_CONST;
 GtkWidget*     gtk_button_new            (void);
-GtkWidget*     gtk_button_new_with_label (const gchar *label);
+GtkWidget*     gtk_button_new_with_label (const gchar   *label);
+GtkWidget*     gtk_button_new_stock      (const gchar   *stock_id,
+                                          GtkAccelGroup *accel_group);
+GtkWidget*     gtk_button_new_accel      (const gchar   *uline_label,
+                                          GtkAccelGroup *accel_group);
 void           gtk_button_pressed        (GtkButton *button);
 void           gtk_button_released       (GtkButton *button);
 void           gtk_button_clicked        (GtkButton *button);
diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
new file mode 100644 (file)
index 0000000..8924df7
--- /dev/null
@@ -0,0 +1,1127 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gtkiconfactory.h"
+#include "stock-icons/gtkstockpixbufs.h"
+#include "gtkstock.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+
+static gpointer parent_class = NULL;
+
+static void gtk_icon_factory_init       (GtkIconFactory      *icon_factory);
+static void gtk_icon_factory_class_init (GtkIconFactoryClass *klass);
+static void gtk_icon_factory_finalize   (GObject             *object);
+static void get_default_icons           (GtkIconFactory      *icon_factory);
+
+GType
+gtk_icon_factory_get_type (void)
+{
+  static GType object_type = 0;
+
+  if (!object_type)
+    {
+      static const GTypeInfo object_info =
+      {
+        sizeof (GtkIconFactoryClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gtk_icon_factory_class_init,
+        NULL,           /* class_finalize */
+        NULL,           /* class_data */
+        sizeof (GtkIconFactory),
+        0,              /* n_preallocs */
+        (GInstanceInitFunc) gtk_icon_factory_init,
+      };
+      
+      object_type = g_type_register_static (G_TYPE_OBJECT,
+                                            "GtkIconFactory",
+                                            &object_info);
+    }
+  
+  return object_type;
+}
+
+static void
+gtk_icon_factory_init (GtkIconFactory *factory)
+{
+  factory->icons = g_hash_table_new (g_str_hash, g_str_equal);
+}
+
+static void
+gtk_icon_factory_class_init (GtkIconFactoryClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->finalize = gtk_icon_factory_finalize;
+}
+
+static void
+free_icon_set (gpointer key, gpointer value, gpointer data)
+{
+  g_free (key);
+  gtk_icon_set_unref (value);
+}
+
+static void
+gtk_icon_factory_finalize (GObject *object)
+{
+  GtkIconFactory *factory = GTK_ICON_FACTORY (object);
+
+  g_hash_table_foreach (factory->icons, free_icon_set, NULL);
+  
+  g_hash_table_destroy (factory->icons);
+  
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+GtkIconFactory*
+gtk_icon_factory_new (void)
+{
+  return GTK_ICON_FACTORY (g_object_new (GTK_TYPE_ICON_FACTORY, NULL));
+}
+
+void
+gtk_icon_factory_add (GtkIconFactory *factory,
+                      const gchar    *stock_id,
+                      GtkIconSet     *icon_set)
+{
+  gpointer old_key = NULL;
+  gpointer old_value = NULL;
+
+  g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
+  g_return_if_fail (stock_id != NULL);
+  g_return_if_fail (icon_set != NULL);  
+
+  g_hash_table_lookup_extended (factory->icons, stock_id,
+                                &old_key, &old_value);
+
+  if (old_value == icon_set)
+    return;
+  
+  gtk_icon_set_ref (icon_set);
+
+  /* GHashTable key memory management is so fantastically broken. */
+  if (old_key)
+    g_hash_table_insert (factory->icons, old_key, icon_set);
+  else
+    g_hash_table_insert (factory->icons, g_strdup (stock_id), icon_set);
+
+  if (old_value)
+    gtk_icon_set_unref (old_value);
+}
+
+GtkIconSet *
+gtk_icon_factory_lookup (GtkIconFactory *factory,
+                         const gchar    *stock_id)
+{
+  g_return_val_if_fail (GTK_IS_ICON_FACTORY (factory), NULL);
+  g_return_val_if_fail (stock_id != NULL, NULL);
+  
+  return g_hash_table_lookup (factory->icons, stock_id);
+}
+
+static GtkIconFactory *gtk_default_icons = NULL;
+static GSList *default_factories = NULL;
+
+void
+gtk_icon_factory_add_default (GtkIconFactory *factory)
+{
+  g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
+
+  g_object_ref (G_OBJECT (factory));
+  
+  default_factories = g_slist_prepend (default_factories, factory);
+}
+
+void
+gtk_icon_factory_remove_default (GtkIconFactory  *factory)
+{
+  g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
+
+  default_factories = g_slist_remove (default_factories, factory);
+
+  g_object_unref (G_OBJECT (factory));
+}
+
+GtkIconSet *
+gtk_icon_factory_lookup_default (const gchar *stock_id)
+{
+  GSList *tmp_list;
+
+  g_return_val_if_fail (stock_id != NULL, NULL);
+  
+  tmp_list = default_factories;
+  while (tmp_list != NULL)
+    {
+      GtkIconSet *icon_set =
+        gtk_icon_factory_lookup (GTK_ICON_FACTORY (tmp_list->data),
+                                 stock_id);
+
+      if (icon_set)
+        return icon_set;
+
+      tmp_list = g_slist_next (tmp_list);
+    }
+
+  if (gtk_default_icons == NULL)
+    {
+      gtk_default_icons = gtk_icon_factory_new ();
+
+      get_default_icons (gtk_default_icons);
+    }
+  
+  return gtk_icon_factory_lookup (gtk_default_icons, stock_id);
+}
+
+static GtkIconSet *
+sized_icon_set_from_inline (const guchar *inline_data,
+                            const gchar  *size)
+{
+  GtkIconSet *set;
+
+  GtkIconSource source = { NULL, NULL, 0, 0, NULL,
+                           TRUE, TRUE, FALSE };
+
+  source.size = size;
+
+  set = gtk_icon_set_new ();
+
+  source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1);
+
+  g_assert (source.pixbuf);
+
+  gtk_icon_set_add_source (set, &source);
+
+  g_object_unref (G_OBJECT (source.pixbuf));
+  
+  return set;
+}
+
+static GtkIconSet *
+unsized_icon_set_from_inline (const guchar *inline_data)
+{
+  GtkIconSet *set;
+
+  /* This icon can be used for any direction/state/size */
+  GtkIconSource source = { NULL, NULL, 0, 0, 0,
+                           TRUE, TRUE, TRUE };
+
+  set = gtk_icon_set_new ();
+
+  source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1);
+
+  g_assert (source.pixbuf);
+
+  gtk_icon_set_add_source (set, &source);
+
+  g_object_unref (G_OBJECT (source.pixbuf));
+  
+  return set;
+}
+
+static void
+add_sized (GtkIconFactory *factory,
+           const guchar   *inline_data,
+           const gchar    *size,
+           const gchar    *stock_id)
+{
+  GtkIconSet *set;
+  
+  set = sized_icon_set_from_inline (inline_data, size);
+  
+  gtk_icon_factory_add (factory, stock_id, set);
+
+  gtk_icon_set_unref (set);
+}
+
+static void
+add_unsized (GtkIconFactory *factory,
+             const guchar   *inline_data,
+             const gchar    *stock_id)
+{
+  GtkIconSet *set;
+  
+  set = unsized_icon_set_from_inline (inline_data);
+  
+  gtk_icon_factory_add (factory, stock_id, set);
+
+  gtk_icon_set_unref (set);
+}
+
+static void
+get_default_icons (GtkIconFactory *factory)
+{
+  /* KEEP IN SYNC with gtkstock.c */
+
+  add_sized (factory, dialog_error, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_ERROR);
+  add_sized (factory, dialog_info, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_INFO);
+  add_sized (factory, dialog_question, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_QUESTION);
+  add_sized (factory, dialog_warning, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_WARNING);
+
+  add_sized (factory, stock_button_apply, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_APPLY);
+  add_sized (factory, stock_button_ok, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_OK);
+  add_sized (factory, stock_button_cancel, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_CANCEL);
+  add_sized (factory, stock_button_close, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_CLOSE);
+  add_sized (factory, stock_button_yes, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_YES);
+  add_sized (factory, stock_button_no, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_NO);
+    
+  add_unsized (factory, stock_close, GTK_STOCK_CLOSE);
+  add_unsized (factory, stock_exit, GTK_STOCK_QUIT);
+  add_unsized (factory, stock_help, GTK_STOCK_HELP);
+  add_unsized (factory, stock_new, GTK_STOCK_NEW);
+  add_unsized (factory, stock_open, GTK_STOCK_OPEN);
+  add_unsized (factory, stock_save, GTK_STOCK_SAVE);
+}
+
+/* Sizes */
+
+static GHashTable *icon_sizes = NULL;
+
+typedef struct _IconSize IconSize;
+
+struct _IconSize
+{
+  gchar *name;
+  
+  gboolean is_alias;
+
+  union
+  {
+    gchar *target;
+    struct
+    {
+      gint width;
+      gint height;
+    } size;
+  } d;
+};
+
+static IconSize*
+icon_size_new (const gchar *name)
+{
+  IconSize *is;
+
+  is = g_new0 (IconSize, 1);
+
+  is->name = g_strdup (name);
+
+  return is;
+}
+
+static void
+icon_size_free (IconSize *is)
+{
+  g_free (is->name);
+  
+  if (is->is_alias)
+    g_free (is->d.target);
+
+  g_free (is);
+}
+
+static void
+icon_size_insert (IconSize *is)
+{
+  gpointer old_key, old_value;
+
+  /* Remove old ones */
+  if (g_hash_table_lookup_extended (icon_sizes,
+                                    is->name,
+                                    &old_key, &old_value))
+    {
+      g_hash_table_remove (icon_sizes, is->name);
+      icon_size_free (old_value);
+    }
+  
+  g_hash_table_insert (icon_sizes,
+                       is->name, is);
+
+}
+
+static IconSize*
+icon_size_lookup (const gchar *name)
+{
+  IconSize *is;
+
+  is = g_hash_table_lookup (icon_sizes,
+                            name);
+
+  while (is && is->is_alias)
+    {
+      is = g_hash_table_lookup (icon_sizes,
+                                is->d.target);
+
+    }
+
+  return is;
+}
+
+static void
+icon_size_add (const gchar *name,
+               gint         width,
+               gint         height)
+{
+  IconSize *is;
+  
+  is = icon_size_new (name);
+  is->d.size.width = width;
+  is->d.size.height = height;
+  
+  icon_size_insert (is);
+}
+
+static void
+icon_alias_add (const gchar *name,
+                const gchar *target)
+{
+  IconSize *is;
+  
+  is = icon_size_new (name);
+  is->is_alias = TRUE;
+
+  is->d.target = g_strdup (target);
+
+  icon_size_insert (is);
+}
+
+static void
+init_icon_sizes (void)
+{
+  if (icon_sizes == NULL)
+    {
+      IconSize *is;
+      
+      icon_sizes = g_hash_table_new (g_str_hash, g_str_equal);
+
+      icon_size_add (GTK_ICON_SIZE_MENU, 16, 16);
+      icon_size_add (GTK_ICON_SIZE_BUTTON, 24, 24);
+      icon_size_add (GTK_ICON_SIZE_SMALL_TOOLBAR, 18, 18);
+      icon_size_add (GTK_ICON_SIZE_LARGE_TOOLBAR, 24, 24);
+      icon_size_add (GTK_ICON_SIZE_DIALOG, 48, 48);
+    }
+}
+
+gboolean
+gtk_icon_size_lookup (const gchar *alias,
+                      gint        *widthp,
+                      gint        *heightp)
+{
+  IconSize *is;
+  
+  g_return_val_if_fail (alias != NULL, FALSE);
+  
+  init_icon_sizes ();
+  
+  is = icon_size_lookup (alias);
+
+  if (is == NULL)
+    return FALSE;
+
+  if (widthp)
+    *widthp = is->d.size.width;
+
+  if (heightp)
+    *heightp = is->d.size.height;
+
+  return TRUE;
+}
+
+void
+gtk_icon_size_register (const gchar *alias,
+                        gint         width,
+                        gint         height)
+{
+  gpointer old_key, old_value;
+  
+  g_return_if_fail (alias != NULL);
+  g_return_if_fail (width > 0);
+  g_return_if_fail (height > 0);
+  
+  init_icon_sizes ();
+
+  icon_size_add (alias, width, height);
+}
+
+void
+gtk_icon_size_register_alias (const gchar *alias,
+                              const gchar *target)
+{
+  g_return_if_fail (alias != NULL);
+  g_return_if_fail (target != NULL);
+
+  init_icon_sizes ();
+
+  icon_alias_add (alias, target);
+}
+
+/* Icon Set */
+
+
+/* Clear icon set contents, drop references to all contained
+ * GdkPixbuf objects and forget all GtkIconSources. Used to
+ * recycle an icon set.
+ */
+static void gtk_icon_set_clear      (GtkIconSet       *icon_set);
+
+static GdkPixbuf *find_in_cache     (GtkIconSet       *icon_set,
+                                     GtkStyle         *style,
+                                     GtkTextDirection  direction,
+                                     GtkStateType      state,
+                                     const gchar      *size);
+static void       add_to_cache      (GtkIconSet       *icon_set,
+                                     GtkStyle         *style,
+                                     GtkTextDirection  direction,
+                                     GtkStateType      state,
+                                     const gchar      *size,
+                                     GdkPixbuf        *pixbuf);
+static void       clear_cache       (GtkIconSet       *icon_set,
+                                     gboolean          style_detach);
+static GSList*    copy_cache        (GtkIconSet       *icon_set,
+                                     GtkIconSet       *copy_recipient);
+static void       attach_to_style   (GtkIconSet       *icon_set,
+                                     GtkStyle         *style);
+static void       detach_from_style (GtkIconSet       *icon_set,
+                                     GtkStyle         *style);
+static void       style_dnotify     (gpointer          data);
+
+struct _GtkIconSet
+{
+  guint ref_count;
+
+  GSList *sources;
+
+  /* Cache of the last few rendered versions of the icon. */
+  GSList *cache;
+
+  guint cache_size;
+
+  guint cache_serial;
+};
+
+static guint cache_serial = 0;
+
+GtkIconSet*
+gtk_icon_set_new (void)
+{
+  GtkIconSet *icon_set;
+
+  icon_set = g_new (GtkIconSet, 1);
+
+  icon_set->ref_count = 1;
+  icon_set->sources = NULL;
+  icon_set->cache = NULL;
+  icon_set->cache_size = 0;
+  icon_set->cache_serial = cache_serial;
+  
+  return icon_set;
+}
+
+GtkIconSet*
+gtk_icon_set_ref (GtkIconSet *icon_set)
+{
+  g_return_val_if_fail (icon_set != NULL, NULL);
+  g_return_val_if_fail (icon_set->ref_count > 0, NULL);
+
+  icon_set->ref_count += 1;
+
+  return icon_set;
+}
+
+void
+gtk_icon_set_unref (GtkIconSet *icon_set)
+{
+  g_return_if_fail (icon_set != NULL);
+  g_return_if_fail (icon_set->ref_count > 0);
+
+  icon_set->ref_count -= 1;
+
+  if (icon_set->ref_count == 0)
+    {
+      GSList *tmp_list = icon_set->sources;
+      while (tmp_list != NULL)
+        {
+          gtk_icon_source_free (tmp_list->data);
+
+          tmp_list = g_slist_next (tmp_list);
+        }
+
+      clear_cache (icon_set, TRUE);
+
+      g_free (icon_set);
+    }
+}
+
+GtkIconSet*
+gtk_icon_set_copy (GtkIconSet *icon_set)
+{
+  GtkIconSet *copy;
+  GSList *tmp_list;
+  
+  copy = gtk_icon_set_new ();
+
+  tmp_list = icon_set->sources;
+  while (tmp_list != NULL)
+    {
+      copy->sources = g_slist_prepend (copy->sources,
+                                       gtk_icon_source_copy (tmp_list->data));
+
+      tmp_list = g_slist_next (tmp_list);
+    }
+
+  copy->sources = g_slist_reverse (copy->sources);
+
+  copy->cache = copy_cache (icon_set, copy);
+  copy->cache_size = icon_set->cache_size;
+  copy->cache_serial = icon_set->cache_serial;
+  
+  return copy;
+}
+
+
+static gboolean
+sizes_equivalent (const gchar *rhs, const gchar *lhs)
+{
+  gint r_w, r_h, l_w, l_h;
+
+  gtk_icon_size_lookup (rhs, &r_w, &r_h);
+  gtk_icon_size_lookup (lhs, &l_w, &l_h);
+
+  return r_w == l_w && r_h == l_h;
+}
+
+static GtkIconSource*
+find_and_prep_icon_source (GtkIconSet       *icon_set,
+                           GtkTextDirection  direction,
+                           GtkStateType      state,
+                           const gchar      *size)
+{
+  GtkIconSource *source;
+  GSList *tmp_list;
+
+
+  /* We need to find the best icon source.  Direction matters more
+   * than state, state matters more than size. icon_set->sources
+   * is sorted according to wildness, so if we take the first
+   * match we find it will be the least-wild match (if there are
+   * multiple matches for a given "wildness" then the RC file contained
+   * dumb stuff, and we end up with an arbitrary matching source)
+   */
+  
+  source = NULL;
+  tmp_list = icon_set->sources;
+  while (tmp_list != NULL)
+    {
+      GtkIconSource *s = tmp_list->data;
+      
+      if ((s->any_direction || (s->direction == direction)) &&
+          (s->any_state || (s->state == state)) &&
+          (s->any_size || (sizes_equivalent (size, s->size))))
+        {
+          source = s;
+          break;
+        }
+      
+      tmp_list = g_slist_next (tmp_list);
+    }
+
+  if (source == NULL)
+    return NULL;
+  
+  if (source->pixbuf == NULL)
+    {
+      gchar *full;
+      
+      g_assert (source->filename);
+
+      if (*source->filename != G_DIR_SEPARATOR)
+        full = gtk_rc_find_pixmap_in_path (NULL, source->filename);
+      else
+        full = g_strdup (source->filename);
+      
+      source->pixbuf = gdk_pixbuf_new_from_file (full);
+
+      g_free (full);
+      
+      if (source->pixbuf == NULL)
+        {
+          /* Remove this icon source so we don't keep trying to
+           * load it.
+           */
+          g_warning ("Failed to load icon '%s'", source->filename);
+          
+          icon_set->sources = g_slist_remove (icon_set->sources, source);
+
+          gtk_icon_source_free (source);
+
+          /* Try to fall back to other sources */
+          if (icon_set->sources != NULL)
+            return find_and_prep_icon_source (icon_set,
+                                              direction,
+                                              state,
+                                              size);
+          else
+            return NULL;
+        }
+    }
+
+  return source;
+}
+
+GdkPixbuf*
+gtk_icon_set_render_icon (GtkIconSet        *icon_set,
+                          GtkStyle          *style,
+                          GtkTextDirection   direction,
+                          GtkStateType       state,
+                          const gchar       *size,
+                          GtkWidget         *widget,
+                          const char        *detail)
+{
+  GdkPixbuf *icon;
+  GtkIconSource *source;
+  
+  /* FIXME conceivably, everywhere this function
+   * returns NULL, we should return some default
+   * dummy icon like a question mark or the image icon
+   * from netscape
+   */
+  
+  g_return_val_if_fail (icon_set != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
+
+  if (icon_set->sources == NULL)
+    return NULL;
+  
+  icon = find_in_cache (icon_set, style, direction,
+                        state, size);
+
+  if (icon)
+    {
+      g_object_ref (G_OBJECT (icon));
+      return icon;
+    }
+
+  
+  source = find_and_prep_icon_source (icon_set, direction, state, size);
+
+  if (source == NULL)
+    return NULL;
+
+  g_assert (source->pixbuf != NULL);
+  
+  icon = gtk_style_render_icon (style,
+                                source,
+                                direction,
+                                state,
+                                size,
+                                widget,
+                                detail);
+
+  if (icon == NULL)
+    {
+      g_warning ("Theme engine failed to render icon");
+      return NULL;
+    }
+  
+  add_to_cache (icon_set, style, direction, state, size, icon);
+  
+  return icon;
+}
+
+/* Order sources by their "wildness", so that "wilder" sources are
+ * greater than "specific" sources; for determining ordering,
+ * direction beats state beats size.
+ */
+
+static int
+icon_source_compare (gconstpointer ap, gconstpointer bp)
+{
+  const GtkIconSource *a = ap;
+  const GtkIconSource *b = bp;
+
+  if (!a->any_direction && b->any_direction)
+    return -1;
+  else if (a->any_direction && !b->any_direction)
+    return 1;
+  else if (!a->any_state && b->any_state)
+    return -1;
+  else if (a->any_state && !b->any_state)
+    return 1;
+  else if (!a->any_size && b->any_size)
+    return -1;
+  else if (a->any_size && !b->any_size)
+    return 1;
+  else
+    return 0;
+}
+
+void
+gtk_icon_set_add_source (GtkIconSet *icon_set,
+                         const GtkIconSource *source)
+{
+  g_return_if_fail (icon_set != NULL);
+  g_return_if_fail (source != NULL);
+
+  if (source->pixbuf == NULL &&
+      source->filename == NULL)
+    {
+      g_warning ("Useless GtkIconSource contains NULL filename and pixbuf");
+      return;
+    }
+  
+  icon_set->sources = g_slist_insert_sorted (icon_set->sources,
+                                             gtk_icon_source_copy (source),
+                                             icon_source_compare);
+}
+
+GtkIconSource *
+gtk_icon_source_copy (const GtkIconSource *source)
+{
+  GtkIconSource *copy;
+  
+  g_return_val_if_fail (source != NULL, NULL);
+
+  copy = g_new (GtkIconSource, 1);
+
+  *copy = *source;
+  
+  copy->filename = g_strdup (source->filename);
+  copy->size = g_strdup (source->size);
+  if (copy->pixbuf)
+    g_object_ref (G_OBJECT (copy->pixbuf));
+
+  return copy;
+}
+
+void
+gtk_icon_source_free (GtkIconSource *source)
+{
+  g_return_if_fail (source != NULL);
+
+  g_free ((char*) source->filename);
+  g_free ((char*) source->size);
+  if (source->pixbuf)
+    g_object_unref (G_OBJECT (source->pixbuf));
+
+  g_free (source);
+}
+
+void
+gtk_icon_set_clear (GtkIconSet *icon_set)
+{
+  GSList *tmp_list;
+
+  g_return_if_fail (icon_set != NULL);
+  
+  tmp_list = icon_set->sources;
+  while (tmp_list != NULL)
+    {
+      gtk_icon_source_free (tmp_list->data);
+
+      tmp_list = g_slist_next (tmp_list);
+    }
+
+  clear_cache (icon_set, TRUE);
+}
+
+/* Note that the logical maximum is 20 per GtkTextDirection, so we could
+ * eventually set this to >20 to never throw anything out.
+ */
+#define NUM_CACHED_ICONS 8
+
+typedef struct _CachedIcon CachedIcon;
+
+struct _CachedIcon
+{
+  /* These must all match to use the cached pixbuf.
+   * If any don't match, we must re-render the pixbuf.
+   */
+  GtkStyle *style;
+  GtkTextDirection direction;
+  GtkStateType state;
+  gchar *size;
+
+  GdkPixbuf *pixbuf;
+};
+
+static void
+ensure_cache_up_to_date (GtkIconSet *icon_set)
+{
+  if (icon_set->cache_serial != cache_serial)
+    clear_cache (icon_set, TRUE);
+}
+
+static void
+cached_icon_free (CachedIcon *icon)
+{
+  g_free (icon->size);
+  g_object_unref (G_OBJECT (icon->pixbuf));
+
+  g_free (icon);
+}
+
+static GdkPixbuf *
+find_in_cache (GtkIconSet      *icon_set,
+               GtkStyle        *style,
+               GtkTextDirection direction,
+               GtkStateType     state,
+               const gchar     *size)
+{
+  GSList *tmp_list;
+  GSList *prev;
+
+  ensure_cache_up_to_date (icon_set);
+  
+  prev = NULL;
+  tmp_list = icon_set->cache;
+  while (tmp_list != NULL)
+    {
+      CachedIcon *icon = tmp_list->data;
+
+      if (icon->style == style &&
+          icon->direction == direction &&
+          icon->state == state &&
+          strcmp (icon->size, size) == 0)
+        {
+          if (prev)
+            {
+              /* Move this icon to the front of the list. */
+              prev->next = tmp_list->next;
+              tmp_list->next = icon_set->cache;
+              icon_set->cache = tmp_list;
+            }
+          
+          return icon->pixbuf;
+        }
+          
+      prev = tmp_list;
+      tmp_list = g_slist_next (tmp_list);
+    }
+
+  return NULL;
+}
+
+static void
+add_to_cache (GtkIconSet      *icon_set,
+              GtkStyle        *style,
+              GtkTextDirection direction,
+              GtkStateType     state,
+              const gchar     *size,
+              GdkPixbuf       *pixbuf)
+{
+  CachedIcon *icon;
+
+  ensure_cache_up_to_date (icon_set);
+  
+  g_object_ref (G_OBJECT (pixbuf));
+
+  /* We have to ref the style, since if the style was finalized
+   * its address could be reused by another style, creating a
+   * really weird bug
+   */
+  
+  if (style)
+    g_object_ref (G_OBJECT (style));
+  
+
+  icon = g_new (CachedIcon, 1);
+  icon_set->cache = g_slist_prepend (icon_set->cache, icon);
+
+  icon->style = style;
+  icon->direction = direction;
+  icon->state = state;
+  icon->size = g_strdup (size);
+  icon->pixbuf = pixbuf;
+
+  if (icon->style)
+    attach_to_style (icon_set, icon->style);
+  
+  if (icon_set->cache_size >= NUM_CACHED_ICONS)
+    {
+      /* Remove oldest item in the cache */
+      
+      GSList *tmp_list;
+      
+      tmp_list = icon_set->cache;
+
+      /* Find next-to-last link */
+      g_assert (NUM_CACHED_ICONS > 2);
+      while (tmp_list->next->next)
+        tmp_list = tmp_list->next;
+
+      g_assert (tmp_list != NULL);
+      g_assert (tmp_list->next != NULL);
+      g_assert (tmp_list->next->next == NULL);
+
+      /* Free the last icon */
+      icon = tmp_list->next->data;
+
+      g_slist_free (tmp_list->next);
+      tmp_list->next = NULL;
+
+      cached_icon_free (icon);
+    }
+}
+
+static void
+clear_cache (GtkIconSet *icon_set,
+             gboolean    style_detach)
+{
+  GSList *tmp_list;
+  GtkStyle *last_style = NULL;
+
+  tmp_list = icon_set->cache;
+  while (tmp_list != NULL)
+    {
+      CachedIcon *icon = tmp_list->data;
+
+      if (style_detach)
+        {
+          /* simple optimization for the case where the cache
+           * contains contiguous icons from the same style.
+           * it's safe to call detach_from_style more than
+           * once on the same style though.
+           */
+          if (last_style != icon->style)
+            {
+              detach_from_style (icon_set, icon->style);
+              last_style = icon->style;
+            }
+        }
+      
+      cached_icon_free (icon);      
+      
+      tmp_list = g_slist_next (tmp_list);
+    }
+
+  g_slist_free (icon_set->cache);
+  icon_set->cache = NULL;
+  icon_set->cache_size = 0;
+}
+
+static GSList*
+copy_cache (GtkIconSet *icon_set,
+            GtkIconSet *copy_recipient)
+{
+  GSList *tmp_list;
+  GSList *copy = NULL;
+
+  ensure_cache_up_to_date (icon_set);
+  
+  tmp_list = icon_set->cache;
+  while (tmp_list != NULL)
+    {
+      CachedIcon *icon = tmp_list->data;
+      CachedIcon *icon_copy = g_new (CachedIcon, 1);
+
+      *icon_copy = *icon;
+
+      if (icon_copy->style)
+        attach_to_style (copy_recipient, icon_copy->style);
+        
+      g_object_ref (G_OBJECT (icon_copy->pixbuf));
+
+      icon_copy->size = g_strdup (icon->size);
+      
+      copy = g_slist_prepend (copy, icon_copy);      
+      
+      tmp_list = g_slist_next (tmp_list);
+    }
+
+  return g_slist_reverse (copy);
+}
+
+static void
+attach_to_style (GtkIconSet *icon_set,
+                 GtkStyle   *style)
+{
+  GHashTable *table;
+
+  table = g_object_get_qdata (G_OBJECT (style),
+                              g_quark_try_string ("gtk-style-icon-sets"));
+
+  if (table == NULL)
+    {
+      table = g_hash_table_new (NULL, NULL);
+      g_object_set_qdata_full (G_OBJECT (style),
+                               g_quark_from_static_string ("gtk-style-icon-sets"),
+                               table,
+                               style_dnotify);
+    }
+
+  g_hash_table_insert (table, icon_set, icon_set);
+}
+
+static void
+detach_from_style (GtkIconSet *icon_set,
+                   GtkStyle   *style)
+{
+  GHashTable *table;
+
+  table = g_object_get_qdata (G_OBJECT (style),
+                              g_quark_try_string ("gtk-style-icon-sets"));
+
+  if (table != NULL)
+    g_hash_table_remove (table, icon_set);
+}
+
+static void
+iconsets_foreach (gpointer key,
+                  gpointer value,
+                  gpointer user_data)
+{
+  GtkIconSet *icon_set = key;
+
+  /* We only need to remove cache entries for the given style;
+   * but that complicates things because in destroy notify
+   * we don't know which style got destroyed, and 95% of the
+   * time all cache entries will have the same style,
+   * so this is faster anyway.
+   */
+  
+  clear_cache (icon_set, FALSE);
+}
+
+static void
+style_dnotify (gpointer data)
+{
+  GHashTable *table = data;
+  
+  g_hash_table_foreach (table, iconsets_foreach, NULL);
+
+  g_hash_table_destroy (table);
+}
+
+/* This allows the icon set to detect that its cache is out of date. */
+void
+_gtk_icon_set_invalidate_caches (void)
+{
+  ++cache_serial;
+}
diff --git a/gtk/gtkiconfactory.h b/gtk/gtkiconfactory.h
new file mode 100644 (file)
index 0000000..357e37e
--- /dev/null
@@ -0,0 +1,159 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GTK_ICON_FACTORY_H__
+#define __GTK_ICON_FACTORY_H__
+
+#include <gdk/gdk.h>
+#include <gtk/gtkrc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _GtkIconFactoryClass GtkIconFactoryClass;
+
+#define GTK_TYPE_ICON_FACTORY              (gtk_icon_factory_get_type ())
+#define GTK_ICON_FACTORY(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_ICON_FACTORY, GtkIconFactory))
+#define GTK_ICON_FACTORY_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_ICON_FACTORY, GtkIconFactoryClass))
+#define GTK_IS_ICON_FACTORY(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GTK_TYPE_ICON_FACTORY))
+#define GTK_IS_ICON_FACTORY_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_ICON_FACTORY))
+#define GTK_ICON_FACTORY_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ICON_FACTORY, GtkIconFactoryClass))
+
+struct _GtkIconFactory
+{
+  GObject parent_instance;
+
+  GHashTable *icons;
+};
+
+struct _GtkIconFactoryClass
+{
+  GObjectClass parent_class;
+
+  
+};
+
+GType           gtk_icon_factory_get_type (void);
+GtkIconFactory* gtk_icon_factory_new      (void);
+void            gtk_icon_factory_add      (GtkIconFactory *factory,
+                                           const gchar    *stock_id,
+                                           GtkIconSet     *icon_set);
+GtkIconSet*     gtk_icon_factory_lookup   (GtkIconFactory *factory,
+                                           const gchar    *stock_id);
+
+/* Manage the default icon factory stack */
+
+void        gtk_icon_factory_add_default     (GtkIconFactory  *factory);
+void        gtk_icon_factory_remove_default  (GtkIconFactory  *factory);
+GtkIconSet* gtk_icon_factory_lookup_default  (const gchar     *stock_id);
+
+/* Get preferred real size from registered semantic size.  Note that
+ * themes SHOULD use this size, but they aren't required to; for size
+ * requests and such, you should get the actual pixbuf from the icon
+ * set and see what size was rendered.
+ *
+ * This function is intended for people who are scaling icons,
+ * rather than for people who are displaying already-scaled icons.
+ * That is, if you are displaying an icon, you should get the
+ * size from the rendered pixbuf, not from here.
+ */
+
+gboolean gtk_icon_size_lookup         (const gchar *alias,
+                                       gint        *width,
+                                       gint        *height);
+void     gtk_icon_size_register       (const gchar *alias,
+                                       gint         width,
+                                       gint         height);
+void     gtk_icon_size_register_alias (const gchar *alias,
+                                       const gchar *target);
+
+
+/* Standard sizes */
+
+#define GTK_ICON_SIZE_MENU          "gtk-menu"
+#define GTK_ICON_SIZE_SMALL_TOOLBAR "gtk-small-toolbar"
+#define GTK_ICON_SIZE_LARGE_TOOLBAR "gtk-large-toolbar"
+#define GTK_ICON_SIZE_BUTTON        "gtk-button"
+#define GTK_ICON_SIZE_DIALOG        "gtk-dialog"
+
+/* Icon sets */
+
+GtkIconSet* gtk_icon_set_new             (void);
+
+GtkIconSet* gtk_icon_set_ref             (GtkIconSet      *icon_set);
+void        gtk_icon_set_unref           (GtkIconSet      *icon_set);
+GtkIconSet* gtk_icon_set_copy            (GtkIconSet      *icon_set);
+
+/* Get one of the icon variants in the set, creating the variant if
+ * necessary.
+ */
+GdkPixbuf*  gtk_icon_set_render_icon     (GtkIconSet      *icon_set,
+                                          GtkStyle        *style,
+                                          GtkTextDirection direction,
+                                          GtkStateType     state,
+                                          const gchar     *size,
+                                          GtkWidget       *widget,
+                                          const char      *detail);
+
+
+void           gtk_icon_set_add_source   (GtkIconSet          *icon_set,
+                                          const GtkIconSource *source);
+
+/* INTERNAL */
+void _gtk_icon_set_invalidate_caches (void);
+
+struct _GtkIconSource
+{
+  /* Either filename or pixbuf can be NULL. If both are non-NULL,
+   * the pixbuf is assumed to be the already-loaded contents of the
+   * file.
+   */
+  gchar *filename;
+  GdkPixbuf *pixbuf;
+
+  GtkTextDirection direction;
+  GtkStateType state;
+  gchar *size;
+
+  /* If TRUE, then the parameter is wildcarded, and the above
+   * fields should be ignored. If FALSE, the parameter is
+   * specified, and the above fields should be valid.
+   */
+  guint any_direction : 1;
+  guint any_state : 1;
+  guint any_size : 1;
+};
+
+
+GtkIconSource* gtk_icon_source_copy    (const GtkIconSource *source);
+void           gtk_icon_source_free    (GtkIconSource       *source);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GTK_ICON_FACTORY_H__ */
index 01154d9293fa0ad7e1ce214734869dfc63f1a182..504b2a2e118bb93810428884da1687b69e9af2bb 100644 (file)
 
 #include "gtkcontainer.h"
 #include "gtkimage.h"
+#include "gtkiconfactory.h"
 
+static void gtk_image_class_init   (GtkImageClass  *klass);
+static void gtk_image_init         (GtkImage       *image);
+static gint gtk_image_expose       (GtkWidget      *widget,
+                                    GdkEventExpose *event);
+static void gtk_image_size_request (GtkWidget      *widget,
+                                    GtkRequisition *requisition);
+static void gtk_image_clear        (GtkImage       *image);
+static void gtk_image_update_size  (GtkImage       *image,
+                                    gint            image_width,
+                                    gint            image_height);
 
-static void gtk_image_class_init (GtkImageClass  *klass);
-static void gtk_image_init       (GtkImage       *image);
-static gint gtk_image_expose     (GtkWidget      *widget,
-                                 GdkEventExpose *event);
-
+static gpointer parent_class;
 
 GtkType
 gtk_image_get_type (void)
@@ -64,9 +71,12 @@ gtk_image_class_init (GtkImageClass *class)
 {
   GtkWidgetClass *widget_class;
 
+  parent_class = g_type_class_peek_parent (class);
+  
   widget_class = (GtkWidgetClass*) class;
 
   widget_class->expose_event = gtk_image_expose;
+  widget_class->size_request = gtk_image_size_request;
 }
 
 static void
@@ -74,49 +84,371 @@ gtk_image_init (GtkImage *image)
 {
   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
 
-  image->image = NULL;
-  image->mask = NULL;
+  image->storage_type = GTK_IMAGE_EMPTY;
 }
 
 GtkWidget*
-gtk_image_new (GdkImage  *val,
-              GdkBitmap *mask)
+gtk_image_new_from_pixmap (GdkPixmap *pixmap,
+                           GdkBitmap *mask)
 {
   GtkImage *image;
 
-  g_return_val_if_fail (val != NULL, NULL);
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_pixmap (image, pixmap, mask);
+
+  return GTK_WIDGET (image);
+}
+
+GtkWidget*
+gtk_image_new_from_image  (GdkImage  *gdk_image,
+                           GdkBitmap *mask)
+{
+  GtkImage *image;
 
   image = gtk_type_new (GTK_TYPE_IMAGE);
 
-  gtk_image_set (image, val, mask);
+  gtk_image_set_from_image (image, gdk_image, mask);
+
+  return GTK_WIDGET (image);
+}
+
+GtkWidget*
+gtk_image_new_from_file   (const gchar *filename)
+{
+  GtkImage *image;
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_file (image, filename);
+
+  return GTK_WIDGET (image);
+}
+
+GtkWidget*
+gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf)
+{
+  GtkImage *image;
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_pixbuf (image, pixbuf);
+
+  return GTK_WIDGET (image);  
+}
+
+GtkWidget*
+gtk_image_new_from_stock (const gchar    *stock_id,
+                          const gchar    *size)
+{
+  GtkImage *image;
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_stock (image, stock_id, size);
+
+  return GTK_WIDGET (image);
+}
+
+GtkWidget*
+gtk_image_new_from_icon_set (GtkIconSet     *icon_set,
+                             const gchar    *size)
+{
+  GtkImage *image;
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_icon_set (image, icon_set, size);
 
   return GTK_WIDGET (image);
 }
 
 void
-gtk_image_set (GtkImage  *image,
-              GdkImage  *val,
-              GdkBitmap *mask)
+gtk_image_set_from_pixmap (GtkImage  *image,
+                           GdkPixmap *pixmap,
+                           GdkBitmap *mask)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (pixmap == NULL ||
+                    GDK_IS_PIXMAP (pixmap));
+  g_return_if_fail (mask == NULL ||
+                    GDK_IS_PIXMAP (mask));
+  
+  if (pixmap)
+    g_object_ref (G_OBJECT (pixmap));
+
+  if (mask)
+    g_object_ref (G_OBJECT (mask));
+
+  gtk_image_clear (image);
+
+  if (pixmap)
+    {
+      int width;
+      int height;
+      
+      image->storage_type = GTK_IMAGE_PIXMAP;
+
+      image->data.pixmap.pixmap = pixmap;
+      image->data.pixmap.mask = mask;
+
+      gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
+
+      gtk_image_update_size (image, width, height);
+    }
+  else
+    {
+      /* Clean up the mask if pixmap was NULL */
+      if (mask)
+        g_object_unref (G_OBJECT (mask));
+    }
+}
+
+void
+gtk_image_set_from_image  (GtkImage  *image,
+                           GdkImage  *gdk_image,
+                           GdkBitmap *mask)
 {
-  g_return_if_fail (image != NULL);
   g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (gdk_image == NULL ||
+                    GDK_IS_IMAGE (gdk_image));
+  g_return_if_fail (mask == NULL ||
+                    GDK_IS_PIXMAP (mask));
+
+  
+  if (gdk_image)
+    g_object_ref (G_OBJECT (gdk_image));
+
+  if (mask)
+    g_object_ref (G_OBJECT (mask));
 
-  image->image = val;
-  image->mask = mask;
+  gtk_image_clear (image);
 
-  if (image->image)
+  if (gdk_image)
     {
-      GTK_WIDGET (image)->requisition.width = image->image->width + GTK_MISC (image)->xpad * 2;
-      GTK_WIDGET (image)->requisition.height = image->image->height + GTK_MISC (image)->ypad * 2;
+      image->storage_type = GTK_IMAGE_IMAGE;
+
+      image->data.image.image = gdk_image;
+      image->data.image.mask = mask;
+
+      gtk_image_update_size (image, gdk_image->width, gdk_image->height);
     }
   else
     {
-      GTK_WIDGET (image)->requisition.width = 0;
-      GTK_WIDGET (image)->requisition.height = 0;
+      /* Clean up the mask if gdk_image was NULL */
+      if (mask)
+        g_object_unref (G_OBJECT (mask));
     }
+}
 
-  if (GTK_WIDGET_VISIBLE (image))
-    gtk_widget_queue_resize (GTK_WIDGET (image));
+void
+gtk_image_set_from_file   (GtkImage    *image,
+                           const gchar *filename)
+{
+  GdkPixbuf *pixbuf;
+  
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (filename != NULL);
+  
+  gtk_image_clear (image);
+
+  if (filename == NULL)
+    return;
+  
+  pixbuf = gdk_pixbuf_new_from_file (filename);
+
+  if (pixbuf == NULL)
+    return;
+
+  gtk_image_set_from_pixbuf (image, pixbuf);
+
+  g_object_unref (G_OBJECT (pixbuf));
+}
+
+void
+gtk_image_set_from_pixbuf (GtkImage  *image,
+                           GdkPixbuf *pixbuf)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (pixbuf == NULL ||
+                    GDK_IS_PIXBUF (pixbuf));
+  
+  if (pixbuf)
+    g_object_ref (G_OBJECT (pixbuf));
+
+  gtk_image_clear (image);
+
+  if (pixbuf != NULL)
+    {
+      image->storage_type = GTK_IMAGE_PIXBUF;
+
+      image->data.pixbuf.pixbuf = pixbuf;
+
+      gtk_image_update_size (image,
+                             gdk_pixbuf_get_width (pixbuf),
+                             gdk_pixbuf_get_height (pixbuf));
+    }
+}
+
+void
+gtk_image_set_from_stock  (GtkImage       *image,
+                           const gchar    *stock_id,
+                           const gchar    *size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  
+  gtk_image_clear (image);
+
+  if (stock_id)
+    {      
+      image->storage_type = GTK_IMAGE_STOCK;
+      
+      image->data.stock.stock_id = g_strdup (stock_id);
+      image->data.stock.size = g_strdup (size);
+
+      /* Size is demand-computed in size request method
+       * if we're a stock image, since changing the
+       * style impacts the size request
+       */
+    }
+}
+
+void
+gtk_image_set_from_icon_set  (GtkImage       *image,
+                              GtkIconSet     *icon_set,
+                              const gchar    *size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+
+  if (icon_set)
+    gtk_icon_set_ref (icon_set);
+  
+  gtk_image_clear (image);
+
+  if (icon_set)
+    {      
+      image->storage_type = GTK_IMAGE_ICON_SET;
+      
+      image->data.icon_set.icon_set = icon_set;
+      image->data.icon_set.size = g_strdup (size);
+
+      /* Size is demand-computed in size request method
+       * if we're an icon set
+       */
+    }
+}
+
+GtkImageType
+gtk_image_get_storage_type (GtkImage *image)
+{
+  g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY);
+
+  return image->storage_type;
+}
+
+void
+gtk_image_get_pixmap (GtkImage   *image,
+                      GdkPixmap **pixmap,
+                      GdkBitmap **mask)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image)); 
+  g_return_if_fail (image->storage_type == GTK_IMAGE_PIXMAP ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+  
+  if (pixmap)
+    *pixmap = image->data.pixmap.pixmap;
+  
+  if (mask)
+    *mask = image->data.pixmap.mask;
+}
+
+void
+gtk_image_get_image  (GtkImage   *image,
+                      GdkImage  **gdk_image,
+                      GdkBitmap **mask)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (image->storage_type == GTK_IMAGE_IMAGE ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+
+  if (gdk_image)
+    *gdk_image = image->data.image.image;
+  
+  if (mask)
+    *mask = image->data.image.mask;
+}
+
+GdkPixbuf*
+gtk_image_get_pixbuf (GtkImage *image)
+{
+  g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
+  g_return_val_if_fail (image->storage_type == GTK_IMAGE_PIXBUF ||
+                        image->storage_type == GTK_IMAGE_EMPTY, NULL);
+
+  if (image->storage_type == GTK_IMAGE_EMPTY)
+    image->data.pixbuf.pixbuf = NULL;
+  
+  return image->data.pixbuf.pixbuf;
+}
+
+void
+gtk_image_get_stock  (GtkImage        *image,
+                      gchar          **stock_id,
+                      gchar          **size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (image->storage_type == GTK_IMAGE_STOCK ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+
+  if (image->storage_type == GTK_IMAGE_EMPTY)
+    image->data.stock.stock_id = NULL;
+  
+  if (stock_id)
+    *stock_id = g_strdup (image->data.stock.stock_id);
+
+  if (size)
+    *size = image->data.stock.size;
+}
+
+void
+gtk_image_get_icon_set  (GtkImage        *image,
+                         GtkIconSet     **icon_set,
+                         gchar          **size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_SET ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+      
+  if (icon_set)    
+    *icon_set = image->data.icon_set.icon_set;
+
+  if (size)
+    *size = g_strdup (image->data.icon_set.size);
+}
+
+GtkWidget*
+gtk_image_new (GdkImage  *val,
+              GdkBitmap *mask)
+{
+  GtkImage *image;
+
+  g_return_val_if_fail (val != NULL, NULL);
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set (image, val, mask);
+
+  return GTK_WIDGET (image);
+}
+
+void
+gtk_image_set (GtkImage  *image,
+              GdkImage  *val,
+              GdkBitmap *mask)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+
+  gtk_image_set_from_image (image, val, mask);
 }
 
 void
@@ -124,13 +456,9 @@ gtk_image_get (GtkImage   *image,
               GdkImage  **val,
               GdkBitmap **mask)
 {
-  g_return_if_fail (image != NULL);
   g_return_if_fail (GTK_IS_IMAGE (image));
 
-  if (val)
-    *val = image->image;
-  if (mask)
-    *mask = image->mask;
+  gtk_image_get_image (image, val, mask);
 }
 
 
@@ -141,13 +469,16 @@ gtk_image_expose (GtkWidget      *widget,
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
-
-  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
+  
+  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
+      GTK_IMAGE (widget)->storage_type != GTK_IMAGE_EMPTY)
     {
       GtkImage *image;
       GtkMisc *misc;
       GdkRectangle area, image_bound, intersection;
       gint x, y;
+      GdkBitmap *mask = NULL;
+      GdkPixbuf *stock_pixbuf = NULL;
       
       image = GTK_IMAGE (widget);
       misc = GTK_MISC (widget);
@@ -161,35 +492,265 @@ gtk_image_expose (GtkWidget      *widget,
            - (widget->requisition.height - misc->ypad * 2)) *
           misc->yalign) + 0.5;
 
-      if (image->mask)
+      image_bound.x = x;
+      image_bound.y = y;      
+
+      switch (image->storage_type)
+        {
+        case GTK_IMAGE_PIXMAP:
+          mask = image->data.pixmap.mask;
+          gdk_drawable_get_size (image->data.pixmap.pixmap,
+                                 &image_bound.width,
+                                 &image_bound.height);
+          break;
+
+        case GTK_IMAGE_IMAGE:
+          mask = image->data.image.mask;
+          image_bound.width = image->data.image.image->width;
+          image_bound.height = image->data.image.image->height;
+          break;
+
+        case GTK_IMAGE_PIXBUF:
+          image_bound.width = gdk_pixbuf_get_width (image->data.pixbuf.pixbuf);
+          image_bound.height = gdk_pixbuf_get_height (image->data.pixbuf.pixbuf);
+          break;
+
+        case GTK_IMAGE_STOCK:
+          stock_pixbuf = gtk_widget_render_stock_icon (widget,
+                                                       image->data.stock.stock_id,
+                                                       image->data.stock.size,
+                                                       NULL);
+
+          if (stock_pixbuf)
+            {
+              image_bound.width = gdk_pixbuf_get_width (stock_pixbuf);
+              image_bound.height = gdk_pixbuf_get_height (stock_pixbuf);
+            }
+          break;
+
+        case GTK_IMAGE_ICON_SET:
+          stock_pixbuf =
+            gtk_icon_set_render_icon (image->data.icon_set.icon_set,
+                                      widget->style,
+                                      gtk_widget_get_direction (widget),
+                                      GTK_WIDGET_STATE (widget),
+                                      image->data.icon_set.size,
+                                      widget,
+                                      NULL);
+
+          if (stock_pixbuf)
+            {
+              image_bound.width = gdk_pixbuf_get_width (stock_pixbuf);
+              image_bound.height = gdk_pixbuf_get_height (stock_pixbuf);
+            }
+          break;
+          
+        default:
+          break;
+        }
+
+      if (mask)
        {
-         gdk_gc_set_clip_mask (widget->style->black_gc, image->mask);
+         gdk_gc_set_clip_mask (widget->style->black_gc, mask);
          gdk_gc_set_clip_origin (widget->style->black_gc, x, y);
        }
 
-      image_bound.x = x;
-      image_bound.y = y;      
-      image_bound.width = image->image->width;
-      image_bound.height = image->image->height;      
-
       area = event->area;
       
-      if(gdk_rectangle_intersect(&image_bound, &area, &intersection))
+      if (gdk_rectangle_intersect (&image_bound, &area, &intersection))
         {
-          gdk_draw_image (widget->window,
-                          widget->style->black_gc,
-                          image->image,
-                          image_bound.x - x, image_bound.y - y,
-                          image_bound.x, image_bound.y,
-                          image_bound.width, image_bound.height);
+
+          switch (image->storage_type)
+            {
+            case GTK_IMAGE_PIXMAP:
+              gdk_draw_drawable (widget->window,
+                                 widget->style->black_gc,
+                                 image->data.pixmap.pixmap,
+                                 image_bound.x - x, image_bound.y - y,
+                                 image_bound.x, image_bound.y,
+                                 image_bound.width, image_bound.height);
+              break;
+              
+            case GTK_IMAGE_IMAGE:
+              gdk_draw_image (widget->window,
+                              widget->style->black_gc,
+                              image->data.image.image,
+                              image_bound.x - x, image_bound.y - y,
+                              image_bound.x, image_bound.y,
+                              image_bound.width, image_bound.height);
+              break;
+
+            case GTK_IMAGE_PIXBUF:
+              gdk_pixbuf_render_to_drawable_alpha (image->data.pixbuf.pixbuf,
+                                                   widget->window,
+                                                   image_bound.x - x, image_bound.y - y,
+                                                   image_bound.x, image_bound.y,
+                                                   image_bound.width, image_bound.height,
+                                                   GDK_PIXBUF_ALPHA_FULL,
+                                                   128,
+                                                   GDK_RGB_DITHER_NORMAL,
+                                                   0, 0);
+              break;
+
+            case GTK_IMAGE_STOCK: /* fall thru */
+            case GTK_IMAGE_ICON_SET:
+              if (stock_pixbuf)
+                {
+                  gdk_pixbuf_render_to_drawable_alpha (stock_pixbuf,
+                                                       widget->window,
+                                                       image_bound.x - x, image_bound.y - y,
+                                                       image_bound.x, image_bound.y,
+                                                       image_bound.width, image_bound.height,
+                                                       GDK_PIXBUF_ALPHA_FULL,
+                                                       128,
+                                                       GDK_RGB_DITHER_NORMAL,
+                                                       0, 0);
+                  
+                  g_object_unref (G_OBJECT (stock_pixbuf));
+                }
+              break;
+
+            default:
+              break;
+            }
+        } /* if rectangle intersects */      
+      if (mask)
+        {
+          gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
+          gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
         }
+    } /* if widget is drawable */
+
+  return FALSE;
+}
+
+static void
+gtk_image_clear (GtkImage *image)
+{
+  switch (image->storage_type)
+    {
+    case GTK_IMAGE_PIXMAP:
+
+      if (image->data.pixmap.pixmap)
+        g_object_unref (G_OBJECT (image->data.pixmap.pixmap));
+
+      if (image->data.pixmap.mask)
+        g_object_unref (G_OBJECT (image->data.pixmap.mask));
+
+      image->data.pixmap.pixmap = NULL;
+      image->data.pixmap.mask = NULL;
+
+      break;
+
+    case GTK_IMAGE_IMAGE:
+
+      if (image->data.image.image)
+        g_object_unref (G_OBJECT (image->data.image.image));
+
+      if (image->data.image.mask)
+        g_object_unref (G_OBJECT (image->data.image.mask));
+
+      image->data.image.image = NULL;
+      image->data.image.mask = NULL;
+
+      break;
+
+    case GTK_IMAGE_PIXBUF:
+
+      if (image->data.pixbuf.pixbuf)
+        g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf));
+
+      image->data.pixbuf.pixbuf = NULL;
+
+      break;
+
+    case GTK_IMAGE_STOCK:
+
+      g_free (image->data.stock.size);
+      g_free (image->data.stock.stock_id);
+
+      image->data.stock.stock_id = NULL;
+      image->data.stock.size = NULL;
+      
+      break;
+
+    case GTK_IMAGE_ICON_SET:
+      if (image->data.icon_set.icon_set)
+        gtk_icon_set_unref (image->data.icon_set.icon_set);
+
+      g_free (image->data.icon_set.size);
+
+      image->data.icon_set.size = NULL;
+      image->data.icon_set.icon_set = NULL;
+      
+      break;
+      
+    case GTK_IMAGE_EMPTY:
+    default:
+      break;
       
-      if (image->mask)
-       {
-         gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
-         gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
-       }
     }
 
-  return FALSE;
+  image->storage_type = GTK_IMAGE_EMPTY;
+
+  GTK_WIDGET (image)->requisition.width = 0;
+  GTK_WIDGET (image)->requisition.height = 0;
+  
+  if (GTK_WIDGET_VISIBLE (image))
+    gtk_widget_queue_resize (GTK_WIDGET (image));
+}
+
+static void
+gtk_image_size_request (GtkWidget      *widget,
+                        GtkRequisition *requisition)
+{
+  GtkImage *image;
+  GdkPixbuf *pixbuf = NULL;
+  
+  image = GTK_IMAGE (widget);
+
+  switch (image->storage_type)
+    {
+    case GTK_IMAGE_STOCK:
+      pixbuf = gtk_widget_render_stock_icon (GTK_WIDGET (image),
+                                             image->data.stock.stock_id,
+                                             image->data.stock.size,
+                                             NULL);
+      break;
+
+    case GTK_IMAGE_ICON_SET:
+      pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
+                                         widget->style,
+                                         gtk_widget_get_direction (widget),
+                                         GTK_WIDGET_STATE (widget),
+                                         image->data.icon_set.size,
+                                         widget,
+                                         NULL);
+      break;
+      
+    default:
+      break;
+    }
+
+  if (pixbuf)
+    {
+      gtk_image_update_size (image,
+                             gdk_pixbuf_get_width (pixbuf),
+                             gdk_pixbuf_get_height (pixbuf));
+      g_object_unref (G_OBJECT (pixbuf));
+    }
+
+  /* Chain up to default that simply reads current requisition */
+  GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
 }
+
+static void
+gtk_image_update_size (GtkImage *image,
+                       gint      image_width,
+                       gint      image_height)
+{
+  GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
+  GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
+}
+
+
index 147a606463365955bc33494b61d1dbf2aec3d6bd..266d032e67be6e8118cc34b09b6ade6bcd3ef38c 100644 (file)
@@ -36,7 +36,6 @@
 extern "C" {
 #endif /* __cplusplus */
 
-
 #define GTK_TYPE_IMAGE                  (gtk_image_get_type ())
 #define GTK_IMAGE(obj)                  (GTK_CHECK_CAST ((obj), GTK_TYPE_IMAGE, GtkImage))
 #define GTK_IMAGE_CLASS(klass)          (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_IMAGE, GtkImageClass))
@@ -48,21 +47,122 @@ extern "C" {
 typedef struct _GtkImage       GtkImage;
 typedef struct _GtkImageClass  GtkImageClass;
 
-struct _GtkImage
+typedef struct _GtkImagePixmapData  GtkImagePixmapData;
+typedef struct _GtkImageImageData   GtkImageImageData;
+typedef struct _GtkImagePixbufData  GtkImagePixbufData;
+typedef struct _GtkImageStockData   GtkImageStockData;
+typedef struct _GtkImageIconSetData GtkImageIconSetData;
+
+struct _GtkImagePixmapData
 {
-  GtkMisc misc;
+  GdkPixmap *pixmap;
+  GdkBitmap *mask;
+};
 
+struct _GtkImageImageData
+{
   GdkImage *image;
   GdkBitmap *mask;
 };
 
+struct _GtkImagePixbufData
+{
+  GdkPixbuf *pixbuf;
+};
+
+struct _GtkImageStockData
+{
+  gchar *stock_id;
+  gchar *size;
+};
+
+struct _GtkImageIconSetData
+{
+  GtkIconSet *icon_set;
+  gchar      *size;
+};
+
+typedef enum
+{
+  GTK_IMAGE_EMPTY,
+  GTK_IMAGE_PIXMAP,
+  GTK_IMAGE_IMAGE,
+  GTK_IMAGE_PIXBUF,
+  GTK_IMAGE_STOCK,
+  GTK_IMAGE_ICON_SET
+} GtkImageType;
+
+struct _GtkImage
+{
+  GtkMisc misc;
+
+  GtkImageType storage_type;
+  
+  union
+  {
+    GtkImagePixmapData pixmap;
+    GtkImageImageData image;
+    GtkImagePixbufData pixbuf;
+    GtkImageStockData stock;
+    GtkImageIconSetData icon_set;
+  } data;
+};
+
 struct _GtkImageClass
 {
   GtkMiscClass parent_class;
 };
 
-
 GtkType    gtk_image_get_type (void) G_GNUC_CONST;
+
+GtkWidget* gtk_image_new_from_pixmap   (GdkPixmap       *pixmap,
+                                        GdkBitmap       *mask);
+GtkWidget* gtk_image_new_from_image    (GdkImage        *image,
+                                        GdkBitmap       *mask);
+GtkWidget* gtk_image_new_from_file     (const gchar     *filename);
+GtkWidget* gtk_image_new_from_pixbuf   (GdkPixbuf       *pixbuf);
+GtkWidget* gtk_image_new_from_stock    (const gchar     *stock_id,
+                                        const gchar     *size);
+GtkWidget* gtk_image_new_from_icon_set (GtkIconSet      *icon_set,
+                                        const gchar     *size);
+
+void gtk_image_set_from_pixmap   (GtkImage        *image,
+                                  GdkPixmap       *pixmap,
+                                  GdkBitmap       *mask);
+void gtk_image_set_from_image    (GtkImage        *image,
+                                  GdkImage        *gdk_image,
+                                  GdkBitmap       *mask);
+void gtk_image_set_from_file     (GtkImage        *image,
+                                  const gchar     *filename);
+void gtk_image_set_from_pixbuf   (GtkImage        *image,
+                                  GdkPixbuf       *pixbuf);
+void gtk_image_set_from_stock    (GtkImage        *image,
+                                  const gchar     *stock_id,
+                                  const gchar     *size);
+void gtk_image_set_from_icon_set (GtkImage        *image,
+                                  GtkIconSet      *icon_set,
+                                  const gchar     *size);
+
+GtkImageType gtk_image_get_storage_type (GtkImage   *image);
+
+void       gtk_image_get_pixmap   (GtkImage         *image,
+                                   GdkPixmap       **pixmap,
+                                   GdkBitmap       **mask);
+void       gtk_image_get_image    (GtkImage         *image,
+                                   GdkImage        **gdk_image,
+                                   GdkBitmap       **mask);
+GdkPixbuf* gtk_image_get_pixbuf   (GtkImage         *image);
+void       gtk_image_get_stock    (GtkImage         *image,
+                                   gchar           **stock_id,
+                                   gchar           **size);
+void       gtk_image_get_icon_set (GtkImage         *image,
+                                   GtkIconSet      **icon_set,
+                                   gchar           **size);
+
+
+
+/* These three are deprecated */
+
 GtkWidget* gtk_image_new      (GdkImage   *val,
                               GdkBitmap  *mask);
 void       gtk_image_set      (GtkImage   *image,
index 495fbbd411f4cb3469f036fe54736cf1a0a098f8..324e8d3a5442821eda5510aa388bac814972645d 100644 (file)
@@ -60,6 +60,7 @@
 #include "gtkbindings.h"
 #include "gtkthemes.h"
 #include "gtkintl.h"
+#include "gtkiconfactory.h"
 
 typedef struct _GtkRcSet    GtkRcSet;
 typedef struct _GtkRcNode   GtkRcNode;
@@ -127,6 +128,9 @@ static void        gtk_rc_parse_pixmap_path_string   (gchar           *pix_path)
 static guint       gtk_rc_parse_module_path          (GScanner        *scanner);
 static void        gtk_rc_parse_module_path_string   (gchar           *mod_path);
 static guint       gtk_rc_parse_path_pattern         (GScanner        *scanner);
+static guint       gtk_rc_parse_stock                (GScanner        *scanner,
+                                                      GtkRcStyle      *rc_style,
+                                                      GtkIconFactory  *factory);
 static void        gtk_rc_clear_hash_node            (gpointer         key,
                                                       gpointer         data,
                                                       gpointer         user_data);
@@ -220,6 +224,9 @@ static const struct
   { "highest", GTK_RC_TOKEN_HIGHEST },
   { "engine", GTK_RC_TOKEN_ENGINE },
   { "module_path", GTK_RC_TOKEN_MODULE_PATH },
+  { "stock", GTK_RC_TOKEN_STOCK },
+  { "LTR", GTK_RC_TOKEN_LTR },
+  { "RTL", GTK_RC_TOKEN_RTL }
 };
 
 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
@@ -857,8 +864,19 @@ gtk_rc_style_finalize (GObject *object)
 
       tmp_list1 = tmp_list1->next;
     }
+
   g_slist_free (rc_style->rc_style_lists);
 
+  tmp_list1 = rc_style->icon_factories;
+  while (tmp_list1)
+    {
+      g_object_unref (G_OBJECT (tmp_list1->data));
+
+      tmp_list1 = tmp_list1->next;
+    }
+
+  g_slist_free (rc_style->icon_factories);
+  
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -887,7 +905,7 @@ gtk_rc_style_copy (GtkRcStyle *orig)
 {
   GtkRcStyle *style;
 
-  g_return_if_fail (GTK_IS_RC_STYLE (orig));
+  g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
   
   style = GTK_RC_STYLE_GET_CLASS (orig)->clone (orig);
   GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
@@ -1363,10 +1381,11 @@ gtk_rc_style_to_style (GtkRcStyle *rc_style)
   style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
 
   style->rc_style = rc_style;
+
   gtk_rc_style_ref (rc_style);
   
-  GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
-  
+  GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);  
+
   return style;
 }
 
@@ -1402,13 +1421,13 @@ gtk_rc_init_style (GSList *rc_styles)
       while (tmp_styles)
        {
          GtkRcStyle *rc_style = tmp_styles->data;
-
+          
          if (G_OBJECT_TYPE (rc_style) != rc_style_type)
            {
              base_style = rc_style;
              break;
            }
-
+          
          tmp_styles = tmp_styles->next;
        }
       
@@ -1419,13 +1438,31 @@ gtk_rc_init_style (GSList *rc_styles)
       while (tmp_styles)
        {
          GtkRcStyle *rc_style = tmp_styles->data;
-         
-         proto_style_class->merge (proto_style, rc_style);
-         
+          GSList *factories;
+          
+         proto_style_class->merge (proto_style, rc_style);       
+          
          /* Point from each rc_style to the list of styles */
          if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
            rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
-         
+
+          factories = g_slist_copy (rc_style->icon_factories);
+          if (factories)
+            {
+              GSList *iter;
+              
+              iter = factories;
+              while (iter != NULL)
+                {
+                  g_object_ref (G_OBJECT (iter->data));
+                  iter = g_slist_next (iter);
+                }
+
+              proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
+                                                            factories);
+
+            }
+          
          tmp_styles = tmp_styles->next;
        }
 
@@ -1508,6 +1545,7 @@ gtk_rc_parse_style (GScanner *scanner)
   guint token;
   gint insert;
   gint i;
+  GtkIconFactory *our_factory = NULL;
   
   token = g_scanner_get_next_token (scanner);
   if (token != GTK_RC_TOKEN_STYLE)
@@ -1519,6 +1557,12 @@ gtk_rc_parse_style (GScanner *scanner)
   
   insert = FALSE;
   rc_style = gtk_rc_style_find (scanner->value.v_string);
+
+  /* If there's a list, its first member is always the factory belonging
+   * to this RcStyle
+   */
+  if (rc_style && rc_style->icon_factories)
+    our_factory = rc_style->icon_factories->data;
   
   if (!rc_style)
     {
@@ -1532,7 +1576,7 @@ gtk_rc_parse_style (GScanner *scanner)
       for (i = 0; i < 5; i++)
        rc_style->color_flags[i] = 0;
     }
-  
+
   token = g_scanner_peek_next_token (scanner);
   if (token == G_TOKEN_EQUAL_SIGN)
     {
@@ -1550,6 +1594,8 @@ gtk_rc_parse_style (GScanner *scanner)
       parent_style = gtk_rc_style_find (scanner->value.v_string);
       if (parent_style)
        {
+          GSList *factories;
+          
          for (i = 0; i < 5; i++)
            {
              rc_style->color_flags[i] = parent_style->color_flags[i];
@@ -1575,6 +1621,35 @@ gtk_rc_parse_style (GScanner *scanner)
                g_free (rc_style->bg_pixmap_name[i]);
              rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
            }
+          
+          /* Append parent's factories, adding a ref to them */
+          if (parent_style->icon_factories != NULL)
+            {
+              /* Add a factory for ourselves if we have none,
+               * in case we end up defining more stock icons.
+               * I see no real way around this; we need to maintain
+               * the invariant that the first factory in the list
+               * is always our_factory, the one belonging to us,
+               * and if we put parent factories in the list we can't
+               * do that if the style is reopened.
+               */
+              if (our_factory == NULL)
+                {
+                  our_factory = gtk_icon_factory_new ();
+                  rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
+                                                              our_factory);
+                }
+              
+              rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
+                                                         g_slist_copy (parent_style->icon_factories));
+              
+              factories = parent_style->icon_factories;
+              while (factories != NULL)
+                {
+                  g_object_ref (G_OBJECT (factories->data));
+                  factories = factories->next;
+                }
+            }
        }
     }
   
@@ -1625,6 +1700,15 @@ gtk_rc_parse_style (GScanner *scanner)
        case GTK_RC_TOKEN_ENGINE:
          token = gtk_rc_parse_engine (scanner, &rc_style);
          break;
+        case GTK_RC_TOKEN_STOCK:
+          if (our_factory == NULL)
+            {
+              our_factory = gtk_icon_factory_new ();
+              rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
+                                                          our_factory);
+            }
+          token = gtk_rc_parse_stock (scanner, rc_style, our_factory);
+          break;
        default:
          g_scanner_get_next_token (scanner);
          token = G_TOKEN_RIGHT_CURLY;
@@ -2502,6 +2586,270 @@ gtk_rc_parse_path_pattern (GScanner   *scanner)
   return G_TOKEN_NONE;
 }
 
+static guint
+gtk_rc_parse_stock_id (GScanner         *scanner,
+                       gchar    **stock_id)
+{
+  guint token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_LEFT_BRACE)
+    return G_TOKEN_LEFT_BRACE;
+
+  token = g_scanner_get_next_token (scanner);
+  
+  if (token != G_TOKEN_STRING)
+    return G_TOKEN_STRING;
+  
+  *stock_id = g_strdup (scanner->value.v_string);
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_RIGHT_BRACE)
+    {
+      g_free (*stock_id);
+      return G_TOKEN_RIGHT_BRACE;
+    }
+  
+  return G_TOKEN_NONE;
+}
+
+static void
+cleanup_source (GtkIconSource *source)
+{
+  g_free (source->filename);
+  g_free (source->size);
+}
+
+static guint
+gtk_rc_parse_icon_source (GScanner      *scanner,
+                          GtkIconSet     *icon_set)
+{
+  guint token;
+  GtkIconSource source = { NULL, NULL,
+                           0, 0, 0,
+                           TRUE, TRUE, TRUE };
+  
+  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_STRING)
+    return G_TOKEN_STRING;
+  
+  source.filename = g_strdup (scanner->value.v_string);
+  
+  token = g_scanner_get_next_token (scanner);
+
+  if (token == G_TOKEN_RIGHT_CURLY)
+    {
+      gtk_icon_set_add_source (icon_set, &source);
+      cleanup_source (&source);
+      return G_TOKEN_NONE;
+    }  
+  else if (token != G_TOKEN_COMMA)
+    {
+      cleanup_source (&source);
+      return G_TOKEN_COMMA;
+    }
+
+  /* Get the direction */
+  
+  token = g_scanner_get_next_token (scanner);
+
+  switch (token)
+    {
+    case GTK_RC_TOKEN_RTL:
+      source.any_direction = FALSE;
+      source.direction = GTK_TEXT_DIR_RTL;
+      break;
+
+    case GTK_RC_TOKEN_LTR:
+      source.any_direction = FALSE;
+      source.direction = GTK_TEXT_DIR_LTR;
+      break;
+      
+    case '*':
+      break;
+      
+    default:
+      cleanup_source (&source);
+      return GTK_RC_TOKEN_RTL;
+      break;
+    }
+
+  token = g_scanner_get_next_token (scanner);
+
+  if (token == G_TOKEN_RIGHT_CURLY)
+    {
+      gtk_icon_set_add_source (icon_set, &source);
+      cleanup_source (&source);
+      return G_TOKEN_NONE;
+    }  
+  else if (token != G_TOKEN_COMMA)
+    {
+      cleanup_source (&source);
+      return G_TOKEN_COMMA;
+    }
+
+  /* Get the state */
+  
+  token = g_scanner_get_next_token (scanner);
+  
+  switch (token)
+    {
+    case GTK_RC_TOKEN_NORMAL:
+      source.any_state = FALSE;
+      source.state = GTK_STATE_NORMAL;
+      break;
+
+    case GTK_RC_TOKEN_PRELIGHT:
+      source.any_state = FALSE;
+      source.state = GTK_STATE_PRELIGHT;
+      break;
+      
+
+    case GTK_RC_TOKEN_INSENSITIVE:
+      source.any_state = FALSE;
+      source.state = GTK_STATE_INSENSITIVE;
+      break;
+
+    case GTK_RC_TOKEN_ACTIVE:
+      source.any_state = FALSE;
+      source.state = GTK_STATE_ACTIVE;
+      break;
+
+    case GTK_RC_TOKEN_SELECTED:
+      source.any_state = FALSE;
+      source.state = GTK_STATE_SELECTED;
+      break;
+
+    case '*':
+      break;
+      
+    default:
+      cleanup_source (&source);
+      return GTK_RC_TOKEN_PRELIGHT;
+      break;
+    }  
+
+  token = g_scanner_get_next_token (scanner);
+
+  if (token == G_TOKEN_RIGHT_CURLY)
+    {
+      gtk_icon_set_add_source (icon_set, &source);
+      cleanup_source (&source);
+      return G_TOKEN_NONE;
+    }
+  else if (token != G_TOKEN_COMMA)
+    {
+      cleanup_source (&source);
+      return G_TOKEN_COMMA;
+    }
+  
+  /* Get the size */
+  
+  token = g_scanner_get_next_token (scanner);
+
+  if (token != '*')
+    {
+      if (token != G_TOKEN_STRING)
+        {
+          cleanup_source (&source);
+          return G_TOKEN_STRING;
+        }
+      
+      source.size = g_strdup (scanner->value.v_string);
+      source.any_size = FALSE;
+    }
+
+  /* Check the close brace */
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_RIGHT_CURLY)
+    {
+      cleanup_source (&source);
+      return G_TOKEN_RIGHT_CURLY;
+    }
+
+  gtk_icon_set_add_source (icon_set, &source);
+
+  cleanup_source (&source);
+  
+  return G_TOKEN_NONE;
+}
+
+static guint
+gtk_rc_parse_stock (GScanner       *scanner,
+                    GtkRcStyle     *rc_style,
+                    GtkIconFactory *factory)
+{
+  GtkIconSet *icon_set = NULL;
+  gchar *stock_id = NULL;
+  guint token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_STOCK)
+    return GTK_RC_TOKEN_STOCK;
+  
+  token = gtk_rc_parse_stock_id (scanner, &stock_id);
+  if (token != G_TOKEN_NONE)
+    return token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_EQUAL_SIGN)
+    {
+      g_free (stock_id);
+      return G_TOKEN_EQUAL_SIGN;
+    }
+
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_LEFT_CURLY)
+    {
+      g_free (stock_id);
+      return G_TOKEN_LEFT_CURLY;
+    }
+
+  token = g_scanner_peek_next_token (scanner);
+  while (token != G_TOKEN_RIGHT_CURLY)
+    {
+      if (icon_set == NULL)
+        icon_set = gtk_icon_set_new ();
+      
+      token = gtk_rc_parse_icon_source (scanner, icon_set);
+      if (token != G_TOKEN_NONE)
+        {
+          g_free (stock_id);
+          gtk_icon_set_unref (icon_set);
+          return token;
+        }
+
+      token = g_scanner_get_next_token (scanner);
+      
+      if (token != G_TOKEN_COMMA &&
+          token != G_TOKEN_RIGHT_CURLY)
+        {
+          g_free (stock_id);
+          gtk_icon_set_unref (icon_set);
+          return G_TOKEN_RIGHT_CURLY;
+        }
+    }
+
+  if (icon_set)
+    {
+      gtk_icon_factory_add (factory,
+                            stock_id,
+                            icon_set);
+      
+      gtk_icon_set_unref (icon_set);
+    }
+  
+  g_free (stock_id);
+
+  return G_TOKEN_NONE;
+}
+
 /*
 typedef  GdkPixmap * (*GtkImageLoader) (GdkWindow   *window,
                                         GdkColormap *colormap,
index a1a98f227807a21de7637287b3a31e7e33cf9a60..0b37039311f8129bf5b099c94969f076d74de0a9 100644 (file)
@@ -35,6 +35,9 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/* Forward declaration */
+typedef struct _GtkIconFactory GtkIconFactory;
+
 #define GTK_TYPE_RC_STYLE              (gtk_rc_style_get_type ())
 #define GTK_RC_STYLE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_RC_STYLE, GtkRcStyle))
 #define GTK_RC_STYLE_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_RC_STYLE, GtkRcStyleClass))
@@ -70,11 +73,13 @@ struct _GtkRcStyle
 
   gint xthickness;
   gint ythickness;
-
+  
   /*< private >*/
   
   /* list of RC style lists including this RC style */
   GSList *rc_style_lists;
+
+  GSList *icon_factories;
 };
 
 struct _GtkRcStyleClass
@@ -177,6 +182,9 @@ typedef enum {
   GTK_RC_TOKEN_HIGHEST,
   GTK_RC_TOKEN_ENGINE,
   GTK_RC_TOKEN_MODULE_PATH,
+  GTK_RC_TOKEN_STOCK,
+  GTK_RC_TOKEN_LTR,
+  GTK_RC_TOKEN_RTL,
   GTK_RC_TOKEN_LAST
 } GtkRcTokenType;
 
diff --git a/gtk/gtkstock.c b/gtk/gtkstock.c
new file mode 100644 (file)
index 0000000..ecb3079
--- /dev/null
@@ -0,0 +1,198 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gtkstock.h"
+#include "gtkintl.h"
+#include <gdk/gdkkeysyms.h>
+
+static GHashTable *stock_hash = NULL;
+static void init_stock_hash (void);
+
+static void
+real_add (const GtkStockItem *items,
+          guint               n_items,
+          gboolean            copy)
+{
+  int i;
+
+  init_stock_hash ();
+
+  if (n_items == 0)
+    return;
+
+  i = 0;
+  while (i < n_items)
+    {
+      gpointer old_key, old_value;
+      const GtkStockItem *item = &items[i];
+      if (copy)
+        item = gtk_stock_item_copy (item);
+
+      if (g_hash_table_lookup_extended (stock_hash, item->stock_id,
+                                        &old_key, &old_value))
+        {
+          g_hash_table_remove (stock_hash, old_key);
+          gtk_stock_item_free (old_value);
+        }
+      
+      g_hash_table_insert (stock_hash,
+                           (gchar*)item->stock_id, (GtkStockItem*)item);
+
+      ++i;
+    }
+}
+
+void
+gtk_stock_add (const GtkStockItem *items,
+               guint               n_items)
+{
+  g_return_if_fail (items != NULL);
+
+  real_add (items, n_items, TRUE);
+}
+
+void
+gtk_stock_add_static (const GtkStockItem *items,
+                      guint               n_items)
+{
+  g_return_if_fail (items != NULL);
+
+  real_add (items, n_items, FALSE);
+}
+
+gboolean
+gtk_stock_lookup (const gchar  *stock_id,
+                  GtkStockItem *item)
+{
+  const GtkStockItem *found;
+
+  g_return_val_if_fail (stock_id != NULL, FALSE);
+  g_return_val_if_fail (item != NULL, FALSE);
+
+  init_stock_hash ();
+
+  found = g_hash_table_lookup (stock_hash, stock_id);
+
+  if (found)
+    {
+      *item = *found;
+      if (item->label)
+        item->label = dgettext (item->translation_domain, item->label);
+    }
+
+  return found != NULL;
+}
+
+static void
+listify_foreach (gpointer key, gpointer value, gpointer data)
+{
+  GSList **list = data;
+
+  *list = g_slist_prepend (*list, value);
+}
+
+static GSList *
+g_hash_table_get_values (GHashTable *table)
+{
+  GSList *list = NULL;
+
+  g_hash_table_foreach (table, listify_foreach, &list);
+
+  return list;
+}
+
+GSList *
+gtk_stock_list_items (void)
+{
+  init_stock_hash ();
+
+  return g_hash_table_get_values (stock_hash);
+}
+
+GtkStockItem *
+gtk_stock_item_copy (const GtkStockItem *item)
+{
+  GtkStockItem *copy;
+
+  g_return_val_if_fail (item != NULL, NULL);
+
+  copy = g_new (GtkStockItem, 1);
+
+  *copy = *item;
+
+  copy->stock_id = g_strdup (item->stock_id);
+  copy->label = g_strdup (item->label);
+  copy->translation_domain = g_strdup (item->translation_domain);
+
+  return copy;
+}
+
+void
+gtk_stock_item_free (GtkStockItem *item)
+{
+  g_return_if_fail (item != NULL);
+
+  g_free ((gchar*)item->stock_id);
+  g_free ((gchar*)item->label);
+  g_free ((gchar*)item->translation_domain);
+
+  g_free (item);
+}
+
+static GtkStockItem builtin_items [] =
+{
+  /* KEEP IN SYNC with gtkiconfactory.c stock icons */ 
+  { GTK_STOCK_DIALOG_INFO, N_("Information"), 0, 0, GETTEXT_PACKAGE },
+  { GTK_STOCK_DIALOG_WARNING, N_("Warning"), 0, 0, GETTEXT_PACKAGE },
+  { GTK_STOCK_DIALOG_ERROR, N_("Error"), 0, 0, GETTEXT_PACKAGE },
+  { GTK_STOCK_DIALOG_QUESTION, N_("Question"), 0, 0, GETTEXT_PACKAGE },
+
+  { GTK_STOCK_BUTTON_APPLY, N_("_Apply"), 0, 0, GETTEXT_PACKAGE },
+  { GTK_STOCK_BUTTON_OK, N_("OK"), 0, 0, GETTEXT_PACKAGE },
+  { GTK_STOCK_BUTTON_CANCEL, N_("Cancel"), 0, 0, GETTEXT_PACKAGE },
+  { GTK_STOCK_BUTTON_CLOSE, N_("_Close"), 0, 0, GETTEXT_PACKAGE },
+  { GTK_STOCK_BUTTON_YES, N_("_Yes"), 0, 0, GETTEXT_PACKAGE },
+  { GTK_STOCK_BUTTON_NO, N_("_No"), 0, 0, GETTEXT_PACKAGE },
+
+  { GTK_STOCK_CLOSE, N_("Close"), GDK_CONTROL_MASK, 'w', GETTEXT_PACKAGE },
+  { GTK_STOCK_QUIT, N_("Quit"), GDK_CONTROL_MASK, 'q', GETTEXT_PACKAGE },
+  { GTK_STOCK_HELP, N_("Help"), GDK_CONTROL_MASK, 'h', GETTEXT_PACKAGE },
+  { GTK_STOCK_NEW, N_("New"), GDK_CONTROL_MASK, 'n', GETTEXT_PACKAGE },
+  { GTK_STOCK_OPEN, N_("Open"), GDK_CONTROL_MASK, 'o', GETTEXT_PACKAGE },
+  { GTK_STOCK_SAVE, N_("Save"), GDK_CONTROL_MASK, 's', GETTEXT_PACKAGE }
+};
+
+static void
+init_stock_hash (void)
+{
+  if (stock_hash == NULL)
+    {
+      stock_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+      gtk_stock_add_static (builtin_items, G_N_ELEMENTS (builtin_items));
+    }
+}
diff --git a/gtk/gtkstock.h b/gtk/gtkstock.h
new file mode 100644 (file)
index 0000000..02b51ff
--- /dev/null
@@ -0,0 +1,89 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GTK_STOCK_H__
+#define __GTK_STOCK_H__
+
+
+#include <gdk/gdk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _GtkStockItem GtkStockItem;
+
+struct _GtkStockItem
+{
+  gchar *stock_id;
+  gchar *label;
+  GdkModifierType modifier;
+  guint keyval;
+  gchar *translation_domain;
+};
+
+void     gtk_stock_add        (const GtkStockItem  *item,
+                               guint                n_items);
+void     gtk_stock_add_static (const GtkStockItem  *item,
+                               guint                n_items);
+gboolean gtk_stock_lookup     (const gchar         *stock_id,
+                               GtkStockItem        *item);
+
+/* Should free the list, but DO NOT modify the items in the list.
+ * This function is only useful for GUI builders and such.
+ */
+GSList*  gtk_stock_list_items  (void);
+
+GtkStockItem *gtk_stock_item_copy (const GtkStockItem *item);
+void          gtk_stock_item_free (GtkStockItem       *item);
+
+
+/* Stock IDs */
+#define GTK_STOCK_DIALOG_INFO      "gtk-dialog-info"
+#define GTK_STOCK_DIALOG_WARNING   "gtk-dialog-warning"
+#define GTK_STOCK_DIALOG_ERROR     "gtk-dialog-error"
+#define GTK_STOCK_DIALOG_QUESTION  "gtk-dialog-question"
+
+#define GTK_STOCK_BUTTON_APPLY     "gtk-button-apply"
+#define GTK_STOCK_BUTTON_OK        "gtk-button-ok"
+#define GTK_STOCK_BUTTON_CANCEL    "gtk-button-cancel"
+#define GTK_STOCK_BUTTON_CLOSE     "gtk-button-close"
+#define GTK_STOCK_BUTTON_YES       "gtk-button-yes"
+#define GTK_STOCK_BUTTON_NO        "gtk-button-no"
+
+#define GTK_STOCK_CLOSE            "gtk-close"
+#define GTK_STOCK_QUIT             "gtk-quit"
+#define GTK_STOCK_HELP             "gtk-help"
+#define GTK_STOCK_NEW              "gtk-new"
+#define GTK_STOCK_OPEN             "gtk-open"
+#define GTK_STOCK_SAVE             "gtk-save"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK_STOCK_H__ */
index a7c1b6880d1cf20c27f9b684b4ae8d3e854d0f3e..087bcb12ed696ea2c58e65a23e043d93e508d9ec 100644 (file)
@@ -31,7 +31,7 @@
 #include "gtkstyle.h"
 #include "gtkwidget.h"
 #include "gtkthemes.h"
-
+#include "gtkiconfactory.h"
 
 #define LIGHTNESS_MULT  1.3
 #define DARKNESS_MULT   0.7
@@ -56,7 +56,16 @@ static void      gtk_style_real_set_background (GtkStyle     *style,
                                                GtkStateType  state_type);
 static GtkStyle *gtk_style_real_clone          (GtkStyle     *style);
 static void      gtk_style_real_init_from_rc   (GtkStyle     *style,
-                                               GtkRcStyle   *rc_style);
+                                                GtkRcStyle   *rc_style);
+
+
+static GdkPixbuf *gtk_default_render_icon      (GtkStyle            *style,
+                                                const GtkIconSource *source,
+                                                GtkTextDirection     direction,
+                                                GtkStateType         state,
+                                                const gchar         *size,
+                                                GtkWidget           *widget,
+                                                const gchar         *detail);
 
 static void gtk_default_draw_hline      (GtkStyle        *style,
                                         GdkWindow       *window,
@@ -445,7 +454,8 @@ gtk_style_class_init (GtkStyleClass *klass)
   klass->realize = gtk_style_real_realize;
   klass->unrealize = gtk_style_real_unrealize;
   klass->set_background = gtk_style_real_set_background;
-  
+  klass->render_icon = gtk_default_render_icon;
+
   klass->draw_hline = gtk_default_draw_hline;
   klass->draw_vline = gtk_default_draw_vline;
   klass->draw_shadow = gtk_default_draw_shadow;
@@ -521,7 +531,7 @@ gtk_style_duplicate (GtkStyle *style)
 {
   GtkStyle *new_style;
   
-  g_return_val_if_fail (style != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
   
   new_style = gtk_style_copy (style);
   
@@ -582,7 +592,7 @@ gtk_style_attach (GtkStyle  *style,
   GtkStyle *new_style = NULL;
   GdkColormap *colormap;
   
-  g_return_val_if_fail (style != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
   g_return_val_if_fail (window != NULL, NULL);
   
   colormap = gdk_window_get_colormap (window);
@@ -632,7 +642,7 @@ gtk_style_attach (GtkStyle  *style,
 void
 gtk_style_detach (GtkStyle *style)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   
   style->attach_count -= 1;
   if (style->attach_count == 0)
@@ -659,7 +669,7 @@ static void
 gtk_style_realize (GtkStyle    *style,
                    GdkColormap *colormap)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   
   style->colormap = colormap;
   style->depth = gdk_colormap_get_visual (colormap)->depth;
@@ -667,6 +677,31 @@ gtk_style_realize (GtkStyle    *style,
   GTK_STYLE_GET_CLASS (style)->realize (style);
 }
 
+GtkIconSet*
+gtk_style_lookup_icon_set (GtkStyle   *style,
+                           const char *stock_id)
+{
+  GSList *iter;
+
+  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
+  g_return_val_if_fail (stock_id != NULL, NULL);
+  
+  iter = style->icon_factories;
+  while (iter != NULL)
+    {
+      GtkIconSet *icon_set =
+        gtk_icon_factory_lookup (GTK_ICON_FACTORY (iter->data),
+                                 stock_id);
+
+      if (icon_set)
+        return icon_set;
+      
+      iter = g_slist_next (iter);
+    }
+
+  return gtk_icon_factory_lookup_default (stock_id);
+}
+
 void
 gtk_draw_hline (GtkStyle     *style,
                 GdkWindow    *window,
@@ -675,7 +710,7 @@ gtk_draw_hline (GtkStyle     *style,
                 gint          x2,
                 gint          y)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_hline != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_hline (style, window, state_type, NULL, NULL, NULL, x1, x2, y);
@@ -690,7 +725,7 @@ gtk_draw_vline (GtkStyle     *style,
                 gint          y2,
                 gint          x)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_vline != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_vline (style, window, state_type, NULL, NULL, NULL, y1, y2, x);
@@ -707,7 +742,7 @@ gtk_draw_shadow (GtkStyle      *style,
                  gint           width,
                  gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_shadow (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -722,7 +757,7 @@ gtk_draw_polygon (GtkStyle      *style,
                   gint           npoints,
                   gboolean       fill)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_polygon != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_polygon (style, window, state_type, shadow_type, NULL, NULL, NULL, points, npoints, fill);
@@ -740,7 +775,7 @@ gtk_draw_arrow (GtkStyle      *style,
                 gint           width,
                 gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_arrow != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_arrow (style, window, state_type, shadow_type, NULL, NULL, NULL, arrow_type, fill, x, y, width, height);
@@ -757,7 +792,7 @@ gtk_draw_diamond (GtkStyle      *style,
                   gint           width,
                   gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_diamond != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_diamond (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -774,7 +809,7 @@ gtk_draw_oval (GtkStyle      *style,
                gint           width,
                gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_oval != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_oval (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -788,7 +823,7 @@ gtk_draw_string (GtkStyle      *style,
                  gint           y,
                  const gchar   *string)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_string != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_string (style, window, state_type, NULL, NULL, NULL, x, y, string);
@@ -804,7 +839,7 @@ gtk_draw_box (GtkStyle      *style,
               gint           width,
               gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_box != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_box (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -820,7 +855,7 @@ gtk_draw_flat_box (GtkStyle      *style,
                    gint           width,
                    gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_flat_box != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_flat_box (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -836,7 +871,7 @@ gtk_draw_check (GtkStyle      *style,
                 gint           width,
                 gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_check != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_check (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -852,7 +887,7 @@ gtk_draw_option (GtkStyle      *style,
                 gint           width,
                 gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_option != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_option (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -868,7 +903,7 @@ gtk_draw_cross (GtkStyle      *style,
                gint           width,
                gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_cross != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_cross (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -885,7 +920,7 @@ gtk_draw_ramp (GtkStyle      *style,
               gint           width,
               gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_ramp != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_ramp (style, window, state_type, shadow_type, NULL, NULL, NULL, arrow_type, x, y, width, height);
@@ -901,7 +936,7 @@ gtk_draw_tab (GtkStyle      *style,
              gint           width,
              gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_tab != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_tab (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height);
@@ -920,7 +955,7 @@ gtk_draw_shadow_gap (GtkStyle       *style,
                      gint            gap_x,
                      gint            gap_width)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow_gap != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_shadow_gap (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height, gap_side, gap_x, gap_width);
@@ -939,7 +974,7 @@ gtk_draw_box_gap (GtkStyle       *style,
                   gint            gap_x,
                   gint            gap_width)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_box_gap != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_box_gap (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height, gap_side, gap_x, gap_width);
@@ -956,7 +991,7 @@ gtk_draw_extension (GtkStyle       *style,
                     gint            height,
                     GtkPositionType gap_side)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_extension != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_extension (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height, gap_side);
@@ -970,7 +1005,7 @@ gtk_draw_focus (GtkStyle      *style,
                gint           width,
                gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_focus != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_focus (style, window, NULL, NULL, NULL, x, y, width, height);
@@ -987,7 +1022,7 @@ gtk_draw_slider (GtkStyle      *style,
                 gint           height,
                 GtkOrientation orientation)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_slider != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_slider (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height, orientation);
@@ -1004,7 +1039,7 @@ gtk_draw_handle (GtkStyle      *style,
                 gint           height,
                 GtkOrientation orientation)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_handle != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_handle (style, window, state_type, shadow_type, NULL, NULL, NULL, x, y, width, height, orientation);
@@ -1015,7 +1050,7 @@ gtk_style_set_background (GtkStyle    *style,
                           GdkWindow   *window,
                           GtkStateType state_type)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   GTK_STYLE_GET_CLASS (style)->set_background (style, window, state_type);
@@ -1103,6 +1138,22 @@ gtk_style_real_init_from_rc (GtkStyle   *style,
     style->xthickness = rc_style->xthickness;
   if (rc_style->ythickness >= 0)
     style->ythickness = rc_style->ythickness;
+
+  
+  if (rc_style->icon_factories)
+    {
+      GSList *iter;
+
+      style->icon_factories = g_slist_copy (rc_style->icon_factories);
+      
+      iter = style->icon_factories;
+      while (iter != NULL)
+        {
+          g_object_ref (G_OBJECT (iter->data));
+          
+          iter = g_slist_next (iter);
+        }
+    }
 }
 
 static void
@@ -1241,6 +1292,29 @@ gtk_style_real_set_background (GtkStyle    *style,
     gdk_window_set_background (window, &style->bg[state_type]);
 }
 
+GdkPixbuf *
+gtk_style_render_icon (GtkStyle            *style,
+                       const GtkIconSource *source,
+                       GtkTextDirection     direction,
+                       GtkStateType         state,
+                       const gchar         *size,
+                       GtkWidget           *widget,
+                       const gchar         *detail)
+{
+  GdkPixbuf *pixbuf;
+  
+  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
+  g_return_val_if_fail (GTK_STYLE_GET_CLASS (style)->render_icon != NULL, NULL);
+  
+  pixbuf = GTK_STYLE_GET_CLASS (style)->render_icon (style, source, direction, state,
+                                                     size, widget, detail);
+
+  g_return_val_if_fail (pixbuf != NULL, NULL);
+
+  return pixbuf;
+}
+
+/* Default functions */
 void
 gtk_style_apply_default_background (GtkStyle     *style,
                                     GdkWindow    *window,
@@ -1305,6 +1379,92 @@ gtk_style_apply_default_background (GtkStyle     *style,
     }
 }
 
+static GdkPixbuf*
+scale_or_ref (GdkPixbuf *src,
+              gint width,
+              gint height)
+{
+  if (width == gdk_pixbuf_get_width (src) &&
+      height == gdk_pixbuf_get_height (src))
+    {
+      gdk_pixbuf_ref (src);
+      return src;
+    }
+  else
+    {
+      return gdk_pixbuf_scale_simple (src,
+                                      width, height,
+                                      GDK_INTERP_BILINEAR);
+    }
+}
+
+static GdkPixbuf *
+gtk_default_render_icon (GtkStyle            *style,
+                          const GtkIconSource *source,
+                          GtkTextDirection     direction,
+                          GtkStateType         state,
+                          const gchar         *size,
+                          GtkWidget           *widget,
+                          const gchar         *detail)
+{
+  gint width = 1;
+  gint height = 1;
+  GdkPixbuf *scaled;
+  GdkPixbuf *stated;
+
+  /* Oddly, style can be NULL in this function, because
+   * GtkIconSet can be used without a style and if so
+   * it uses this function.
+   */
+  
+  g_return_val_if_fail (source->pixbuf != NULL, NULL);
+  
+  if (!gtk_icon_size_lookup (size, &width, &height))
+    {
+      g_warning ("Bad icon size '%s' passed to render_icon", size);
+      return NULL;
+    }
+
+  /* If the size was wildcarded, then scale; otherwise, leave it
+   * alone.
+   */
+  if (source->any_size)
+    scaled = scale_or_ref (source->pixbuf, width, height);
+  else
+    scaled = GDK_PIXBUF (g_object_ref (G_OBJECT (source->pixbuf)));
+
+  /* If the state was wildcarded, then generate a state. */
+  if (source->any_state)
+    {
+      if (state == GTK_STATE_INSENSITIVE)
+        {
+          stated = gdk_pixbuf_copy (scaled);      
+          
+          gdk_pixbuf_saturate_and_pixelate (scaled, stated,
+                                            0.8, TRUE);
+          
+          gdk_pixbuf_unref (scaled);
+        }
+      else if (state == GTK_STATE_PRELIGHT)
+        {
+          stated = gdk_pixbuf_copy (scaled);      
+          
+          gdk_pixbuf_saturate_and_pixelate (scaled, stated,
+                                            1.2, FALSE);
+          
+          gdk_pixbuf_unref (scaled);
+        }
+      else
+        {
+          stated = scaled;
+        }
+    }
+  else
+    stated = scaled;
+  
+  return stated;
+}
+
 static void
 gtk_default_draw_hline (GtkStyle     *style,
                         GdkWindow    *window,
@@ -1320,7 +1480,7 @@ gtk_default_draw_hline (GtkStyle     *style,
   gint thickness_dark;
   gint i;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   thickness_light = style->ythickness / 2;
@@ -1377,7 +1537,7 @@ gtk_default_draw_vline (GtkStyle     *style,
   gint thickness_dark;
   gint i;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   thickness_light = style->xthickness / 2;
@@ -1427,7 +1587,7 @@ gtk_default_draw_shadow (GtkStyle      *style,
   gint thickness_dark;
   gint i;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if ((width == -1) && (height == -1))
@@ -1606,7 +1766,7 @@ gtk_default_draw_polygon (GtkStyle      *style,
   gint yadjust;
   gint i;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   g_return_if_fail (points != NULL);
   
@@ -1740,7 +1900,7 @@ gtk_default_draw_arrow (GtkStyle      *style,
   gint half_height;
   GdkPoint points[3];
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   switch (shadow_type)
@@ -2086,7 +2246,7 @@ gtk_default_draw_diamond (GtkStyle      *style,
   gint half_width;
   gint half_height;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if ((width == -1) && (height == -1))
@@ -2211,7 +2371,7 @@ gtk_default_draw_oval (GtkStyle      *style,
                        gint           width,
                        gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
 
   g_warning ("gtk_default_draw_oval(): FIXME, this function is currently unimplemented");
@@ -2228,7 +2388,7 @@ gtk_default_draw_string (GtkStyle      *style,
                          gint           y,
                          const gchar   *string)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if (area)
@@ -2262,7 +2422,7 @@ gtk_default_draw_box (GtkStyle      *style,
                      gint           width,
                      gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if (width == -1 && height == -1)
@@ -2307,7 +2467,7 @@ gtk_default_draw_flat_box (GtkStyle      *style,
 {
   GdkGC *gc1;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if (width == -1 && height == -1)
@@ -2400,7 +2560,7 @@ gtk_default_draw_cross (GtkStyle      *style,
                        gint           width,
                        gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
 
   g_warning ("gtk_default_draw_cross(): FIXME, this function is currently unimplemented");
@@ -2420,7 +2580,7 @@ gtk_default_draw_ramp    (GtkStyle      *style,
                           gint           width,
                           gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
 
   g_warning ("gtk_default_draw_ramp(): FIXME, this function is currently unimplemented");
@@ -2439,7 +2599,7 @@ gtk_default_draw_tab (GtkStyle      *style,
                      gint           width,
                      gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   gtk_paint_box (style, window, state_type, shadow_type, area, widget, detail,
@@ -2467,7 +2627,7 @@ gtk_default_draw_shadow_gap (GtkStyle       *style,
   GdkGC *gc3 = NULL;
   GdkGC *gc4 = NULL;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if (width == -1 && height == -1)
@@ -2688,7 +2848,7 @@ gtk_default_draw_box_gap (GtkStyle       *style,
   GdkGC *gc3 = NULL;
   GdkGC *gc4 = NULL;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   gtk_style_apply_default_background (style, window,
@@ -2912,7 +3072,7 @@ gtk_default_draw_extension (GtkStyle       *style,
   GdkGC *gc3 = NULL;
   GdkGC *gc4 = NULL;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   gtk_style_apply_default_background (style, window,
@@ -3084,7 +3244,7 @@ gtk_default_draw_focus (GtkStyle      *style,
                         gint           width,
                         gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if (width == -1 && height == -1)
@@ -3143,7 +3303,7 @@ gtk_default_draw_slider (GtkStyle      *style,
                          gint           height,
                          GtkOrientation orientation)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if (width == -1 && height == -1)
@@ -3214,7 +3374,7 @@ gtk_default_draw_handle (GtkStyle      *style,
   GdkRectangle dest;
   gint intersect;
   
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (window != NULL);
   
   if (width == -1 && height == -1)
@@ -3488,7 +3648,7 @@ gtk_paint_hline (GtkStyle      *style,
                  gint          x2,
                  gint          y)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_hline != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_hline (style, window, state_type, area, widget, detail, x1, x2, y);
@@ -3505,7 +3665,7 @@ gtk_paint_vline (GtkStyle      *style,
                  gint          y2,
                  gint          x)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_vline != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_vline (style, window, state_type, area, widget, detail, y1, y2, x);
@@ -3524,7 +3684,7 @@ gtk_paint_shadow (GtkStyle     *style,
                   gint          width,
                   gint          height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_shadow (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3542,7 +3702,7 @@ gtk_paint_polygon (GtkStyle      *style,
                    gint           npoints,
                    gboolean       fill)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_polygon (style, window, state_type, shadow_type, area, widget, detail, points, npoints, fill);
@@ -3563,7 +3723,7 @@ gtk_paint_arrow (GtkStyle      *style,
                  gint           width,
                  gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_arrow != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_arrow (style, window, state_type, shadow_type, area, widget, detail, arrow_type, fill, x, y, width, height);
@@ -3582,7 +3742,7 @@ gtk_paint_diamond (GtkStyle      *style,
                    gint        width,
                    gint        height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_diamond != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_diamond (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3601,7 +3761,7 @@ gtk_paint_oval (GtkStyle      *style,
                 gint           width,
                 gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_oval != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_oval (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3618,7 +3778,7 @@ gtk_paint_string (GtkStyle      *style,
                   gint           y,
                   const gchar   *string)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_string != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_string (style, window, state_type, area, widget, detail, x, y, string);
@@ -3637,7 +3797,7 @@ gtk_paint_box (GtkStyle      *style,
                gint           width,
                gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_box != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_box (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3656,7 +3816,7 @@ gtk_paint_flat_box (GtkStyle      *style,
                     gint           width,
                     gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_flat_box != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_flat_box (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3675,7 +3835,7 @@ gtk_paint_check (GtkStyle      *style,
                  gint           width,
                  gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_check != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_check (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3694,7 +3854,7 @@ gtk_paint_option (GtkStyle      *style,
                   gint           width,
                   gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_option != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_option (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3713,7 +3873,7 @@ gtk_paint_cross (GtkStyle      *style,
                  gint           width,
                  gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_cross != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_cross (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3733,7 +3893,7 @@ gtk_paint_ramp (GtkStyle      *style,
                 gint           width,
                 gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_ramp != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_ramp (style, window, state_type, shadow_type, area, widget, detail, arrow_type, x, y, width, height);
@@ -3752,7 +3912,7 @@ gtk_paint_tab (GtkStyle      *style,
                gint           width,
                gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_tab != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_tab (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height);
@@ -3774,7 +3934,7 @@ gtk_paint_shadow_gap (GtkStyle       *style,
                       gint            gap_x,
                       gint            gap_width)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow_gap != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_shadow_gap (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height, gap_side, gap_x, gap_width);
@@ -3797,7 +3957,7 @@ gtk_paint_box_gap (GtkStyle       *style,
                    gint            gap_x,
                    gint            gap_width)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_box_gap != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_box_gap (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height, gap_side, gap_x, gap_width);
@@ -3817,7 +3977,7 @@ gtk_paint_extension (GtkStyle       *style,
                      gint            height,
                      GtkPositionType gap_side)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_extension != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_extension (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height, gap_side);
@@ -3834,7 +3994,7 @@ gtk_paint_focus (GtkStyle      *style,
                  gint           width,
                  gint           height)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_focus != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_focus (style, window, area, widget, detail, x, y, width, height);
@@ -3854,7 +4014,7 @@ gtk_paint_slider (GtkStyle      *style,
                   gint           height,
                   GtkOrientation orientation)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_slider != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_slider (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height, orientation);
@@ -3874,7 +4034,7 @@ gtk_paint_handle (GtkStyle      *style,
                   gint           height,
                   GtkOrientation orientation)
 {
-  g_return_if_fail (style != NULL);
+  g_return_if_fail (GTK_IS_STYLE (style));
   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_handle != NULL);
   
   GTK_STYLE_GET_CLASS (style)->draw_handle (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height, orientation);
index e23203a1c556d78c0cb3e527e1091d31c37fbe77..84271273079d6578fe37d9c117cd1281f2b50457 100644 (file)
@@ -51,7 +51,8 @@ typedef struct _GtkStyleClass  GtkStyleClass;
  */
 typedef struct _GtkThemeEngine GtkThemeEngine;
 typedef struct _GtkRcStyle     GtkRcStyle;
-
+typedef struct _GtkIconSet     GtkIconSet;
+typedef struct _GtkIconSource  GtkIconSource;
 
 /* We make this forward declaration here, since we pass
  * GtkWidgt's to the draw functions.
@@ -110,6 +111,8 @@ struct _GtkStyle
                                 * was created
                                 */
   GSList        *styles;
+
+  GSList         *icon_factories;
 };
 
 struct _GtkStyleClass
@@ -149,8 +152,18 @@ struct _GtkStyleClass
                                 GdkWindow              *window,
                                 GtkStateType            state_type);
 
+
+  GdkPixbuf * (* render_icon)   (GtkStyle               *style,
+                                 const GtkIconSource    *source,
+                                 GtkTextDirection        direction,
+                                 GtkStateType            state,
+                                 const gchar            *size,
+                                 GtkWidget              *widget,
+                                 const gchar            *detail);
+  
   /* Drawing functions
    */
+  
   void (*draw_hline)           (GtkStyle               *style,
                                 GdkWindow              *window,
                                 GtkStateType            state_type,
@@ -408,6 +421,15 @@ void         gtk_style_apply_default_background (GtkStyle     *style,
                                              gint          width, 
                                              gint          height);
 
+GtkIconSet* gtk_style_lookup_icon_set (GtkStyle            *style,
+                                       const gchar         *stock_id);
+GdkPixbuf * gtk_style_render_icon     (GtkStyle            *style,
+                                       const GtkIconSource *source,
+                                       GtkTextDirection     direction,
+                                       GtkStateType         state,
+                                       const gchar *        size,
+                                       GtkWidget           *widget,
+                                       const gchar         *detail);
 void gtk_draw_hline      (GtkStyle        *style,
                          GdkWindow       *window,
                          GtkStateType     state_type,
@@ -815,6 +837,7 @@ void gtk_paint_handle     (GtkStyle        *style,
                           gint             height,
                           GtkOrientation   orientation);
 
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index bd084de24daf86462ad25be1acdb747752182f61..ed19d79e4f70b0a4cd855a4d4eba6ae191962d13 100644 (file)
@@ -28,6 +28,7 @@
 #include <string.h>
 #include <locale.h>
 #include "gtkcontainer.h"
+#include "gtkiconfactory.h"
 #include "gtkmain.h"
 #include "gtkrc.h"
 #include "gtkselection.h"
@@ -3541,6 +3542,37 @@ gtk_widget_create_pango_layout (GtkWidget   *widget,
   return layout;
 }
 
+GdkPixbuf*
+gtk_widget_render_stock_icon (GtkWidget      *widget,
+                              const gchar    *stock_id,
+                              const gchar    *size,
+                              const gchar    *detail)
+{
+  GtkIconSet *icon_set;
+  GdkPixbuf *retval;
+  
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+  g_return_val_if_fail (stock_id != NULL, NULL);
+  g_return_val_if_fail (size != NULL, NULL);
+  
+  gtk_widget_ensure_style (widget);
+  
+  icon_set = gtk_style_lookup_icon_set (widget->style, stock_id);
+
+  if (icon_set == NULL)
+    return NULL;
+
+  retval = gtk_icon_set_render_icon (icon_set,
+                                     widget->style,
+                                     gtk_widget_get_direction (widget),
+                                     GTK_WIDGET_STATE (widget),
+                                     size,
+                                     widget,
+                                     detail);
+
+  return retval;
+}
+
 /*************************************************************
  * gtk_widget_set_parent_window:
  *     Set a non default parent window for widget
index 4e2a87e7f6db43fb83d91112cb9cb0d2c638f5da..b55a2a1b9967c56bbfbb74ebd2051945ab41a514 100644 (file)
@@ -606,6 +606,11 @@ PangoContext *gtk_widget_get_pango_context    (GtkWidget   *widget);
 PangoLayout  *gtk_widget_create_pango_layout  (GtkWidget   *widget,
                                               const gchar *text);
 
+GdkPixbuf* gtk_widget_render_stock_icon       (GtkWidget      *widget,
+                                               const gchar    *stock_id,
+                                               const gchar    *size,
+                                               const gchar    *detail);
+
 /* handle composite names for GTK_COMPOSITE_CHILD widgets,
  * the returned name is newly allocated.
  */
diff --git a/gtk/stock-icons/Makefile.am b/gtk/stock-icons/Makefile.am
new file mode 100644 (file)
index 0000000..3bf0d50
--- /dev/null
@@ -0,0 +1,23 @@
+BUILT_SOURCES=gtkstockpixbufs.h
+
+IMAGES= dialog_error.png  dialog_info.png  dialog_question.png  dialog_warning.png  stock_button_apply.png  stock_button_cancel.png  stock_button_close.png  stock_button_no.png  stock_button_ok.png  stock_button_yes.png  stock_close.png  stock_exit.png  stock_help.png  stock_new.png  stock_open.png  stock_save.png
+
+VARIABLES=     dialog_error            dialog_error.png        \
+               dialog_info             dialog_info.png         \
+               dialog_question         dialog_question.png     \
+               dialog_warning          dialog_warning.png      \
+               stock_button_apply      stock_button_apply.png  \
+               stock_button_cancel     stock_button_cancel.png \
+               stock_button_close      stock_button_close.png  \
+               stock_button_no         stock_button_no.png     \
+               stock_button_ok         stock_button_ok.png     \
+               stock_button_yes        stock_button_yes.png    \
+               stock_close             stock_close.png         \
+               stock_exit              stock_exit.png          \
+               stock_help              stock_help.png          \
+               stock_new               stock_new.png           \
+               stock_open              stock_open.png          \
+               stock_save              stock_save.png
+
+gtkstockpixbufs.h: $(top_builddir)/gdk-pixbuf/make-inline-pixbuf $(IMAGES)
+       GDK_PIXBUF_MODULEDIR=$(top_builddir)/gdk-pixbuf/.libs $(top_builddir)/gdk-pixbuf/make-inline-pixbuf gtkstockpixbufs.h $(VARIABLES)
diff --git a/gtk/stock-icons/dialog_error.png b/gtk/stock-icons/dialog_error.png
new file mode 100644 (file)
index 0000000..cc7830e
Binary files /dev/null and b/gtk/stock-icons/dialog_error.png differ
diff --git a/gtk/stock-icons/dialog_error_48.png b/gtk/stock-icons/dialog_error_48.png
new file mode 100644 (file)
index 0000000..cc7830e
Binary files /dev/null and b/gtk/stock-icons/dialog_error_48.png differ
diff --git a/gtk/stock-icons/dialog_info.png b/gtk/stock-icons/dialog_info.png
new file mode 100644 (file)
index 0000000..757e599
Binary files /dev/null and b/gtk/stock-icons/dialog_info.png differ
diff --git a/gtk/stock-icons/dialog_info_48.png b/gtk/stock-icons/dialog_info_48.png
new file mode 100644 (file)
index 0000000..757e599
Binary files /dev/null and b/gtk/stock-icons/dialog_info_48.png differ
diff --git a/gtk/stock-icons/dialog_question.png b/gtk/stock-icons/dialog_question.png
new file mode 100644 (file)
index 0000000..2afbc7a
Binary files /dev/null and b/gtk/stock-icons/dialog_question.png differ
diff --git a/gtk/stock-icons/dialog_question_48.png b/gtk/stock-icons/dialog_question_48.png
new file mode 100644 (file)
index 0000000..2afbc7a
Binary files /dev/null and b/gtk/stock-icons/dialog_question_48.png differ
diff --git a/gtk/stock-icons/dialog_warning.png b/gtk/stock-icons/dialog_warning.png
new file mode 100644 (file)
index 0000000..d6f2306
Binary files /dev/null and b/gtk/stock-icons/dialog_warning.png differ
diff --git a/gtk/stock-icons/dialog_warning_48.png b/gtk/stock-icons/dialog_warning_48.png
new file mode 100644 (file)
index 0000000..d6f2306
Binary files /dev/null and b/gtk/stock-icons/dialog_warning_48.png differ
diff --git a/gtk/stock-icons/stock_apply_20.png b/gtk/stock-icons/stock_apply_20.png
new file mode 100644 (file)
index 0000000..58a64cf
Binary files /dev/null and b/gtk/stock-icons/stock_apply_20.png differ
diff --git a/gtk/stock-icons/stock_button_apply.png b/gtk/stock-icons/stock_button_apply.png
new file mode 100644 (file)
index 0000000..58a64cf
Binary files /dev/null and b/gtk/stock-icons/stock_button_apply.png differ
diff --git a/gtk/stock-icons/stock_button_apply_24.png b/gtk/stock-icons/stock_button_apply_24.png
new file mode 100644 (file)
index 0000000..58a64cf
Binary files /dev/null and b/gtk/stock-icons/stock_button_apply_24.png differ
diff --git a/gtk/stock-icons/stock_button_cancel.png b/gtk/stock-icons/stock_button_cancel.png
new file mode 100644 (file)
index 0000000..2d7c194
Binary files /dev/null and b/gtk/stock-icons/stock_button_cancel.png differ
diff --git a/gtk/stock-icons/stock_button_cancel_24.png b/gtk/stock-icons/stock_button_cancel_24.png
new file mode 100644 (file)
index 0000000..2d7c194
Binary files /dev/null and b/gtk/stock-icons/stock_button_cancel_24.png differ
diff --git a/gtk/stock-icons/stock_button_close.png b/gtk/stock-icons/stock_button_close.png
new file mode 100644 (file)
index 0000000..b900bdf
Binary files /dev/null and b/gtk/stock-icons/stock_button_close.png differ
diff --git a/gtk/stock-icons/stock_button_close_24.png b/gtk/stock-icons/stock_button_close_24.png
new file mode 100644 (file)
index 0000000..b900bdf
Binary files /dev/null and b/gtk/stock-icons/stock_button_close_24.png differ
diff --git a/gtk/stock-icons/stock_button_no.png b/gtk/stock-icons/stock_button_no.png
new file mode 100644 (file)
index 0000000..6478554
Binary files /dev/null and b/gtk/stock-icons/stock_button_no.png differ
diff --git a/gtk/stock-icons/stock_button_no_24.png b/gtk/stock-icons/stock_button_no_24.png
new file mode 100644 (file)
index 0000000..6478554
Binary files /dev/null and b/gtk/stock-icons/stock_button_no_24.png differ
diff --git a/gtk/stock-icons/stock_button_ok.png b/gtk/stock-icons/stock_button_ok.png
new file mode 100644 (file)
index 0000000..f1c3375
Binary files /dev/null and b/gtk/stock-icons/stock_button_ok.png differ
diff --git a/gtk/stock-icons/stock_button_ok_24.png b/gtk/stock-icons/stock_button_ok_24.png
new file mode 100644 (file)
index 0000000..f1c3375
Binary files /dev/null and b/gtk/stock-icons/stock_button_ok_24.png differ
diff --git a/gtk/stock-icons/stock_button_yes.png b/gtk/stock-icons/stock_button_yes.png
new file mode 100644 (file)
index 0000000..e061e7f
Binary files /dev/null and b/gtk/stock-icons/stock_button_yes.png differ
diff --git a/gtk/stock-icons/stock_button_yes_24.png b/gtk/stock-icons/stock_button_yes_24.png
new file mode 100644 (file)
index 0000000..e061e7f
Binary files /dev/null and b/gtk/stock-icons/stock_button_yes_24.png differ
diff --git a/gtk/stock-icons/stock_cancel_20.png b/gtk/stock-icons/stock_cancel_20.png
new file mode 100644 (file)
index 0000000..2d7c194
Binary files /dev/null and b/gtk/stock-icons/stock_cancel_20.png differ
diff --git a/gtk/stock-icons/stock_close.png b/gtk/stock-icons/stock_close.png
new file mode 100644 (file)
index 0000000..4338bdc
Binary files /dev/null and b/gtk/stock-icons/stock_close.png differ
diff --git a/gtk/stock-icons/stock_close_20.png b/gtk/stock-icons/stock_close_20.png
new file mode 100644 (file)
index 0000000..b900bdf
Binary files /dev/null and b/gtk/stock-icons/stock_close_20.png differ
diff --git a/gtk/stock-icons/stock_close_24.png b/gtk/stock-icons/stock_close_24.png
new file mode 100644 (file)
index 0000000..4338bdc
Binary files /dev/null and b/gtk/stock-icons/stock_close_24.png differ
diff --git a/gtk/stock-icons/stock_dialog_error_48.png b/gtk/stock-icons/stock_dialog_error_48.png
new file mode 100644 (file)
index 0000000..cc7830e
Binary files /dev/null and b/gtk/stock-icons/stock_dialog_error_48.png differ
diff --git a/gtk/stock-icons/stock_dialog_info_48.png b/gtk/stock-icons/stock_dialog_info_48.png
new file mode 100644 (file)
index 0000000..757e599
Binary files /dev/null and b/gtk/stock-icons/stock_dialog_info_48.png differ
diff --git a/gtk/stock-icons/stock_dialog_question_48.png b/gtk/stock-icons/stock_dialog_question_48.png
new file mode 100644 (file)
index 0000000..2afbc7a
Binary files /dev/null and b/gtk/stock-icons/stock_dialog_question_48.png differ
diff --git a/gtk/stock-icons/stock_dialog_warning_48.png b/gtk/stock-icons/stock_dialog_warning_48.png
new file mode 100644 (file)
index 0000000..d6f2306
Binary files /dev/null and b/gtk/stock-icons/stock_dialog_warning_48.png differ
diff --git a/gtk/stock-icons/stock_exit.png b/gtk/stock-icons/stock_exit.png
new file mode 100644 (file)
index 0000000..34cccc3
Binary files /dev/null and b/gtk/stock-icons/stock_exit.png differ
diff --git a/gtk/stock-icons/stock_exit_24.png b/gtk/stock-icons/stock_exit_24.png
new file mode 100644 (file)
index 0000000..34cccc3
Binary files /dev/null and b/gtk/stock-icons/stock_exit_24.png differ
diff --git a/gtk/stock-icons/stock_help.png b/gtk/stock-icons/stock_help.png
new file mode 100644 (file)
index 0000000..2836a0f
Binary files /dev/null and b/gtk/stock-icons/stock_help.png differ
diff --git a/gtk/stock-icons/stock_help_24.png b/gtk/stock-icons/stock_help_24.png
new file mode 100644 (file)
index 0000000..2836a0f
Binary files /dev/null and b/gtk/stock-icons/stock_help_24.png differ
diff --git a/gtk/stock-icons/stock_new.png b/gtk/stock-icons/stock_new.png
new file mode 100644 (file)
index 0000000..538e9ac
Binary files /dev/null and b/gtk/stock-icons/stock_new.png differ
diff --git a/gtk/stock-icons/stock_new_24.png b/gtk/stock-icons/stock_new_24.png
new file mode 100644 (file)
index 0000000..538e9ac
Binary files /dev/null and b/gtk/stock-icons/stock_new_24.png differ
diff --git a/gtk/stock-icons/stock_no_20.png b/gtk/stock-icons/stock_no_20.png
new file mode 100644 (file)
index 0000000..6478554
Binary files /dev/null and b/gtk/stock-icons/stock_no_20.png differ
diff --git a/gtk/stock-icons/stock_ok_20.png b/gtk/stock-icons/stock_ok_20.png
new file mode 100644 (file)
index 0000000..f1c3375
Binary files /dev/null and b/gtk/stock-icons/stock_ok_20.png differ
diff --git a/gtk/stock-icons/stock_open.png b/gtk/stock-icons/stock_open.png
new file mode 100644 (file)
index 0000000..e966ad7
Binary files /dev/null and b/gtk/stock-icons/stock_open.png differ
diff --git a/gtk/stock-icons/stock_open_24.png b/gtk/stock-icons/stock_open_24.png
new file mode 100644 (file)
index 0000000..e966ad7
Binary files /dev/null and b/gtk/stock-icons/stock_open_24.png differ
diff --git a/gtk/stock-icons/stock_save.png b/gtk/stock-icons/stock_save.png
new file mode 100644 (file)
index 0000000..2281b92
Binary files /dev/null and b/gtk/stock-icons/stock_save.png differ
diff --git a/gtk/stock-icons/stock_save_24.png b/gtk/stock-icons/stock_save_24.png
new file mode 100644 (file)
index 0000000..2281b92
Binary files /dev/null and b/gtk/stock-icons/stock_save_24.png differ
diff --git a/gtk/stock-icons/stock_yes_20.png b/gtk/stock-icons/stock_yes_20.png
new file mode 100644 (file)
index 0000000..e061e7f
Binary files /dev/null and b/gtk/stock-icons/stock_yes_20.png differ