diff options
author | Havoc Pennington <hp@redhat.com> | 2000-09-26 20:22:17 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 2000-09-26 20:22:17 +0000 |
commit | e8597130f58f6808cdfa1bac7058da7f33a9f600 (patch) | |
tree | 147da1d69e7b52f2139600d9609eb58a1253965d /gtk | |
parent | 9bec105a6606f11fb1e85e5f378d39595da0c165 (diff) | |
download | gtk+-e8597130f58f6808cdfa1bac7058da7f33a9f600.tar.gz |
Move more text widget headers into the private header list
2000-09-26 Havoc Pennington <hp@redhat.com>
* gtk/Makefile.am (gtk_private_h_sources): Move more text widget
headers into the private header list
* Makefile.am (pkgconfig_DATA): install pkg-config files
* configure.in: add pkg-config files
* gdk-2.0.pc.in, gdk-pixbuf.pc.in, gtk+-2.0.pc.in: pkg-config files
* gtk/gtkwindow.c (gtk_window_read_rcfiles): Invalidate
outstanding icon caches on theme change.
* gtk/gtkiconfactory.h, gtk/gtkiconfactory.c: New icon system. Three
important types:
(GtkIconSource): Specification for creating a pixbuf
appropriate for a direction/state/size triplet from
a source pixbuf or filename
(GtkIconSet): List of GtkIconSource objects that are used to
create the "same" icon (e.g. an OK button icon), and cache for
rendered icons
(GtkIconFactory): Hash from stock ID to GtkIconSet; used to look
up the icon set for a given stock ID. GTK maintains a stack of
GtkIconFactory to search, and applications or libraries can add
additional icon factories on top of the stack
* gtk/gtkrc.h, gtk/gtkrc.c: When loading an RcStyle, parse
the set of GtkIconSource specified for a given stock ID into
a GtkIconSet, and put the GtkIconSet into a GtkIconFactory for the
RcStyle, under the specified stock ID.
* gtk/gtkstyle.h, gtk/gtkstyle.c: Add a virtual function
render_icon used to derive a GdkPixbuf from a GtkIconSource.
This allows people to theme how prelight, insensitive, etc. are
done.
(gtk_style_lookup_icon_set): Look up a stock ID in the list of
icon factories for a style, and return the resulting
icon set if any.
(gtk_style_render_icon): Render an icon using the render_icon
method in the GtkStyleClass.
* gtk/gtkwidget.h, gtk/gtkwidget.c (gtk_widget_render_icon):
Use the style for a given widget to look up a stock ID, get the
icon set, and render an icon using the render_icon method
of the style
* gtk/gtkstock.h, gtk/gtkstock.c: Header with the GtkStockItem type
(contains information about a stock item), the built-in stock item
IDs, and functions to add/lookup stock items.
* gtk/stock-icons/*: Stock icons that come with GTK
* gtk/gtkbutton.h, gtk/gtkbutton.c (gtk_button_new_stock): Returns
a button based on a GtkStockItem
(gtk_button_new_accel): Takes a uline string and accel group, and
installs the accelerator.
* gtk/gtkimage.h, gtk/gtkimage.c: Make this into a generic
image-display widget.
Diffstat (limited to 'gtk')
59 files changed, 3080 insertions, 142 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 274ecc36ad..173ef56a92 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 \ @@ -75,6 +75,7 @@ #include <gtk/gtkhscale.h> #include <gtk/gtkhscrollbar.h> #include <gtk/gtkhseparator.h> +#include <gtk/gtkiconfactory.h> #include <gtk/gtkimage.h> #include <gtk/gtkimcontext.h> #include <gtk/gtkimmulticontext.h> @@ -116,6 +117,7 @@ #include <gtk/gtksignal.h> #include <gtk/gtksocket.h> #include <gtk/gtkspinbutton.h> +#include <gtk/gtkstock.h> #include <gtk/gtkstyle.h> #include <gtk/gtkstatusbar.h> #include <gtk/gtktable.h> diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c index 802873e008..394688496b 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 a55460e03c..0d8c676d09 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 0000000000..8924df75c5 --- /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 <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <string.h> + +static gpointer parent_class = NULL; + +static void gtk_icon_factory_init (GtkIconFactory *icon_factory); +static void gtk_icon_factory_class_init (GtkIconFactoryClass *klass); +static void gtk_icon_factory_finalize (GObject *object); +static void get_default_icons (GtkIconFactory *icon_factory); + +GType +gtk_icon_factory_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (GtkIconFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_icon_factory_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkIconFactory), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_icon_factory_init, + }; + + object_type = g_type_register_static (G_TYPE_OBJECT, + "GtkIconFactory", + &object_info); + } + + return object_type; +} + +static void +gtk_icon_factory_init (GtkIconFactory *factory) +{ + factory->icons = g_hash_table_new (g_str_hash, g_str_equal); +} + +static void +gtk_icon_factory_class_init (GtkIconFactoryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = gtk_icon_factory_finalize; +} + +static void +free_icon_set (gpointer key, gpointer value, gpointer data) +{ + g_free (key); + gtk_icon_set_unref (value); +} + +static void +gtk_icon_factory_finalize (GObject *object) +{ + GtkIconFactory *factory = GTK_ICON_FACTORY (object); + + g_hash_table_foreach (factory->icons, free_icon_set, NULL); + + g_hash_table_destroy (factory->icons); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +GtkIconFactory* +gtk_icon_factory_new (void) +{ + return GTK_ICON_FACTORY (g_object_new (GTK_TYPE_ICON_FACTORY, NULL)); +} + +void +gtk_icon_factory_add (GtkIconFactory *factory, + const gchar *stock_id, + GtkIconSet *icon_set) +{ + gpointer old_key = NULL; + gpointer old_value = NULL; + + g_return_if_fail (GTK_IS_ICON_FACTORY (factory)); + g_return_if_fail (stock_id != NULL); + g_return_if_fail (icon_set != NULL); + + g_hash_table_lookup_extended (factory->icons, stock_id, + &old_key, &old_value); + + if (old_value == icon_set) + return; + + gtk_icon_set_ref (icon_set); + + /* GHashTable key memory management is so fantastically broken. */ + if (old_key) + g_hash_table_insert (factory->icons, old_key, icon_set); + else + g_hash_table_insert (factory->icons, g_strdup (stock_id), icon_set); + + if (old_value) + gtk_icon_set_unref (old_value); +} + +GtkIconSet * +gtk_icon_factory_lookup (GtkIconFactory *factory, + const gchar *stock_id) +{ + g_return_val_if_fail (GTK_IS_ICON_FACTORY (factory), NULL); + g_return_val_if_fail (stock_id != NULL, NULL); + + return g_hash_table_lookup (factory->icons, stock_id); +} + +static GtkIconFactory *gtk_default_icons = NULL; +static GSList *default_factories = NULL; + +void +gtk_icon_factory_add_default (GtkIconFactory *factory) +{ + g_return_if_fail (GTK_IS_ICON_FACTORY (factory)); + + g_object_ref (G_OBJECT (factory)); + + default_factories = g_slist_prepend (default_factories, factory); +} + +void +gtk_icon_factory_remove_default (GtkIconFactory *factory) +{ + g_return_if_fail (GTK_IS_ICON_FACTORY (factory)); + + default_factories = g_slist_remove (default_factories, factory); + + g_object_unref (G_OBJECT (factory)); +} + +GtkIconSet * +gtk_icon_factory_lookup_default (const gchar *stock_id) +{ + GSList *tmp_list; + + g_return_val_if_fail (stock_id != NULL, NULL); + + tmp_list = default_factories; + while (tmp_list != NULL) + { + GtkIconSet *icon_set = + gtk_icon_factory_lookup (GTK_ICON_FACTORY (tmp_list->data), + stock_id); + + if (icon_set) + return icon_set; + + tmp_list = g_slist_next (tmp_list); + } + + if (gtk_default_icons == NULL) + { + gtk_default_icons = gtk_icon_factory_new (); + + get_default_icons (gtk_default_icons); + } + + return gtk_icon_factory_lookup (gtk_default_icons, stock_id); +} + +static GtkIconSet * +sized_icon_set_from_inline (const guchar *inline_data, + const gchar *size) +{ + GtkIconSet *set; + + GtkIconSource source = { NULL, NULL, 0, 0, NULL, + TRUE, TRUE, FALSE }; + + source.size = size; + + set = gtk_icon_set_new (); + + source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1); + + g_assert (source.pixbuf); + + gtk_icon_set_add_source (set, &source); + + g_object_unref (G_OBJECT (source.pixbuf)); + + return set; +} + +static GtkIconSet * +unsized_icon_set_from_inline (const guchar *inline_data) +{ + GtkIconSet *set; + + /* This icon can be used for any direction/state/size */ + GtkIconSource source = { NULL, NULL, 0, 0, 0, + TRUE, TRUE, TRUE }; + + set = gtk_icon_set_new (); + + source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1); + + g_assert (source.pixbuf); + + gtk_icon_set_add_source (set, &source); + + g_object_unref (G_OBJECT (source.pixbuf)); + + return set; +} + +static void +add_sized (GtkIconFactory *factory, + const guchar *inline_data, + const gchar *size, + const gchar *stock_id) +{ + GtkIconSet *set; + + set = sized_icon_set_from_inline (inline_data, size); + + gtk_icon_factory_add (factory, stock_id, set); + + gtk_icon_set_unref (set); +} + +static void +add_unsized (GtkIconFactory *factory, + const guchar *inline_data, + const gchar *stock_id) +{ + GtkIconSet *set; + + set = unsized_icon_set_from_inline (inline_data); + + gtk_icon_factory_add (factory, stock_id, set); + + gtk_icon_set_unref (set); +} + +static void +get_default_icons (GtkIconFactory *factory) +{ + /* KEEP IN SYNC with gtkstock.c */ + + add_sized (factory, dialog_error, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_ERROR); + add_sized (factory, dialog_info, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_INFO); + add_sized (factory, dialog_question, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_QUESTION); + add_sized (factory, dialog_warning, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_WARNING); + + add_sized (factory, stock_button_apply, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_APPLY); + add_sized (factory, stock_button_ok, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_OK); + add_sized (factory, stock_button_cancel, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_CANCEL); + add_sized (factory, stock_button_close, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_CLOSE); + add_sized (factory, stock_button_yes, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_YES); + add_sized (factory, stock_button_no, GTK_ICON_SIZE_BUTTON, GTK_STOCK_BUTTON_NO); + + add_unsized (factory, stock_close, GTK_STOCK_CLOSE); + add_unsized (factory, stock_exit, GTK_STOCK_QUIT); + add_unsized (factory, stock_help, GTK_STOCK_HELP); + add_unsized (factory, stock_new, GTK_STOCK_NEW); + add_unsized (factory, stock_open, GTK_STOCK_OPEN); + add_unsized (factory, stock_save, GTK_STOCK_SAVE); +} + +/* Sizes */ + +static GHashTable *icon_sizes = NULL; + +typedef struct _IconSize IconSize; + +struct _IconSize +{ + gchar *name; + + gboolean is_alias; + + union + { + gchar *target; + struct + { + gint width; + gint height; + } size; + } d; +}; + +static IconSize* +icon_size_new (const gchar *name) +{ + IconSize *is; + + is = g_new0 (IconSize, 1); + + is->name = g_strdup (name); + + return is; +} + +static void +icon_size_free (IconSize *is) +{ + g_free (is->name); + + if (is->is_alias) + g_free (is->d.target); + + g_free (is); +} + +static void +icon_size_insert (IconSize *is) +{ + gpointer old_key, old_value; + + /* Remove old ones */ + if (g_hash_table_lookup_extended (icon_sizes, + is->name, + &old_key, &old_value)) + { + g_hash_table_remove (icon_sizes, is->name); + icon_size_free (old_value); + } + + g_hash_table_insert (icon_sizes, + is->name, is); + +} + +static IconSize* +icon_size_lookup (const gchar *name) +{ + IconSize *is; + + is = g_hash_table_lookup (icon_sizes, + name); + + while (is && is->is_alias) + { + is = g_hash_table_lookup (icon_sizes, + is->d.target); + + } + + return is; +} + +static void +icon_size_add (const gchar *name, + gint width, + gint height) +{ + IconSize *is; + + is = icon_size_new (name); + is->d.size.width = width; + is->d.size.height = height; + + icon_size_insert (is); +} + +static void +icon_alias_add (const gchar *name, + const gchar *target) +{ + IconSize *is; + + is = icon_size_new (name); + is->is_alias = TRUE; + + is->d.target = g_strdup (target); + + icon_size_insert (is); +} + +static void +init_icon_sizes (void) +{ + if (icon_sizes == NULL) + { + IconSize *is; + + icon_sizes = g_hash_table_new (g_str_hash, g_str_equal); + + icon_size_add (GTK_ICON_SIZE_MENU, 16, 16); + icon_size_add (GTK_ICON_SIZE_BUTTON, 24, 24); + icon_size_add (GTK_ICON_SIZE_SMALL_TOOLBAR, 18, 18); + icon_size_add (GTK_ICON_SIZE_LARGE_TOOLBAR, 24, 24); + icon_size_add (GTK_ICON_SIZE_DIALOG, 48, 48); + } +} + +gboolean +gtk_icon_size_lookup (const gchar *alias, + gint *widthp, + gint *heightp) +{ + IconSize *is; + + g_return_val_if_fail (alias != NULL, FALSE); + + init_icon_sizes (); + + is = icon_size_lookup (alias); + + if (is == NULL) + return FALSE; + + if (widthp) + *widthp = is->d.size.width; + + if (heightp) + *heightp = is->d.size.height; + + return TRUE; +} + +void +gtk_icon_size_register (const gchar *alias, + gint width, + gint height) +{ + gpointer old_key, old_value; + + g_return_if_fail (alias != NULL); + g_return_if_fail (width > 0); + g_return_if_fail (height > 0); + + init_icon_sizes (); + + icon_size_add (alias, width, height); +} + +void +gtk_icon_size_register_alias (const gchar *alias, + const gchar *target) +{ + g_return_if_fail (alias != NULL); + g_return_if_fail (target != NULL); + + init_icon_sizes (); + + icon_alias_add (alias, target); +} + +/* Icon Set */ + + +/* Clear icon set contents, drop references to all contained + * GdkPixbuf objects and forget all GtkIconSources. Used to + * recycle an icon set. + */ +static void gtk_icon_set_clear (GtkIconSet *icon_set); + +static GdkPixbuf *find_in_cache (GtkIconSet *icon_set, + GtkStyle *style, + GtkTextDirection direction, + GtkStateType state, + const gchar *size); +static void add_to_cache (GtkIconSet *icon_set, + GtkStyle *style, + GtkTextDirection direction, + GtkStateType state, + const gchar *size, + GdkPixbuf *pixbuf); +static void clear_cache (GtkIconSet *icon_set, + gboolean style_detach); +static GSList* copy_cache (GtkIconSet *icon_set, + GtkIconSet *copy_recipient); +static void attach_to_style (GtkIconSet *icon_set, + GtkStyle *style); +static void detach_from_style (GtkIconSet *icon_set, + GtkStyle *style); +static void style_dnotify (gpointer data); + +struct _GtkIconSet +{ + guint ref_count; + + GSList *sources; + + /* Cache of the last few rendered versions of the icon. */ + GSList *cache; + + guint cache_size; + + guint cache_serial; +}; + +static guint cache_serial = 0; + +GtkIconSet* +gtk_icon_set_new (void) +{ + GtkIconSet *icon_set; + + icon_set = g_new (GtkIconSet, 1); + + icon_set->ref_count = 1; + icon_set->sources = NULL; + icon_set->cache = NULL; + icon_set->cache_size = 0; + icon_set->cache_serial = cache_serial; + + return icon_set; +} + +GtkIconSet* +gtk_icon_set_ref (GtkIconSet *icon_set) +{ + g_return_val_if_fail (icon_set != NULL, NULL); + g_return_val_if_fail (icon_set->ref_count > 0, NULL); + + icon_set->ref_count += 1; + + return icon_set; +} + +void +gtk_icon_set_unref (GtkIconSet *icon_set) +{ + g_return_if_fail (icon_set != NULL); + g_return_if_fail (icon_set->ref_count > 0); + + icon_set->ref_count -= 1; + + if (icon_set->ref_count == 0) + { + GSList *tmp_list = icon_set->sources; + while (tmp_list != NULL) + { + gtk_icon_source_free (tmp_list->data); + + tmp_list = g_slist_next (tmp_list); + } + + clear_cache (icon_set, TRUE); + + g_free (icon_set); + } +} + +GtkIconSet* +gtk_icon_set_copy (GtkIconSet *icon_set) +{ + GtkIconSet *copy; + GSList *tmp_list; + + copy = gtk_icon_set_new (); + + tmp_list = icon_set->sources; + while (tmp_list != NULL) + { + copy->sources = g_slist_prepend (copy->sources, + gtk_icon_source_copy (tmp_list->data)); + + tmp_list = g_slist_next (tmp_list); + } + + copy->sources = g_slist_reverse (copy->sources); + + copy->cache = copy_cache (icon_set, copy); + copy->cache_size = icon_set->cache_size; + copy->cache_serial = icon_set->cache_serial; + + return copy; +} + + +static gboolean +sizes_equivalent (const gchar *rhs, const gchar *lhs) +{ + gint r_w, r_h, l_w, l_h; + + gtk_icon_size_lookup (rhs, &r_w, &r_h); + gtk_icon_size_lookup (lhs, &l_w, &l_h); + + return r_w == l_w && r_h == l_h; +} + +static GtkIconSource* +find_and_prep_icon_source (GtkIconSet *icon_set, + GtkTextDirection direction, + GtkStateType state, + const gchar *size) +{ + GtkIconSource *source; + GSList *tmp_list; + + + /* We need to find the best icon source. Direction matters more + * than state, state matters more than size. icon_set->sources + * is sorted according to wildness, so if we take the first + * match we find it will be the least-wild match (if there are + * multiple matches for a given "wildness" then the RC file contained + * dumb stuff, and we end up with an arbitrary matching source) + */ + + source = NULL; + tmp_list = icon_set->sources; + while (tmp_list != NULL) + { + GtkIconSource *s = tmp_list->data; + + if ((s->any_direction || (s->direction == direction)) && + (s->any_state || (s->state == state)) && + (s->any_size || (sizes_equivalent (size, s->size)))) + { + source = s; + break; + } + + tmp_list = g_slist_next (tmp_list); + } + + if (source == NULL) + return NULL; + + if (source->pixbuf == NULL) + { + gchar *full; + + g_assert (source->filename); + + if (*source->filename != G_DIR_SEPARATOR) + full = gtk_rc_find_pixmap_in_path (NULL, source->filename); + else + full = g_strdup (source->filename); + + source->pixbuf = gdk_pixbuf_new_from_file (full); + + g_free (full); + + if (source->pixbuf == NULL) + { + /* Remove this icon source so we don't keep trying to + * load it. + */ + g_warning ("Failed to load icon '%s'", source->filename); + + icon_set->sources = g_slist_remove (icon_set->sources, source); + + gtk_icon_source_free (source); + + /* Try to fall back to other sources */ + if (icon_set->sources != NULL) + return find_and_prep_icon_source (icon_set, + direction, + state, + size); + else + return NULL; + } + } + + return source; +} + +GdkPixbuf* +gtk_icon_set_render_icon (GtkIconSet *icon_set, + GtkStyle *style, + GtkTextDirection direction, + GtkStateType state, + const gchar *size, + GtkWidget *widget, + const char *detail) +{ + GdkPixbuf *icon; + GtkIconSource *source; + + /* FIXME conceivably, everywhere this function + * returns NULL, we should return some default + * dummy icon like a question mark or the image icon + * from netscape + */ + + g_return_val_if_fail (icon_set != NULL, NULL); + g_return_val_if_fail (GTK_IS_STYLE (style), NULL); + + if (icon_set->sources == NULL) + return NULL; + + icon = find_in_cache (icon_set, style, direction, + state, size); + + if (icon) + { + g_object_ref (G_OBJECT (icon)); + return icon; + } + + + source = find_and_prep_icon_source (icon_set, direction, state, size); + + if (source == NULL) + return NULL; + + g_assert (source->pixbuf != NULL); + + icon = gtk_style_render_icon (style, + source, + direction, + state, + size, + widget, + detail); + + if (icon == NULL) + { + g_warning ("Theme engine failed to render icon"); + return NULL; + } + + add_to_cache (icon_set, style, direction, state, size, icon); + + return icon; +} + +/* Order sources by their "wildness", so that "wilder" sources are + * greater than "specific" sources; for determining ordering, + * direction beats state beats size. + */ + +static int +icon_source_compare (gconstpointer ap, gconstpointer bp) +{ + const GtkIconSource *a = ap; + const GtkIconSource *b = bp; + + if (!a->any_direction && b->any_direction) + return -1; + else if (a->any_direction && !b->any_direction) + return 1; + else if (!a->any_state && b->any_state) + return -1; + else if (a->any_state && !b->any_state) + return 1; + else if (!a->any_size && b->any_size) + return -1; + else if (a->any_size && !b->any_size) + return 1; + else + return 0; +} + +void +gtk_icon_set_add_source (GtkIconSet *icon_set, + const GtkIconSource *source) +{ + g_return_if_fail (icon_set != NULL); + g_return_if_fail (source != NULL); + + if (source->pixbuf == NULL && + source->filename == NULL) + { + g_warning ("Useless GtkIconSource contains NULL filename and pixbuf"); + return; + } + + icon_set->sources = g_slist_insert_sorted (icon_set->sources, + gtk_icon_source_copy (source), + icon_source_compare); +} + +GtkIconSource * +gtk_icon_source_copy (const GtkIconSource *source) +{ + GtkIconSource *copy; + + g_return_val_if_fail (source != NULL, NULL); + + copy = g_new (GtkIconSource, 1); + + *copy = *source; + + copy->filename = g_strdup (source->filename); + copy->size = g_strdup (source->size); + if (copy->pixbuf) + g_object_ref (G_OBJECT (copy->pixbuf)); + + return copy; +} + +void +gtk_icon_source_free (GtkIconSource *source) +{ + g_return_if_fail (source != NULL); + + g_free ((char*) source->filename); + g_free ((char*) source->size); + if (source->pixbuf) + g_object_unref (G_OBJECT (source->pixbuf)); + + g_free (source); +} + +void +gtk_icon_set_clear (GtkIconSet *icon_set) +{ + GSList *tmp_list; + + g_return_if_fail (icon_set != NULL); + + tmp_list = icon_set->sources; + while (tmp_list != NULL) + { + gtk_icon_source_free (tmp_list->data); + + tmp_list = g_slist_next (tmp_list); + } + + clear_cache (icon_set, TRUE); +} + +/* Note that the logical maximum is 20 per GtkTextDirection, so we could + * eventually set this to >20 to never throw anything out. + */ +#define NUM_CACHED_ICONS 8 + +typedef struct _CachedIcon CachedIcon; + +struct _CachedIcon +{ + /* These must all match to use the cached pixbuf. + * If any don't match, we must re-render the pixbuf. + */ + GtkStyle *style; + GtkTextDirection direction; + GtkStateType state; + gchar *size; + + GdkPixbuf *pixbuf; +}; + +static void +ensure_cache_up_to_date (GtkIconSet *icon_set) +{ + if (icon_set->cache_serial != cache_serial) + clear_cache (icon_set, TRUE); +} + +static void +cached_icon_free (CachedIcon *icon) +{ + g_free (icon->size); + g_object_unref (G_OBJECT (icon->pixbuf)); + + g_free (icon); +} + +static GdkPixbuf * +find_in_cache (GtkIconSet *icon_set, + GtkStyle *style, + GtkTextDirection direction, + GtkStateType state, + const gchar *size) +{ + GSList *tmp_list; + GSList *prev; + + ensure_cache_up_to_date (icon_set); + + prev = NULL; + tmp_list = icon_set->cache; + while (tmp_list != NULL) + { + CachedIcon *icon = tmp_list->data; + + if (icon->style == style && + icon->direction == direction && + icon->state == state && + strcmp (icon->size, size) == 0) + { + if (prev) + { + /* Move this icon to the front of the list. */ + prev->next = tmp_list->next; + tmp_list->next = icon_set->cache; + icon_set->cache = tmp_list; + } + + return icon->pixbuf; + } + + prev = tmp_list; + tmp_list = g_slist_next (tmp_list); + } + + return NULL; +} + +static void +add_to_cache (GtkIconSet *icon_set, + GtkStyle *style, + GtkTextDirection direction, + GtkStateType state, + const gchar *size, + GdkPixbuf *pixbuf) +{ + CachedIcon *icon; + + ensure_cache_up_to_date (icon_set); + + g_object_ref (G_OBJECT (pixbuf)); + + /* We have to ref the style, since if the style was finalized + * its address could be reused by another style, creating a + * really weird bug + */ + + if (style) + g_object_ref (G_OBJECT (style)); + + + icon = g_new (CachedIcon, 1); + icon_set->cache = g_slist_prepend (icon_set->cache, icon); + + icon->style = style; + icon->direction = direction; + icon->state = state; + icon->size = g_strdup (size); + icon->pixbuf = pixbuf; + + if (icon->style) + attach_to_style (icon_set, icon->style); + + if (icon_set->cache_size >= NUM_CACHED_ICONS) + { + /* Remove oldest item in the cache */ + + GSList *tmp_list; + + tmp_list = icon_set->cache; + + /* Find next-to-last link */ + g_assert (NUM_CACHED_ICONS > 2); + while (tmp_list->next->next) + tmp_list = tmp_list->next; + + g_assert (tmp_list != NULL); + g_assert (tmp_list->next != NULL); + g_assert (tmp_list->next->next == NULL); + + /* Free the last icon */ + icon = tmp_list->next->data; + + g_slist_free (tmp_list->next); + tmp_list->next = NULL; + + cached_icon_free (icon); + } +} + +static void +clear_cache (GtkIconSet *icon_set, + gboolean style_detach) +{ + GSList *tmp_list; + GtkStyle *last_style = NULL; + + tmp_list = icon_set->cache; + while (tmp_list != NULL) + { + CachedIcon *icon = tmp_list->data; + + if (style_detach) + { + /* simple optimization for the case where the cache + * contains contiguous icons from the same style. + * it's safe to call detach_from_style more than + * once on the same style though. + */ + if (last_style != icon->style) + { + detach_from_style (icon_set, icon->style); + last_style = icon->style; + } + } + + cached_icon_free (icon); + + tmp_list = g_slist_next (tmp_list); + } + + g_slist_free (icon_set->cache); + icon_set->cache = NULL; + icon_set->cache_size = 0; +} + +static GSList* +copy_cache (GtkIconSet *icon_set, + GtkIconSet *copy_recipient) +{ + GSList *tmp_list; + GSList *copy = NULL; + + ensure_cache_up_to_date (icon_set); + + tmp_list = icon_set->cache; + while (tmp_list != NULL) + { + CachedIcon *icon = tmp_list->data; + CachedIcon *icon_copy = g_new (CachedIcon, 1); + + *icon_copy = *icon; + + if (icon_copy->style) + attach_to_style (copy_recipient, icon_copy->style); + + g_object_ref (G_OBJECT (icon_copy->pixbuf)); + + icon_copy->size = g_strdup (icon->size); + + copy = g_slist_prepend (copy, icon_copy); + + tmp_list = g_slist_next (tmp_list); + } + + return g_slist_reverse (copy); +} + +static void +attach_to_style (GtkIconSet *icon_set, + GtkStyle *style) +{ + GHashTable *table; + + table = g_object_get_qdata (G_OBJECT (style), + g_quark_try_string ("gtk-style-icon-sets")); + + if (table == NULL) + { + table = g_hash_table_new (NULL, NULL); + g_object_set_qdata_full (G_OBJECT (style), + g_quark_from_static_string ("gtk-style-icon-sets"), + table, + style_dnotify); + } + + g_hash_table_insert (table, icon_set, icon_set); +} + +static void +detach_from_style (GtkIconSet *icon_set, + GtkStyle *style) +{ + GHashTable *table; + + table = g_object_get_qdata (G_OBJECT (style), + g_quark_try_string ("gtk-style-icon-sets")); + + if (table != NULL) + g_hash_table_remove (table, icon_set); +} + +static void +iconsets_foreach (gpointer key, + gpointer value, + gpointer user_data) +{ + GtkIconSet *icon_set = key; + + /* We only need to remove cache entries for the given style; + * but that complicates things because in destroy notify + * we don't know which style got destroyed, and 95% of the + * time all cache entries will have the same style, + * so this is faster anyway. + */ + + clear_cache (icon_set, FALSE); +} + +static void +style_dnotify (gpointer data) +{ + GHashTable *table = data; + + g_hash_table_foreach (table, iconsets_foreach, NULL); + + g_hash_table_destroy (table); +} + +/* This allows the icon set to detect that its cache is out of date. */ +void +_gtk_icon_set_invalidate_caches (void) +{ + ++cache_serial; +} diff --git a/gtk/gtkiconfactory.h b/gtk/gtkiconfactory.h new file mode 100644 index 0000000000..357e37eb7c --- /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 <gdk/gdk.h> +#include <gtk/gtkrc.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _GtkIconFactoryClass GtkIconFactoryClass; + +#define GTK_TYPE_ICON_FACTORY (gtk_icon_factory_get_type ()) +#define GTK_ICON_FACTORY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_ICON_FACTORY, GtkIconFactory)) +#define GTK_ICON_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_ICON_FACTORY, GtkIconFactoryClass)) +#define GTK_IS_ICON_FACTORY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GTK_TYPE_ICON_FACTORY)) +#define GTK_IS_ICON_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_ICON_FACTORY)) +#define GTK_ICON_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ICON_FACTORY, GtkIconFactoryClass)) + +struct _GtkIconFactory +{ + GObject parent_instance; + + GHashTable *icons; +}; + +struct _GtkIconFactoryClass +{ + GObjectClass parent_class; + + +}; + +GType gtk_icon_factory_get_type (void); +GtkIconFactory* gtk_icon_factory_new (void); +void gtk_icon_factory_add (GtkIconFactory *factory, + const gchar *stock_id, + GtkIconSet *icon_set); +GtkIconSet* gtk_icon_factory_lookup (GtkIconFactory *factory, + const gchar *stock_id); + +/* Manage the default icon factory stack */ + +void gtk_icon_factory_add_default (GtkIconFactory *factory); +void gtk_icon_factory_remove_default (GtkIconFactory *factory); +GtkIconSet* gtk_icon_factory_lookup_default (const gchar *stock_id); + +/* Get preferred real size from registered semantic size. Note that + * themes SHOULD use this size, but they aren't required to; for size + * requests and such, you should get the actual pixbuf from the icon + * set and see what size was rendered. + * + * This function is intended for people who are scaling icons, + * rather than for people who are displaying already-scaled icons. + * That is, if you are displaying an icon, you should get the + * size from the rendered pixbuf, not from here. + */ + +gboolean gtk_icon_size_lookup (const gchar *alias, + gint *width, + gint *height); +void gtk_icon_size_register (const gchar *alias, + gint width, + gint height); +void gtk_icon_size_register_alias (const gchar *alias, + const gchar *target); + + +/* Standard sizes */ + +#define GTK_ICON_SIZE_MENU "gtk-menu" +#define GTK_ICON_SIZE_SMALL_TOOLBAR "gtk-small-toolbar" +#define GTK_ICON_SIZE_LARGE_TOOLBAR "gtk-large-toolbar" +#define GTK_ICON_SIZE_BUTTON "gtk-button" +#define GTK_ICON_SIZE_DIALOG "gtk-dialog" + +/* Icon sets */ + +GtkIconSet* gtk_icon_set_new (void); + +GtkIconSet* gtk_icon_set_ref (GtkIconSet *icon_set); +void gtk_icon_set_unref (GtkIconSet *icon_set); +GtkIconSet* gtk_icon_set_copy (GtkIconSet *icon_set); + +/* Get one of the icon variants in the set, creating the variant if + * necessary. + */ +GdkPixbuf* gtk_icon_set_render_icon (GtkIconSet *icon_set, + GtkStyle *style, + GtkTextDirection direction, + GtkStateType state, + const gchar *size, + GtkWidget *widget, + const char *detail); + + +void gtk_icon_set_add_source (GtkIconSet *icon_set, + const GtkIconSource *source); + +/* INTERNAL */ +void _gtk_icon_set_invalidate_caches (void); + +struct _GtkIconSource +{ + /* Either filename or pixbuf can be NULL. If both are non-NULL, + * the pixbuf is assumed to be the already-loaded contents of the + * file. + */ + gchar *filename; + GdkPixbuf *pixbuf; + + GtkTextDirection direction; + GtkStateType state; + gchar *size; + + /* If TRUE, then the parameter is wildcarded, and the above + * fields should be ignored. If FALSE, the parameter is + * specified, and the above fields should be valid. + */ + guint any_direction : 1; + guint any_state : 1; + guint any_size : 1; +}; + + +GtkIconSource* gtk_icon_source_copy (const GtkIconSource *source); +void gtk_icon_source_free (GtkIconSource *source); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GTK_ICON_FACTORY_H__ */ diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c index 01154d9293..504b2a2e11 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 147a606463..266d032e67 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 495fbbd411..324e8d3a54 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 a1a98f2278..0b37039311 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 0000000000..ecb3079736 --- /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 <gdk/gdkkeysyms.h> + +static GHashTable *stock_hash = NULL; +static void init_stock_hash (void); + +static void +real_add (const GtkStockItem *items, + guint n_items, + gboolean copy) +{ + int i; + + init_stock_hash (); + + if (n_items == 0) + return; + + i = 0; + while (i < n_items) + { + gpointer old_key, old_value; + const GtkStockItem *item = &items[i]; + if (copy) + item = gtk_stock_item_copy (item); + + if (g_hash_table_lookup_extended (stock_hash, item->stock_id, + &old_key, &old_value)) + { + g_hash_table_remove (stock_hash, old_key); + gtk_stock_item_free (old_value); + } + + g_hash_table_insert (stock_hash, + (gchar*)item->stock_id, (GtkStockItem*)item); + + ++i; + } +} + +void +gtk_stock_add (const GtkStockItem *items, + guint n_items) +{ + g_return_if_fail (items != NULL); + + real_add (items, n_items, TRUE); +} + +void +gtk_stock_add_static (const GtkStockItem *items, + guint n_items) +{ + g_return_if_fail (items != NULL); + + real_add (items, n_items, FALSE); +} + +gboolean +gtk_stock_lookup (const gchar *stock_id, + GtkStockItem *item) +{ + const GtkStockItem *found; + + g_return_val_if_fail (stock_id != NULL, FALSE); + g_return_val_if_fail (item != NULL, FALSE); + + init_stock_hash (); + + found = g_hash_table_lookup (stock_hash, stock_id); + + if (found) + { + *item = *found; + if (item->label) + item->label = dgettext (item->translation_domain, item->label); + } + + return found != NULL; +} + +static void +listify_foreach (gpointer key, gpointer value, gpointer data) +{ + GSList **list = data; + + *list = g_slist_prepend (*list, value); +} + +static GSList * +g_hash_table_get_values (GHashTable *table) +{ + GSList *list = NULL; + + g_hash_table_foreach (table, listify_foreach, &list); + + return list; +} + +GSList * +gtk_stock_list_items (void) +{ + init_stock_hash (); + + return g_hash_table_get_values (stock_hash); +} + +GtkStockItem * +gtk_stock_item_copy (const GtkStockItem *item) +{ + GtkStockItem *copy; + + g_return_val_if_fail (item != NULL, NULL); + + copy = g_new (GtkStockItem, 1); + + *copy = *item; + + copy->stock_id = g_strdup (item->stock_id); + copy->label = g_strdup (item->label); + copy->translation_domain = g_strdup (item->translation_domain); + + return copy; +} + +void +gtk_stock_item_free (GtkStockItem *item) +{ + g_return_if_fail (item != NULL); + + g_free ((gchar*)item->stock_id); + g_free ((gchar*)item->label); + g_free ((gchar*)item->translation_domain); + + g_free (item); +} + +static GtkStockItem builtin_items [] = +{ + /* KEEP IN SYNC with gtkiconfactory.c stock icons */ + + { GTK_STOCK_DIALOG_INFO, N_("Information"), 0, 0, GETTEXT_PACKAGE }, + { GTK_STOCK_DIALOG_WARNING, N_("Warning"), 0, 0, GETTEXT_PACKAGE }, + { GTK_STOCK_DIALOG_ERROR, N_("Error"), 0, 0, GETTEXT_PACKAGE }, + { GTK_STOCK_DIALOG_QUESTION, N_("Question"), 0, 0, GETTEXT_PACKAGE }, + + { GTK_STOCK_BUTTON_APPLY, N_("_Apply"), 0, 0, GETTEXT_PACKAGE }, + { GTK_STOCK_BUTTON_OK, N_("OK"), 0, 0, GETTEXT_PACKAGE }, + { GTK_STOCK_BUTTON_CANCEL, N_("Cancel"), 0, 0, GETTEXT_PACKAGE }, + { GTK_STOCK_BUTTON_CLOSE, N_("_Close"), 0, 0, GETTEXT_PACKAGE }, + { GTK_STOCK_BUTTON_YES, N_("_Yes"), 0, 0, GETTEXT_PACKAGE }, + { GTK_STOCK_BUTTON_NO, N_("_No"), 0, 0, GETTEXT_PACKAGE }, + + { GTK_STOCK_CLOSE, N_("Close"), GDK_CONTROL_MASK, 'w', GETTEXT_PACKAGE }, + { GTK_STOCK_QUIT, N_("Quit"), GDK_CONTROL_MASK, 'q', GETTEXT_PACKAGE }, + { GTK_STOCK_HELP, N_("Help"), GDK_CONTROL_MASK, 'h', GETTEXT_PACKAGE }, + { GTK_STOCK_NEW, N_("New"), GDK_CONTROL_MASK, 'n', GETTEXT_PACKAGE }, + { GTK_STOCK_OPEN, N_("Open"), GDK_CONTROL_MASK, 'o', GETTEXT_PACKAGE }, + { GTK_STOCK_SAVE, N_("Save"), GDK_CONTROL_MASK, 's', GETTEXT_PACKAGE } +}; + +static void +init_stock_hash (void) +{ + if (stock_hash == NULL) + { + stock_hash = g_hash_table_new (g_str_hash, g_str_equal); + + gtk_stock_add_static (builtin_items, G_N_ELEMENTS (builtin_items)); + } +} diff --git a/gtk/gtkstock.h b/gtk/gtkstock.h new file mode 100644 index 0000000000..02b51ff979 --- /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 <gdk/gdk.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _GtkStockItem GtkStockItem; + +struct _GtkStockItem +{ + gchar *stock_id; + gchar *label; + GdkModifierType modifier; + guint keyval; + gchar *translation_domain; +}; + +void gtk_stock_add (const GtkStockItem *item, + guint n_items); +void gtk_stock_add_static (const GtkStockItem *item, + guint n_items); +gboolean gtk_stock_lookup (const gchar *stock_id, + GtkStockItem *item); + +/* Should free the list, but DO NOT modify the items in the list. + * This function is only useful for GUI builders and such. + */ +GSList* gtk_stock_list_items (void); + +GtkStockItem *gtk_stock_item_copy (const GtkStockItem *item); +void gtk_stock_item_free (GtkStockItem *item); + + +/* Stock IDs */ +#define GTK_STOCK_DIALOG_INFO "gtk-dialog-info" +#define GTK_STOCK_DIALOG_WARNING "gtk-dialog-warning" +#define GTK_STOCK_DIALOG_ERROR "gtk-dialog-error" +#define GTK_STOCK_DIALOG_QUESTION "gtk-dialog-question" + +#define GTK_STOCK_BUTTON_APPLY "gtk-button-apply" +#define GTK_STOCK_BUTTON_OK "gtk-button-ok" +#define GTK_STOCK_BUTTON_CANCEL "gtk-button-cancel" +#define GTK_STOCK_BUTTON_CLOSE "gtk-button-close" +#define GTK_STOCK_BUTTON_YES "gtk-button-yes" +#define GTK_STOCK_BUTTON_NO "gtk-button-no" + +#define GTK_STOCK_CLOSE "gtk-close" +#define GTK_STOCK_QUIT "gtk-quit" +#define GTK_STOCK_HELP "gtk-help" +#define GTK_STOCK_NEW "gtk-new" +#define GTK_STOCK_OPEN "gtk-open" +#define GTK_STOCK_SAVE "gtk-save" + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_STOCK_H__ */ diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c index a7c1b6880d..087bcb12ed 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 e23203a1c5..8427127307 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 bd084de24d..ed19d79e4f 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -28,6 +28,7 @@ #include <string.h> #include <locale.h> #include "gtkcontainer.h" +#include "gtkiconfactory.h" #include "gtkmain.h" #include "gtkrc.h" #include "gtkselection.h" @@ -3541,6 +3542,37 @@ gtk_widget_create_pango_layout (GtkWidget *widget, return layout; } +GdkPixbuf* +gtk_widget_render_stock_icon (GtkWidget *widget, + const gchar *stock_id, + const gchar *size, + const gchar *detail) +{ + GtkIconSet *icon_set; + GdkPixbuf *retval; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + g_return_val_if_fail (stock_id != NULL, NULL); + g_return_val_if_fail (size != NULL, NULL); + + gtk_widget_ensure_style (widget); + + icon_set = gtk_style_lookup_icon_set (widget->style, stock_id); + + if (icon_set == NULL) + return NULL; + + retval = gtk_icon_set_render_icon (icon_set, + widget->style, + gtk_widget_get_direction (widget), + GTK_WIDGET_STATE (widget), + size, + widget, + detail); + + return retval; +} + /************************************************************* * gtk_widget_set_parent_window: * Set a non default parent window for widget diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 4e2a87e7f6..b55a2a1b99 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 0000000000..3bf0d50741 --- /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 Binary files differnew file mode 100644 index 0000000000..cc7830e26e --- /dev/null +++ b/gtk/stock-icons/dialog_error.png diff --git a/gtk/stock-icons/dialog_error_48.png b/gtk/stock-icons/dialog_error_48.png Binary files differnew file mode 100644 index 0000000000..cc7830e26e --- /dev/null +++ b/gtk/stock-icons/dialog_error_48.png diff --git a/gtk/stock-icons/dialog_info.png b/gtk/stock-icons/dialog_info.png Binary files differnew file mode 100644 index 0000000000..757e599d29 --- /dev/null +++ b/gtk/stock-icons/dialog_info.png diff --git a/gtk/stock-icons/dialog_info_48.png b/gtk/stock-icons/dialog_info_48.png Binary files differnew file mode 100644 index 0000000000..757e599d29 --- /dev/null +++ b/gtk/stock-icons/dialog_info_48.png diff --git a/gtk/stock-icons/dialog_question.png b/gtk/stock-icons/dialog_question.png Binary files differnew file mode 100644 index 0000000000..2afbc7a873 --- /dev/null +++ b/gtk/stock-icons/dialog_question.png diff --git a/gtk/stock-icons/dialog_question_48.png b/gtk/stock-icons/dialog_question_48.png Binary files differnew file mode 100644 index 0000000000..2afbc7a873 --- /dev/null +++ b/gtk/stock-icons/dialog_question_48.png diff --git a/gtk/stock-icons/dialog_warning.png b/gtk/stock-icons/dialog_warning.png Binary files differnew file mode 100644 index 0000000000..d6f2306dba --- /dev/null +++ b/gtk/stock-icons/dialog_warning.png diff --git a/gtk/stock-icons/dialog_warning_48.png b/gtk/stock-icons/dialog_warning_48.png Binary files differnew file mode 100644 index 0000000000..d6f2306dba --- /dev/null +++ b/gtk/stock-icons/dialog_warning_48.png diff --git a/gtk/stock-icons/stock_apply_20.png b/gtk/stock-icons/stock_apply_20.png Binary files differnew file mode 100644 index 0000000000..58a64cfc48 --- /dev/null +++ b/gtk/stock-icons/stock_apply_20.png diff --git a/gtk/stock-icons/stock_button_apply.png b/gtk/stock-icons/stock_button_apply.png Binary files differnew file mode 100644 index 0000000000..58a64cfc48 --- /dev/null +++ b/gtk/stock-icons/stock_button_apply.png diff --git a/gtk/stock-icons/stock_button_apply_24.png b/gtk/stock-icons/stock_button_apply_24.png Binary files differnew file mode 100644 index 0000000000..58a64cfc48 --- /dev/null +++ b/gtk/stock-icons/stock_button_apply_24.png diff --git a/gtk/stock-icons/stock_button_cancel.png b/gtk/stock-icons/stock_button_cancel.png Binary files differnew file mode 100644 index 0000000000..2d7c194c8c --- /dev/null +++ b/gtk/stock-icons/stock_button_cancel.png diff --git a/gtk/stock-icons/stock_button_cancel_24.png b/gtk/stock-icons/stock_button_cancel_24.png Binary files differnew file mode 100644 index 0000000000..2d7c194c8c --- /dev/null +++ b/gtk/stock-icons/stock_button_cancel_24.png diff --git a/gtk/stock-icons/stock_button_close.png b/gtk/stock-icons/stock_button_close.png Binary files differnew file mode 100644 index 0000000000..b900bdf3bd --- /dev/null +++ b/gtk/stock-icons/stock_button_close.png diff --git a/gtk/stock-icons/stock_button_close_24.png b/gtk/stock-icons/stock_button_close_24.png Binary files differnew file mode 100644 index 0000000000..b900bdf3bd --- /dev/null +++ b/gtk/stock-icons/stock_button_close_24.png diff --git a/gtk/stock-icons/stock_button_no.png b/gtk/stock-icons/stock_button_no.png Binary files differnew file mode 100644 index 0000000000..6478554f62 --- /dev/null +++ b/gtk/stock-icons/stock_button_no.png diff --git a/gtk/stock-icons/stock_button_no_24.png b/gtk/stock-icons/stock_button_no_24.png Binary files differnew file mode 100644 index 0000000000..6478554f62 --- /dev/null +++ b/gtk/stock-icons/stock_button_no_24.png diff --git a/gtk/stock-icons/stock_button_ok.png b/gtk/stock-icons/stock_button_ok.png Binary files differnew file mode 100644 index 0000000000..f1c33753f3 --- /dev/null +++ b/gtk/stock-icons/stock_button_ok.png diff --git a/gtk/stock-icons/stock_button_ok_24.png b/gtk/stock-icons/stock_button_ok_24.png Binary files differnew file mode 100644 index 0000000000..f1c33753f3 --- /dev/null +++ b/gtk/stock-icons/stock_button_ok_24.png diff --git a/gtk/stock-icons/stock_button_yes.png b/gtk/stock-icons/stock_button_yes.png Binary files differnew file mode 100644 index 0000000000..e061e7f17c --- /dev/null +++ b/gtk/stock-icons/stock_button_yes.png diff --git a/gtk/stock-icons/stock_button_yes_24.png b/gtk/stock-icons/stock_button_yes_24.png Binary files differnew file mode 100644 index 0000000000..e061e7f17c --- /dev/null +++ b/gtk/stock-icons/stock_button_yes_24.png diff --git a/gtk/stock-icons/stock_cancel_20.png b/gtk/stock-icons/stock_cancel_20.png Binary files differnew file mode 100644 index 0000000000..2d7c194c8c --- /dev/null +++ b/gtk/stock-icons/stock_cancel_20.png diff --git a/gtk/stock-icons/stock_close.png b/gtk/stock-icons/stock_close.png Binary files differnew file mode 100644 index 0000000000..4338bdc3f6 --- /dev/null +++ b/gtk/stock-icons/stock_close.png diff --git a/gtk/stock-icons/stock_close_20.png b/gtk/stock-icons/stock_close_20.png Binary files differnew file mode 100644 index 0000000000..b900bdf3bd --- /dev/null +++ b/gtk/stock-icons/stock_close_20.png diff --git a/gtk/stock-icons/stock_close_24.png b/gtk/stock-icons/stock_close_24.png Binary files differnew file mode 100644 index 0000000000..4338bdc3f6 --- /dev/null +++ b/gtk/stock-icons/stock_close_24.png diff --git a/gtk/stock-icons/stock_dialog_error_48.png b/gtk/stock-icons/stock_dialog_error_48.png Binary files differnew file mode 100644 index 0000000000..cc7830e26e --- /dev/null +++ b/gtk/stock-icons/stock_dialog_error_48.png diff --git a/gtk/stock-icons/stock_dialog_info_48.png b/gtk/stock-icons/stock_dialog_info_48.png Binary files differnew file mode 100644 index 0000000000..757e599d29 --- /dev/null +++ b/gtk/stock-icons/stock_dialog_info_48.png diff --git a/gtk/stock-icons/stock_dialog_question_48.png b/gtk/stock-icons/stock_dialog_question_48.png Binary files differnew file mode 100644 index 0000000000..2afbc7a873 --- /dev/null +++ b/gtk/stock-icons/stock_dialog_question_48.png diff --git a/gtk/stock-icons/stock_dialog_warning_48.png b/gtk/stock-icons/stock_dialog_warning_48.png Binary files differnew file mode 100644 index 0000000000..d6f2306dba --- /dev/null +++ b/gtk/stock-icons/stock_dialog_warning_48.png diff --git a/gtk/stock-icons/stock_exit.png b/gtk/stock-icons/stock_exit.png Binary files differnew file mode 100644 index 0000000000..34cccc31d8 --- /dev/null +++ b/gtk/stock-icons/stock_exit.png diff --git a/gtk/stock-icons/stock_exit_24.png b/gtk/stock-icons/stock_exit_24.png Binary files differnew file mode 100644 index 0000000000..34cccc31d8 --- /dev/null +++ b/gtk/stock-icons/stock_exit_24.png diff --git a/gtk/stock-icons/stock_help.png b/gtk/stock-icons/stock_help.png Binary files differnew file mode 100644 index 0000000000..2836a0f8ae --- /dev/null +++ b/gtk/stock-icons/stock_help.png diff --git a/gtk/stock-icons/stock_help_24.png b/gtk/stock-icons/stock_help_24.png Binary files differnew file mode 100644 index 0000000000..2836a0f8ae --- /dev/null +++ b/gtk/stock-icons/stock_help_24.png diff --git a/gtk/stock-icons/stock_new.png b/gtk/stock-icons/stock_new.png Binary files differnew file mode 100644 index 0000000000..538e9acd38 --- /dev/null +++ b/gtk/stock-icons/stock_new.png diff --git a/gtk/stock-icons/stock_new_24.png b/gtk/stock-icons/stock_new_24.png Binary files differnew file mode 100644 index 0000000000..538e9acd38 --- /dev/null +++ b/gtk/stock-icons/stock_new_24.png diff --git a/gtk/stock-icons/stock_no_20.png b/gtk/stock-icons/stock_no_20.png Binary files differnew file mode 100644 index 0000000000..6478554f62 --- /dev/null +++ b/gtk/stock-icons/stock_no_20.png diff --git a/gtk/stock-icons/stock_ok_20.png b/gtk/stock-icons/stock_ok_20.png Binary files differnew file mode 100644 index 0000000000..f1c33753f3 --- /dev/null +++ b/gtk/stock-icons/stock_ok_20.png diff --git a/gtk/stock-icons/stock_open.png b/gtk/stock-icons/stock_open.png Binary files differnew file mode 100644 index 0000000000..e966ad7bf8 --- /dev/null +++ b/gtk/stock-icons/stock_open.png diff --git a/gtk/stock-icons/stock_open_24.png b/gtk/stock-icons/stock_open_24.png Binary files differnew file mode 100644 index 0000000000..e966ad7bf8 --- /dev/null +++ b/gtk/stock-icons/stock_open_24.png diff --git a/gtk/stock-icons/stock_save.png b/gtk/stock-icons/stock_save.png Binary files differnew file mode 100644 index 0000000000..2281b92c27 --- /dev/null +++ b/gtk/stock-icons/stock_save.png diff --git a/gtk/stock-icons/stock_save_24.png b/gtk/stock-icons/stock_save_24.png Binary files differnew file mode 100644 index 0000000000..2281b92c27 --- /dev/null +++ b/gtk/stock-icons/stock_save_24.png diff --git a/gtk/stock-icons/stock_yes_20.png b/gtk/stock-icons/stock_yes_20.png Binary files differnew file mode 100644 index 0000000000..e061e7f17c --- /dev/null +++ b/gtk/stock-icons/stock_yes_20.png |