From: Havoc Pennington Date: Tue, 26 Sep 2000 20:22:17 +0000 (+0000) Subject: Move more text widget headers into the private header list X-Git-Url: http://pileus.org/git/?p=~andy%2Fgtk;a=commitdiff_plain;h=e8597130f58f6808cdfa1bac7058da7f33a9f600 Move more text widget headers into the private header list 2000-09-26 Havoc Pennington * 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. --- diff --git a/Makefile.am b/Makefile.am index fbab5ecd6..0b42c1c0e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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" \ diff --git a/configure.in b/configure.in index d33a4fe30..5b1dca127 100644 --- a/configure.in +++ b/configure.in @@ -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 index 000000000..0dc03329c --- /dev/null +++ b/gdk-2.0.pc.in @@ -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 index 000000000..96afc3d31 --- /dev/null +++ b/gdk-pixbuf.pc.in @@ -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} diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog index e8bb33219..8a85fb836 100644 --- a/gdk-pixbuf/ChangeLog +++ b/gdk-pixbuf/ChangeLog @@ -1,3 +1,23 @@ +2000-09-26 Havoc Pennington + + * 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 + + * 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 * 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 + * 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 * Makefile.am (libgdk_pixbuf_la_LDFLAGS): Use GTK+ version soname scheme for gdk-pixbuf. - + 2000-06-21 Havoc Pennington * gdk-pixbuf.c: Convert GdkPixbuf to GObject, leaving it opaque diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am index 4628de1cc..2247e657e 100644 --- a/gdk-pixbuf/Makefile.am +++ b/gdk-pixbuf/Makefile.am @@ -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) # diff --git a/gdk-pixbuf/gdk-pixbuf-data.c b/gdk-pixbuf/gdk-pixbuf-data.c index 62634d214..94db20f37 100644 --- a/gdk-pixbuf/gdk-pixbuf-data.c +++ b/gdk-pixbuf/gdk-pixbuf-data.c @@ -23,6 +23,8 @@ #include #include "gdk-pixbuf.h" #include "gdk-pixbuf-private.h" +#include +#include @@ -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; +} + diff --git a/gdk-pixbuf/gdk-pixbuf-private.h b/gdk-pixbuf/gdk-pixbuf-private.h index 1b14e3ccc..e8eb7248a 100644 --- a/gdk-pixbuf/gdk-pixbuf-private.h +++ b/gdk-pixbuf/gdk-pixbuf-private.h @@ -117,4 +117,14 @@ struct _GdkPixbufAnimationClass { +#define GDK_PIXBUF_INLINE_MAGIC_NUMBER 0x47646B50 /* 'GdkP' */ + +typedef enum +{ + GDK_PIXBUF_INLINE_RAW = 0, + GDK_PIXBUF_INLINE_RLE = 1 +} GdkPixbufInlineFormat; + + + #endif diff --git a/gdk-pixbuf/gdk-pixbuf-util.c b/gdk-pixbuf/gdk-pixbuf-util.c index 848aadd14..db8ca758e 100644 --- a/gdk-pixbuf/gdk-pixbuf-util.c +++ b/gdk-pixbuf/gdk-pixbuf-util.c @@ -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; + } +} diff --git a/gdk-pixbuf/gdk-pixbuf.h b/gdk-pixbuf/gdk-pixbuf.h index a7074fd50..aaaad7fda 100644 --- a/gdk-pixbuf/gdk-pixbuf.h +++ b/gdk-pixbuf/gdk-pixbuf.h @@ -36,7 +36,10 @@ extern "C" { -/* 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); + /* Rendering to a drawable */ diff --git a/gdk-pixbuf/make-inline-pixbuf.c b/gdk-pixbuf/make-inline-pixbuf.c new file mode 100644 index 000000000..daf0a7e20 --- /dev/null +++ b/gdk-pixbuf/make-inline-pixbuf.c @@ -0,0 +1,213 @@ +/* Program to convert an image file to inline C data + * + * Copyright (C) 2000 Red Hat, Inc. + * + * Developed by Havoc Pennington + * + * 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 +#include "gdk-pixbuf-private.h" +#include +#include +#include +#include + +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 index 000000000..ddf6c4b62 --- /dev/null +++ b/gtk+-2.0.pc.in @@ -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} diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 274ecc36a..173ef56a9 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -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 \ diff --git a/gtk/gtk.h b/gtk/gtk.h index 25765fdd3..2e2bd5138 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -116,6 +117,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c index 802873e00..394688496 100644 --- a/gtk/gtkbutton.c +++ b/gtk/gtkbutton.c @@ -29,7 +29,10 @@ #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) { diff --git a/gtk/gtkbutton.h b/gtk/gtkbutton.h index a55460e03..0d8c676d0 100644 --- a/gtk/gtkbutton.h +++ b/gtk/gtkbutton.h @@ -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 index 000000000..8924df75c --- /dev/null +++ b/gtk/gtkiconfactory.c @@ -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 +#include +#include +#include + +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 index 000000000..357e37eb7 --- /dev/null +++ b/gtk/gtkiconfactory.h @@ -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 +#include + +#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__ */ diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c index 01154d929..504b2a2e1 100644 --- a/gtk/gtkimage.c +++ b/gtk/gtkimage.c @@ -26,13 +26,20 @@ #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; +} + + diff --git a/gtk/gtkimage.h b/gtk/gtkimage.h index 147a60646..266d032e6 100644 --- a/gtk/gtkimage.h +++ b/gtk/gtkimage.h @@ -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, diff --git a/gtk/gtkrc.c b/gtk/gtkrc.c index 495fbbd41..324e8d3a5 100644 --- a/gtk/gtkrc.c +++ b/gtk/gtkrc.c @@ -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, diff --git a/gtk/gtkrc.h b/gtk/gtkrc.h index a1a98f227..0b3703931 100644 --- a/gtk/gtkrc.h +++ b/gtk/gtkrc.h @@ -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 index 000000000..ecb307973 --- /dev/null +++ b/gtk/gtkstock.c @@ -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 + +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 index 000000000..02b51ff97 --- /dev/null +++ b/gtk/gtkstock.h @@ -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 + +#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__ */ diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c index a7c1b6880..087bcb12e 100644 --- a/gtk/gtkstyle.c +++ b/gtk/gtkstyle.c @@ -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); diff --git a/gtk/gtkstyle.h b/gtk/gtkstyle.h index e23203a1c..842712730 100644 --- a/gtk/gtkstyle.h +++ b/gtk/gtkstyle.h @@ -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 */ diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index bd084de24..ed19d79e4 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -28,6 +28,7 @@ #include #include #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 diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 4e2a87e7f..b55a2a1b9 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -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 index 000000000..3bf0d5074 --- /dev/null +++ b/gtk/stock-icons/Makefile.am @@ -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 index 000000000..cc7830e26 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 index 000000000..cc7830e26 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 index 000000000..757e599d2 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 index 000000000..757e599d2 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 index 000000000..2afbc7a87 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 index 000000000..2afbc7a87 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 index 000000000..d6f2306db 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 index 000000000..d6f2306db 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 index 000000000..58a64cfc4 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 index 000000000..58a64cfc4 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 index 000000000..58a64cfc4 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 index 000000000..2d7c194c8 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 index 000000000..2d7c194c8 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 index 000000000..b900bdf3b 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 index 000000000..b900bdf3b 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 index 000000000..6478554f6 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 index 000000000..6478554f6 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 index 000000000..f1c33753f 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 index 000000000..f1c33753f 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 index 000000000..e061e7f17 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 index 000000000..e061e7f17 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 index 000000000..2d7c194c8 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 index 000000000..4338bdc3f 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 index 000000000..b900bdf3b 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 index 000000000..4338bdc3f 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 index 000000000..cc7830e26 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 index 000000000..757e599d2 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 index 000000000..2afbc7a87 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 index 000000000..d6f2306db 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 index 000000000..34cccc31d 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 index 000000000..34cccc31d 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 index 000000000..2836a0f8a 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 index 000000000..2836a0f8a 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 index 000000000..538e9acd3 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 index 000000000..538e9acd3 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 index 000000000..6478554f6 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 index 000000000..f1c33753f 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 index 000000000..e966ad7bf 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 index 000000000..e966ad7bf 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 index 000000000..2281b92c2 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 index 000000000..2281b92c2 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 index 000000000..e061e7f17 Binary files /dev/null and b/gtk/stock-icons/stock_yes_20.png differ