X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkiconfactory.c;h=2f9ad888fe8c80aaf7b73ca1e794fa2a73335be9;hb=2f57f4684ba1945e7bdf87c8ecea4a6e926cf223;hp=07b5d5038c5357d79cc5835fe3500f4714b668fb;hpb=f88d35bba7cd95b43728df771754e8d0d14a4456;p=~andy%2Fgtk diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c index 07b5d5038..2f9ad888f 100644 --- a/gtk/gtkiconfactory.c +++ b/gtk/gtkiconfactory.c @@ -30,9 +30,32 @@ #include "gtkintl.h" #include #include -#include #include +static GSList *all_icon_factories = NULL; + +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; + GtkIconSize 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; +}; + static gpointer parent_class = NULL; static void gtk_icon_factory_init (GtkIconFactory *icon_factory); @@ -72,6 +95,7 @@ static void gtk_icon_factory_init (GtkIconFactory *factory) { factory->icons = g_hash_table_new (g_str_hash, g_str_equal); + all_icon_factories = g_slist_prepend (all_icon_factories, factory); } static void @@ -96,6 +120,8 @@ gtk_icon_factory_finalize (GObject *object) { GtkIconFactory *factory = GTK_ICON_FACTORY (object); + all_icon_factories = g_slist_remove (all_icon_factories, factory); + g_hash_table_foreach (factory->icons, free_icon_set, NULL); g_hash_table_destroy (factory->icons); @@ -107,11 +133,11 @@ gtk_icon_factory_finalize (GObject *object) * gtk_icon_factory_new: * * Creates a new #GtkIconFactory. An icon factory manages a collection - * of #GtkIconSet; a #GtkIconSet manages a set of variants of a + * of #GtkIconSets; a #GtkIconSet manages a set of variants of a * particular icon (i.e. a #GtkIconSet contains variants for different * sizes and widget states). Icons in an icon factory are named by a * stock ID, which is a simple string identifying the icon. Each - * #GtkStyle has a list of #GtkIconFactory derived from the current + * #GtkStyle has a list of #GtkIconFactorys derived from the current * theme; those icon factories are consulted first when searching for * an icon. If the theme doesn't set a particular icon, GTK+ looks for * the icon in a list of default icon factories, maintained by @@ -243,6 +269,17 @@ gtk_icon_factory_remove_default (GtkIconFactory *factory) g_object_unref (G_OBJECT (factory)); } +static void +ensure_default_icons (void) +{ + if (gtk_default_icons == NULL) + { + gtk_default_icons = gtk_icon_factory_new (); + + get_default_icons (gtk_default_icons); + } +} + /** * gtk_icon_factory_lookup_default: * @stock_id: an icon name @@ -272,34 +309,56 @@ gtk_icon_factory_lookup_default (const gchar *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); - } + ensure_default_icons (); return gtk_icon_factory_lookup (gtk_default_icons, stock_id); } +#if 0 static GtkIconSet * sized_icon_set_from_inline (const guchar *inline_data, - const gchar *size) + GtkIconSize size) { GtkIconSet *set; - GtkIconSource source = { NULL, NULL, 0, 0, NULL, + GtkIconSource source = { NULL, NULL, 0, 0, 0, TRUE, TRUE, FALSE }; - source.size = (gchar*) size; + source.size = size; set = gtk_icon_set_new (); - source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1, NULL); + source.pixbuf = gdk_pixbuf_new_from_inline (-1, inline_data, FALSE, NULL); + + g_assert (source.pixbuf); + + gtk_icon_set_add_source (set, &source); + + g_object_unref (G_OBJECT (source.pixbuf)); + + return set; +} +#endif + +static GtkIconSet * +sized_with_fallback_icon_set_from_inline (const guchar *fallback_data, + const guchar *inline_data, + GtkIconSize size) +{ + GtkIconSet *set; + + GtkIconSource source = { NULL, NULL, 0, 0, 0, + TRUE, TRUE, FALSE }; + + source.size = size; + + set = gtk_icon_set_new (); + + source.pixbuf = gdk_pixbuf_new_from_inline (-1, inline_data, FALSE, NULL); g_assert (source.pixbuf); @@ -307,6 +366,16 @@ sized_icon_set_from_inline (const guchar *inline_data, g_object_unref (G_OBJECT (source.pixbuf)); + source.any_size = TRUE; + + source.pixbuf = gdk_pixbuf_new_from_inline (-1, fallback_data, FALSE, NULL); + + g_assert (source.pixbuf); + + gtk_icon_set_add_source (set, &source); + + g_object_unref (G_OBJECT (source.pixbuf)); + return set; } @@ -321,7 +390,7 @@ unsized_icon_set_from_inline (const guchar *inline_data) set = gtk_icon_set_new (); - source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1, NULL); + source.pixbuf = gdk_pixbuf_new_from_inline (-1, inline_data, FALSE, NULL); g_assert (source.pixbuf); @@ -332,10 +401,11 @@ unsized_icon_set_from_inline (const guchar *inline_data) return set; } +#if 0 static void add_sized (GtkIconFactory *factory, const guchar *inline_data, - const gchar *size, + GtkIconSize size, const gchar *stock_id) { GtkIconSet *set; @@ -346,6 +416,23 @@ add_sized (GtkIconFactory *factory, gtk_icon_set_unref (set); } +#endif + +static void +add_sized_with_fallback (GtkIconFactory *factory, + const guchar *fallback_data, + const guchar *inline_data, + GtkIconSize size, + const gchar *stock_id) +{ + GtkIconSet *set; + + set = sized_with_fallback_icon_set_from_inline (fallback_data, inline_data, size); + + gtk_icon_factory_add (factory, stock_id, set); + + gtk_icon_set_unref (set); +} static void add_unsized (GtkIconFactory *factory, @@ -366,236 +453,599 @@ 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); + /* We add all stock icons unsized, since it's confusing if icons only + * can be loaded at certain sizes. + */ + + /* Have dialog size */ + add_unsized (factory, stock_dialog_error_48, GTK_STOCK_DIALOG_ERROR); + add_unsized (factory, stock_dialog_info_48, GTK_STOCK_DIALOG_INFO); + add_unsized (factory, stock_dialog_question_48, GTK_STOCK_DIALOG_QUESTION); + add_unsized (factory, stock_dialog_warning_48,GTK_STOCK_DIALOG_WARNING); + + /* Have dnd size */ + add_unsized (factory, stock_dnd_32, GTK_STOCK_DND); + add_unsized (factory, stock_dnd_multiple_32, GTK_STOCK_DND_MULTIPLE); + + /* Have button sizes */ + add_unsized (factory, stock_apply_20, GTK_STOCK_APPLY); + add_unsized (factory, stock_cancel_20, GTK_STOCK_CANCEL); + add_unsized (factory, stock_no_20, GTK_STOCK_NO); + add_unsized (factory, stock_ok_20, GTK_STOCK_OK); + add_unsized (factory, stock_yes_20, GTK_STOCK_YES); + + /* Generic + button sizes */ + add_sized_with_fallback (factory, + stock_close_24, + stock_close_20, + GTK_ICON_SIZE_BUTTON, + GTK_STOCK_CLOSE); + + /* Generic + menu sizes */ + add_sized_with_fallback (factory, + stock_add_24, + stock_add_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_ADD); + + add_sized_with_fallback (factory, + stock_align_center_24, + stock_align_center_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_JUSTIFY_CENTER); + + add_sized_with_fallback (factory, + stock_align_justify_24, + stock_align_justify_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_JUSTIFY_FILL); + + add_sized_with_fallback (factory, + stock_align_left_24, + stock_align_left_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_JUSTIFY_LEFT); + + add_sized_with_fallback (factory, + stock_align_right_24, + stock_align_right_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_JUSTIFY_RIGHT); + + add_sized_with_fallback (factory, + stock_bottom_24, + stock_bottom_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_GOTO_BOTTOM); + + add_sized_with_fallback (factory, + stock_cdrom_24, + stock_cdrom_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_CDROM); + + add_sized_with_fallback (factory, + stock_convert_24, + stock_convert_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_CONVERT); + + add_sized_with_fallback (factory, + stock_copy_24, + stock_copy_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_COPY); + + add_sized_with_fallback (factory, + stock_cut_24, + stock_cut_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_CUT); + + add_sized_with_fallback (factory, + stock_down_arrow_24, + stock_down_arrow_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_GO_DOWN); + + add_sized_with_fallback (factory, + stock_exec_24, + stock_exec_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_EXECUTE); + + add_sized_with_fallback (factory, + stock_exit_24, + stock_exit_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_QUIT); + + add_sized_with_fallback (factory, + stock_first_24, + stock_first_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_GOTO_FIRST); + + add_sized_with_fallback (factory, + stock_font_24, + stock_font_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_SELECT_FONT); + + add_sized_with_fallback (factory, + stock_help_24, + stock_help_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_HELP); + + add_sized_with_fallback (factory, + stock_home_24, + stock_home_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_HOME); + + add_sized_with_fallback (factory, + stock_jump_to_24, + stock_jump_to_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_JUMP_TO); + + add_sized_with_fallback (factory, + stock_last_24, + stock_last_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_GOTO_LAST); + + add_sized_with_fallback (factory, + stock_left_arrow_24, + stock_left_arrow_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_GO_BACK); + + add_sized_with_fallback (factory, + stock_missing_image_24, + stock_missing_image_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_MISSING_IMAGE); + + add_sized_with_fallback (factory, + stock_new_24, + stock_new_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_NEW); + + add_sized_with_fallback (factory, + stock_open_24, + stock_open_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_OPEN); + + add_sized_with_fallback (factory, + stock_paste_24, + stock_paste_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_PASTE); + + add_sized_with_fallback (factory, + stock_preferences_24, + stock_preferences_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_PREFERENCES); + + add_sized_with_fallback (factory, + stock_print_24, + stock_print_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_PRINT); + + add_sized_with_fallback (factory, + stock_print_preview_24, + stock_print_preview_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_PRINT_PREVIEW); + + add_sized_with_fallback (factory, + stock_properties_24, + stock_properties_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_PROPERTIES); + + add_sized_with_fallback (factory, + stock_redo_24, + stock_redo_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_REDO); + + add_sized_with_fallback (factory, + stock_remove_24, + stock_remove_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_REMOVE); + + add_sized_with_fallback (factory, + stock_refresh_24, + stock_refresh_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_REFRESH); + + add_sized_with_fallback (factory, + stock_revert_24, + stock_revert_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_REVERT_TO_SAVED); + + add_sized_with_fallback (factory, + stock_right_arrow_24, + stock_right_arrow_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_GO_FORWARD); + + add_sized_with_fallback (factory, + stock_save_24, + stock_save_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_SAVE); + + add_sized_with_fallback (factory, + stock_save_24, + stock_save_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_FLOPPY); + + add_sized_with_fallback (factory, + stock_save_as_24, + stock_save_as_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_SAVE_AS); + + add_sized_with_fallback (factory, + stock_search_24, + stock_search_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_FIND); + + add_sized_with_fallback (factory, + stock_search_replace_24, + stock_search_replace_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_FIND_AND_REPLACE); + + add_sized_with_fallback (factory, + stock_sort_descending_24, + stock_sort_descending_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_SORT_DESCENDING); + + add_sized_with_fallback (factory, + stock_sort_ascending_24, + stock_sort_ascending_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_SORT_ASCENDING); + + add_sized_with_fallback (factory, + stock_spellcheck_24, + stock_spellcheck_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_SPELL_CHECK); + + add_sized_with_fallback (factory, + stock_stop_24, + stock_stop_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_STOP); + + add_sized_with_fallback (factory, + stock_text_bold_24, + stock_text_bold_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_BOLD); + + add_sized_with_fallback (factory, + stock_text_italic_24, + stock_text_italic_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_ITALIC); + + add_sized_with_fallback (factory, + stock_text_strikethrough_24, + stock_text_strikethrough_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_STRIKETHROUGH); + + add_sized_with_fallback (factory, + stock_text_underline_24, + stock_text_underline_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_UNDERLINE); + + add_sized_with_fallback (factory, + stock_top_24, + stock_top_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_GOTO_TOP); + + add_sized_with_fallback (factory, + stock_trash_24, + stock_trash_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_DELETE); + + add_sized_with_fallback (factory, + stock_undelete_24, + stock_undelete_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_UNDELETE); + + add_sized_with_fallback (factory, + stock_undo_24, + stock_undo_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_UNDO); + + add_sized_with_fallback (factory, + stock_up_arrow_24, + stock_up_arrow_16, + GTK_ICON_SIZE_MENU, + GTK_STOCK_GO_UP); + +/* Generic size only */ + + add_unsized (factory, stock_clear_24, GTK_STOCK_CLEAR); + add_unsized (factory, stock_colorselector_24, GTK_STOCK_SELECT_COLOR); + add_unsized (factory, stock_index_24, GTK_STOCK_INDEX); + add_unsized (factory, stock_zoom_1_24, GTK_STOCK_ZOOM_100); + add_unsized (factory, stock_zoom_fit_24, GTK_STOCK_ZOOM_FIT); + add_unsized (factory, stock_zoom_in_24, GTK_STOCK_ZOOM_IN); + add_unsized (factory, stock_zoom_out_24, GTK_STOCK_ZOOM_OUT); } /* Sizes */ -static GHashTable *icon_sizes = NULL; - typedef struct _IconSize IconSize; struct _IconSize { + gint size; gchar *name; - gboolean is_alias; - - union - { - gchar *target; - struct - { - gint width; - gint height; - } size; - } d; + gint width; + gint height; }; -static IconSize* -icon_size_new (const gchar *name) -{ - IconSize *is; - - is = g_new0 (IconSize, 1); - - is->name = g_strdup (name); - - return is; -} +typedef struct _IconAlias IconAlias; -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) +struct _IconAlias { - 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); + gchar *name; + gint target; +}; - icon_size_insert (is); -} +static GHashTable *icon_aliases = NULL; +static IconSize *icon_sizes = NULL; +static gint icon_sizes_allocated = 0; +static gint icon_sizes_used = 0; static void init_icon_sizes (void) { if (icon_sizes == NULL) { - icon_sizes = g_hash_table_new (g_str_hash, g_str_equal); +#define NUM_BUILTIN_SIZES 7 + gint i; - 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); + icon_aliases = g_hash_table_new (g_str_hash, g_str_equal); + + icon_sizes = g_new (IconSize, NUM_BUILTIN_SIZES); + icon_sizes_allocated = NUM_BUILTIN_SIZES; + icon_sizes_used = NUM_BUILTIN_SIZES; + + icon_sizes[GTK_ICON_SIZE_INVALID].size = 0; + icon_sizes[GTK_ICON_SIZE_INVALID].name = NULL; + icon_sizes[GTK_ICON_SIZE_INVALID].width = 0; + icon_sizes[GTK_ICON_SIZE_INVALID].height = 0; + + /* the name strings aren't copied since we don't ever remove + * icon sizes, so we don't need to know whether they're static. + * Even if we did I suppose removing the builtin sizes would be + * disallowed. + */ + + icon_sizes[GTK_ICON_SIZE_MENU].size = GTK_ICON_SIZE_MENU; + icon_sizes[GTK_ICON_SIZE_MENU].name = "gtk-menu"; + icon_sizes[GTK_ICON_SIZE_MENU].width = 16; + icon_sizes[GTK_ICON_SIZE_MENU].height = 16; + + icon_sizes[GTK_ICON_SIZE_BUTTON].size = GTK_ICON_SIZE_BUTTON; + icon_sizes[GTK_ICON_SIZE_BUTTON].name = "gtk-button"; + icon_sizes[GTK_ICON_SIZE_BUTTON].width = 20; + icon_sizes[GTK_ICON_SIZE_BUTTON].height = 20; + + icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].size = GTK_ICON_SIZE_SMALL_TOOLBAR; + icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].name = "gtk-small-toolbar"; + icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].width = 18; + icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].height = 18; + + icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].size = GTK_ICON_SIZE_LARGE_TOOLBAR; + icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].name = "gtk-large-toolbar"; + icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].width = 24; + icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].height = 24; + + icon_sizes[GTK_ICON_SIZE_DND].size = GTK_ICON_SIZE_DND; + icon_sizes[GTK_ICON_SIZE_DND].name = "gtk-dnd"; + icon_sizes[GTK_ICON_SIZE_DND].width = 32; + icon_sizes[GTK_ICON_SIZE_DND].height = 32; + + icon_sizes[GTK_ICON_SIZE_DIALOG].size = GTK_ICON_SIZE_DIALOG; + icon_sizes[GTK_ICON_SIZE_DIALOG].name = "gtk-dialog"; + icon_sizes[GTK_ICON_SIZE_DIALOG].width = 48; + icon_sizes[GTK_ICON_SIZE_DIALOG].height = 48; + + g_assert ((GTK_ICON_SIZE_DIALOG + 1) == NUM_BUILTIN_SIZES); + + /* Alias everything to itself. */ + i = 1; /* skip invalid size */ + while (i < NUM_BUILTIN_SIZES) + { + gtk_icon_size_register_alias (icon_sizes[i].name, icon_sizes[i].size); + + ++i; + } + +#undef NUM_BUILTIN_SIZES } } /** * gtk_icon_size_lookup: - * @alias: name of an icon size + * @size: an icon size * @width: location to store icon width * @height: location to store icon height * - * Obtains the pixel size of an icon, normally @alias would be + * Obtains the pixel size of a semantic icon size, normally @size would be * #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_BUTTON, etc. This function * isn't normally needed, gtk_widget_render_icon() is the usual * way to get an icon for rendering, then just look at the size of * the rendered pixbuf. The rendered pixbuf may not even correspond to * the width/height returned by gtk_icon_size_lookup(), because themes - * are free to render the pixbuf however they like. + * are free to render the pixbuf however they like, including changing + * the usual size. * - * Return value: %TRUE if @alias was known. + * Return value: %TRUE if @size was a valid size **/ gboolean -gtk_icon_size_lookup (const gchar *alias, +gtk_icon_size_lookup (GtkIconSize size, 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) + if (size >= icon_sizes_used) return FALSE; + if (size == GTK_ICON_SIZE_INVALID) + return FALSE; + if (widthp) - *widthp = is->d.size.width; + *widthp = icon_sizes[size].width; if (heightp) - *heightp = is->d.size.height; + *heightp = icon_sizes[size].height; return TRUE; } /** * gtk_icon_size_register: - * @alias: name of the icon size + * @name: name of the icon size * @width: the icon width * @height: the icon height * * Registers a new icon size, along the same lines as #GTK_ICON_SIZE_MENU, - * etc. + * etc. Returns the integer value for the size. + * + * Returns: integer value representing the size * **/ -void -gtk_icon_size_register (const gchar *alias, +GtkIconSize +gtk_icon_size_register (const gchar *name, gint width, gint height) { - g_return_if_fail (alias != NULL); - g_return_if_fail (width > 0); - g_return_if_fail (height > 0); + g_return_val_if_fail (name != NULL, 0); + g_return_val_if_fail (width > 0, 0); + g_return_val_if_fail (height > 0, 0); init_icon_sizes (); - icon_size_add (alias, width, height); + if (icon_sizes_used == icon_sizes_allocated) + { + icon_sizes_allocated *= 2; + icon_sizes = g_renew (IconSize, icon_sizes, icon_sizes_allocated); + } + + icon_sizes[icon_sizes_used].size = icon_sizes_used; + icon_sizes[icon_sizes_used].name = g_strdup (name); + icon_sizes[icon_sizes_used].width = width; + icon_sizes[icon_sizes_used].height = height; + + ++icon_sizes_used; + + /* alias to self. */ + gtk_icon_size_register_alias (name, icon_sizes_used - 1); + + return icon_sizes_used - 1; } /** * gtk_icon_size_register_alias: * @alias: an alias for @target - * @target: an existing icon size name + * @target: an existing icon size + * + * Registers @alias as another name for @target. + * So calling gtk_icon_size_from_name() with @alias as argument + * will return @target. * - * Registers @alias as another name for @target, usable when calling - * gtk_icon_size_lookup(). - * **/ void gtk_icon_size_register_alias (const gchar *alias, - const gchar *target) + GtkIconSize target) { + IconAlias *ia; + g_return_if_fail (alias != NULL); - g_return_if_fail (target != NULL); init_icon_sizes (); - icon_alias_add (alias, target); + if (g_hash_table_lookup (icon_aliases, alias)) + g_warning ("gtk_icon_size_register_alias: Icon size name '%s' already exists", alias); + + if (!gtk_icon_size_lookup (target, NULL, NULL)) + g_warning ("gtk_icon_size_register_alias: Icon size %d does not exist", target); + + ia = g_new (IconAlias, 1); + ia->name = g_strdup (alias); + ia->target = target; + + g_hash_table_insert (icon_aliases, ia->name, ia); +} + +/** + * gtk_icon_size_from_name: + * @name: the name to look up. + * @returns: the icon size with the given name. + * + * Looks up the icon size associated with @name. + **/ +GtkIconSize +gtk_icon_size_from_name (const gchar *name) +{ + IconAlias *ia; + + init_icon_sizes (); + + ia = g_hash_table_lookup (icon_aliases, name); + + if (ia) + return ia->target; + else + return GTK_ICON_SIZE_INVALID; +} + +/** + * gtk_icon_size_get_name: + * @size: a #GtkIconSize. + * @returns: the name of the given icon size. + * + * Gets the canonical name of the given icon size. The returned string + * is statically allocated and should not be freed. + **/ +G_CONST_RETURN gchar* +gtk_icon_size_get_name (GtkIconSize size) +{ + if (size >= icon_sizes_used) + return NULL; + else + return icon_sizes[size].name; } /* Icon Set */ @@ -609,12 +1059,12 @@ static GdkPixbuf *find_in_cache (GtkIconSet *icon_set, GtkStyle *style, GtkTextDirection direction, GtkStateType state, - const gchar *size); + GtkIconSize size); static void add_to_cache (GtkIconSet *icon_set, GtkStyle *style, GtkTextDirection direction, GtkStateType state, - const gchar *size, + GtkIconSize size, GdkPixbuf *pixbuf); static void clear_cache (GtkIconSet *icon_set, gboolean style_detach); @@ -677,7 +1127,11 @@ gtk_icon_set_new (void) * gtk_icon_set_new_from_pixbuf: * @pixbuf: a #GdkPixbuf * - * Creates a new #GtkIconSet seeded with @pixbuf. + * Creates a new #GtkIconSet with @pixbuf as the default/fallback + * source image. If you don't add any additional #GtkIconSource to the + * icon set, all variants of the icon will be created from @pixbuf, + * using scaling, pixelation, etc. as required to adjust the icon size + * or make the icon look insensitive/prelighted. * * Return value: a new #GtkIconSet **/ @@ -686,7 +1140,7 @@ gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf) { GtkIconSet *set; - GtkIconSource source = { NULL, NULL, 0, 0, NULL, + GtkIconSource source = { NULL, NULL, 0, 0, 0, TRUE, TRUE, TRUE }; g_return_val_if_fail (pixbuf != NULL, NULL); @@ -703,11 +1157,11 @@ gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf) /** * gtk_icon_set_ref: - * @icon_set: a #GtkIconSet + * @icon_set: a #GtkIconSet. * - * Increments the reference count on @icon_set + * Increments the reference count on @icon_set. * - * Return value: @icon_set is returned + * Return value: @icon_set. **/ GtkIconSet* gtk_icon_set_ref (GtkIconSet *icon_set) @@ -751,6 +1205,19 @@ gtk_icon_set_unref (GtkIconSet *icon_set) } } +GType +gtk_icon_set_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("GtkIconSet", + (GBoxedCopyFunc) gtk_icon_set_ref, + (GBoxedFreeFunc) gtk_icon_set_unref); + + return our_type; +} + /** * gtk_icon_set_copy: * @icon_set: a #GtkIconSet @@ -787,7 +1254,8 @@ gtk_icon_set_copy (GtkIconSet *icon_set) static gboolean -sizes_equivalent (const gchar *rhs, const gchar *lhs) +sizes_equivalent (GtkIconSize lhs, + GtkIconSize rhs) { gint r_w, r_h, l_w, l_h; @@ -801,7 +1269,7 @@ static GtkIconSource* find_and_prep_icon_source (GtkIconSet *icon_set, GtkTextDirection direction, GtkStateType state, - const gchar *size) + GtkIconSize size) { GtkIconSource *source; GSList *tmp_list; @@ -837,21 +1305,11 @@ find_and_prep_icon_source (GtkIconSet *icon_set, if (source->pixbuf == NULL) { - GError *error; - gchar *full; + GError *error = NULL; g_assert (source->filename); + source->pixbuf = gdk_pixbuf_new_from_file (source->filename, &error); - if (*source->filename != G_DIR_SEPARATOR) - full = gtk_rc_find_pixmap_in_path (NULL, source->filename); - else - full = g_strdup (source->filename); - - error = NULL; - source->pixbuf = gdk_pixbuf_new_from_file (full, &error); - - g_free (full); - if (source->pixbuf == NULL) { /* Remove this icon source so we don't keep trying to @@ -878,6 +1336,29 @@ find_and_prep_icon_source (GtkIconSet *icon_set, return source; } +static GdkPixbuf* +render_fallback_image (GtkStyle *style, + GtkTextDirection direction, + GtkStateType state, + GtkIconSize size, + GtkWidget *widget, + const char *detail) +{ + /* This icon can be used for any direction/state/size */ + static GtkIconSource fallback_source = { NULL, NULL, 0, 0, 0, TRUE, TRUE, TRUE }; + + if (fallback_source.pixbuf == NULL) + fallback_source.pixbuf = gdk_pixbuf_new_from_inline (-1, stock_missing_image_24, FALSE, NULL); + + return gtk_style_render_icon (style, + &fallback_source, + direction, + state, + size, + widget, + detail); +} + /** * gtk_icon_set_render_icon: * @icon_set: a #GtkIconSet @@ -889,36 +1370,31 @@ find_and_prep_icon_source (GtkIconSet *icon_set, * @detail: detail to pass to the theme engine, or %NULL * * Renders an icon using gtk_style_render_icon(). In most cases, - * gtk_widget_render_icon() is better, since it automatically - * provides most of the arguments from the current widget settings. - * A %NULL return value is possible if an icon file fails to load - * or the like. + * gtk_widget_render_icon() is better, since it automatically provides + * most of the arguments from the current widget settings. This + * function never returns %NULL; if the icon can't be rendered + * (perhaps because an image file fails to load), a default "missing + * image" icon will be returned instead. * - * Return value: a #GdkPixbuf to be displayed, or %NULL + * Return value: a #GdkPixbuf to be displayed **/ GdkPixbuf* gtk_icon_set_render_icon (GtkIconSet *icon_set, GtkStyle *style, GtkTextDirection direction, GtkStateType state, - const gchar *size, + GtkIconSize 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; + return render_fallback_image (style, direction, state, size, widget, detail); icon = find_in_cache (icon_set, style, direction, state, size); @@ -933,7 +1409,7 @@ gtk_icon_set_render_icon (GtkIconSet *icon_set, source = find_and_prep_icon_source (icon_set, direction, state, size); if (source == NULL) - return NULL; + return render_fallback_image (style, direction, state, size, widget, detail); g_assert (source->pixbuf != NULL); @@ -993,7 +1469,26 @@ icon_source_compare (gconstpointer ap, gconstpointer bp) * scaled, made to look insensitive, etc. in * gtk_icon_set_render_icon(), but #GtkIconSet needs base images to * work with. The base images and when to use them are described by - * #GtkIconSource. + * a #GtkIconSource. + * + * This function copies @source, so you can reuse the same source immediately + * without affecting the icon set. + * + * An example of when you'd use this function: a web browser's "Back + * to Previous Page" icon might point in a different direction in + * Hebrew and in English; it might look different when insensitive; + * and it might change size depending on toolbar mode (small/large + * icons). So a single icon set would contain all those variants of + * the icon, and you might add a separate source for each one. + * + * You should nearly always add a "default" icon source with all + * fields wildcarded, which will be used as a fallback if no more + * specific source matches. #GtkIconSet always prefers more specific + * icon sources to more generic icon sources. The order in which you + * add the sources to the icon set does not matter. + * + * gtk_icon_set_new_from_pixbuf() creates a new icon set with a + * default icon source based on the given pixbuf. * **/ void @@ -1015,6 +1510,138 @@ gtk_icon_set_add_source (GtkIconSet *icon_set, icon_source_compare); } +/** + * gtk_icon_set_get_sizes: + * @icon_set: a #GtkIconSet + * @sizes: return location for array of sizes + * @n_sizes: location to store number of elements in returned array + * + * Obtains a list of icon sizes this icon set can render. The returned + * array must be freed with g_free(). + * + **/ +void +gtk_icon_set_get_sizes (GtkIconSet *icon_set, + GtkIconSize **sizes, + gint *n_sizes) +{ + GSList *tmp_list; + gboolean all_sizes = FALSE; + GSList *specifics = NULL; + + g_return_if_fail (icon_set != NULL); + g_return_if_fail (sizes != NULL); + g_return_if_fail (n_sizes != NULL); + + tmp_list = icon_set->sources; + while (tmp_list != NULL) + { + GtkIconSource *source; + + source = tmp_list->data; + + if (source->any_size) + { + all_sizes = TRUE; + break; + } + else + specifics = g_slist_prepend (specifics, GINT_TO_POINTER (source->size)); + + tmp_list = g_slist_next (tmp_list); + } + + if (all_sizes) + { + /* Need to find out what sizes exist */ + gint i; + + init_icon_sizes (); + + *sizes = g_new (GtkIconSize, icon_sizes_used); + *n_sizes = icon_sizes_used - 1; + + i = 1; + while (i < icon_sizes_used) + { + (*sizes)[i - 1] = icon_sizes[i].size; + ++i; + } + } + else + { + gint i; + + *n_sizes = g_slist_length (specifics); + *sizes = g_new (GtkIconSize, *n_sizes); + + i = 0; + tmp_list = specifics; + while (tmp_list != NULL) + { + (*sizes)[i] = GPOINTER_TO_INT (tmp_list->data); + + ++i; + tmp_list = g_slist_next (tmp_list); + } + } + + g_slist_free (specifics); +} + + +/** + * gtk_icon_source_new: + * + * Creates a new #GtkIconSource. A #GtkIconSource contains a #GdkPixbuf (or + * image filename) that serves as the base image for one or more of the + * icons in a #GtkIconSet, along with a specification for which icons in the + * icon set will be based on that pixbuf or image file. An icon set contains + * a set of icons that represent "the same" logical concept in different states, + * different global text directions, and different sizes. + * + * So for example a web browser's "Back to Previous Page" icon might + * point in a different direction in Hebrew and in English; it might + * look different when insensitive; and it might change size depending + * on toolbar mode (small/large icons). So a single icon set would + * contain all those variants of the icon. #GtkIconSet contains a list + * of #GtkIconSource from which it can derive specific icon variants in + * the set. + * + * In the simplest case, #GtkIconSet contains one source pixbuf from + * which it derives all variants. The convenience function + * gtk_icon_set_new_from_pixbuf() handles this case; if you only have + * one source pixbuf, just use that function. + * + * If you want to use a different base pixbuf for different icon + * variants, you create multiple icon sources, mark which variants + * they'll be used to create, and add them to the icon set with + * gtk_icon_set_add_source(). + * + * By default, the icon source has all parameters wildcarded. That is, + * the icon source will be used as the base icon for any desired text + * direction, widget state, or icon size. + * + * Return value: a new #GtkIconSource + **/ +GtkIconSource* +gtk_icon_source_new (void) +{ + GtkIconSource *src; + + src = g_new0 (GtkIconSource, 1); + + src->direction = GTK_TEXT_DIR_NONE; + src->size = GTK_ICON_SIZE_INVALID; + src->state = GTK_STATE_NORMAL; + + src->any_direction = TRUE; + src->any_state = TRUE; + src->any_size = TRUE; + + return src; +} + /** * gtk_icon_source_copy: * @source: a #GtkIconSource @@ -1035,7 +1662,7 @@ gtk_icon_source_copy (const GtkIconSource *source) *copy = *source; copy->filename = g_strdup (source->filename); - copy->size = g_strdup (source->size); + copy->size = source->size; if (copy->pixbuf) g_object_ref (G_OBJECT (copy->pixbuf)); @@ -1055,13 +1682,360 @@ 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); } +GType +gtk_icon_source_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("GtkIconSource", + (GBoxedCopyFunc) gtk_icon_source_copy, + (GBoxedFreeFunc) gtk_icon_source_free); + + return our_type; +} + +/** + * gtk_icon_source_set_filename: + * @source: a #GtkIconSource + * @filename: image file to use + * + * Sets the name of an image file to use as a base image when creating + * icon variants for #GtkIconSet. The filename must be absolute. + **/ +void +gtk_icon_source_set_filename (GtkIconSource *source, + const gchar *filename) +{ + g_return_if_fail (source != NULL); + g_return_if_fail (filename == NULL || g_path_is_absolute (filename)); + + if (source->filename == filename) + return; + + if (source->filename) + g_free (source->filename); + + source->filename = g_strdup (filename); +} + +/** + * gtk_icon_source_set_pixbuf: + * @source: a #GtkIconSource + * @pixbuf: pixbuf to use as a source + * + * Sets a pixbuf to use as a base image when creating icon variants + * for #GtkIconSet. If an icon source has both a filename and a pixbuf + * set, the pixbuf will take priority. + * + **/ +void +gtk_icon_source_set_pixbuf (GtkIconSource *source, + GdkPixbuf *pixbuf) +{ + g_return_if_fail (source != NULL); + + if (pixbuf) + g_object_ref (G_OBJECT (pixbuf)); + + if (source->pixbuf) + g_object_unref (G_OBJECT (source->pixbuf)); + + source->pixbuf = pixbuf; +} + +/** + * gtk_icon_source_get_filename: + * @source: a #GtkIconSource + * + * Retrieves the source filename, or %NULL if none is set. The + * filename is not a copy, and should not be modified or expected to + * persist beyond the lifetime of the icon source. + * + * Return value: image filename + **/ +G_CONST_RETURN gchar* +gtk_icon_source_get_filename (const GtkIconSource *source) +{ + g_return_val_if_fail (source != NULL, NULL); + + return source->filename; +} + +/** + * gtk_icon_source_get_pixbuf: + * @source: a #GtkIconSource + * + * Retrieves the source pixbuf, or %NULL if none is set. + * The reference count on the pixbuf is not incremented. + * + * Return value: source pixbuf + **/ +GdkPixbuf* +gtk_icon_source_get_pixbuf (const GtkIconSource *source) +{ + g_return_val_if_fail (source != NULL, NULL); + + return source->pixbuf; +} + +/** + * gtk_icon_source_set_direction_wildcarded: + * @source: a #GtkIconSource + * @setting: %TRUE to wildcard the text direction + * + * If the text direction is wildcarded, this source can be used + * as the base image for an icon in any #GtkTextDirection. + * If the text direction is not wildcarded, then the + * text direction the icon source applies to should be set + * with gtk_icon_source_set_direction(), and the icon source + * will only be used with that text direction. + * + * #GtkIconSet prefers non-wildcarded sources (exact matches) over + * wildcarded sources, and will use an exact match when possible. + * + **/ +void +gtk_icon_source_set_direction_wildcarded (GtkIconSource *source, + gboolean setting) +{ + g_return_if_fail (source != NULL); + + source->any_direction = setting != FALSE; +} + +/** + * gtk_icon_source_set_state_wildcarded: + * @source: a #GtkIconSource + * @setting: %TRUE to wildcard the widget state + * + * If the widget state is wildcarded, this source can be used as the + * base image for an icon in any #GtkStateType. If the widget state + * is not wildcarded, then the state the source applies to should be + * set with gtk_icon_source_set_state() and the icon source will + * only be used with that specific state. + * + * #GtkIconSet prefers non-wildcarded sources (exact matches) over + * wildcarded sources, and will use an exact match when possible. + * + * #GtkIconSet will normally transform wildcarded source images to + * produce an appropriate icon for a given state, for example + * lightening an image on prelight, but will not modify source images + * that match exactly. + **/ +void +gtk_icon_source_set_state_wildcarded (GtkIconSource *source, + gboolean setting) +{ + g_return_if_fail (source != NULL); + + source->any_state = setting != FALSE; +} + + +/** + * gtk_icon_source_set_size_wildcarded: + * @source: a #GtkIconSource + * @setting: %TRUE to wildcard the widget state + * + * If the icon size is wildcarded, this source can be used as the base + * image for an icon of any size. If the size is not wildcarded, then + * the size the source applies to should be set with + * gtk_icon_source_set_size() and the icon source will only be used + * with that specific size. + * + * #GtkIconSet prefers non-wildcarded sources (exact matches) over + * wildcarded sources, and will use an exact match when possible. + * + * #GtkIconSet will normally scale wildcarded source images to produce + * an appropriate icon at a given size, but will not change the size + * of source images that match exactly. + **/ +void +gtk_icon_source_set_size_wildcarded (GtkIconSource *source, + gboolean setting) +{ + g_return_if_fail (source != NULL); + + source->any_size = setting != FALSE; +} + +/** + * gtk_icon_source_get_size_wildcarded: + * @source: a #GtkIconSource + * + * Gets the value set by gtk_icon_source_set_size_wildcarded(). + * + * Return value: %TRUE if this icon source is a base for any icon size variant + **/ +gboolean +gtk_icon_source_get_size_wildcarded (const GtkIconSource *source) +{ + g_return_val_if_fail (source != NULL, TRUE); + + return source->any_size; +} + +/** + * gtk_icon_source_get_state_wildcarded: + * @source: a #GtkIconSource + * + * Gets the value set by gtk_icon_source_set_state_wildcarded(). + * + * Return value: %TRUE if this icon source is a base for any widget state variant + **/ +gboolean +gtk_icon_source_get_state_wildcarded (const GtkIconSource *source) +{ + g_return_val_if_fail (source != NULL, TRUE); + + return source->any_state; +} + +/** + * gtk_icon_source_get_direction_wildcarded: + * @source: a #GtkIconSource + * + * Gets the value set by gtk_icon_source_set_direction_wildcarded(). + * + * Return value: %TRUE if this icon source is a base for any text direction variant + **/ +gboolean +gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source) +{ + g_return_val_if_fail (source != NULL, TRUE); + + return source->any_direction; +} + +/** + * gtk_icon_source_set_direction: + * @source: a #GtkIconSource + * @direction: text direction this source applies to + * + * Sets the text direction this icon source is intended to be used + * with. + * + * Setting the text direction on an icon source makes no difference + * if the text direction is wildcarded. Therefore, you should usually + * call gtk_icon_source_set_direction_wildcarded() to un-wildcard it + * in addition to calling this function. + * + **/ +void +gtk_icon_source_set_direction (GtkIconSource *source, + GtkTextDirection direction) +{ + g_return_if_fail (source != NULL); + + source->direction = direction; +} + +/** + * gtk_icon_source_set_state: + * @source: a #GtkIconSource + * @state: widget state this source applies to + * + * Sets the widget state this icon source is intended to be used + * with. + * + * Setting the widget state on an icon source makes no difference + * if the state is wildcarded. Therefore, you should usually + * call gtk_icon_source_set_state_wildcarded() to un-wildcard it + * in addition to calling this function. + * + **/ +void +gtk_icon_source_set_state (GtkIconSource *source, + GtkStateType state) +{ + g_return_if_fail (source != NULL); + + source->state = state; +} + +/** + * gtk_icon_source_set_size: + * @source: a #GtkIconSource + * @size: icon size this source applies to + * + * Sets the icon size this icon source is intended to be used + * with. + * + * Setting the icon size on an icon source makes no difference + * if the size is wildcarded. Therefore, you should usually + * call gtk_icon_source_set_size_wildcarded() to un-wildcard it + * in addition to calling this function. + * + **/ +void +gtk_icon_source_set_size (GtkIconSource *source, + GtkIconSize size) +{ + g_return_if_fail (source != NULL); + + source->size = size; +} + +/** + * gtk_icon_source_get_direction: + * @source: a #GtkIconSource + * + * Obtains the text direction this icon source applies to. The return + * value is only useful/meaningful if the text direction is not + * wildcarded. + * + * Return value: text direction this source matches + **/ +GtkTextDirection +gtk_icon_source_get_direction (const GtkIconSource *source) +{ + g_return_val_if_fail (source != NULL, 0); + + return source->direction; +} + +/** + * gtk_icon_source_get_state: + * @source: a #GtkIconSource + * + * Obtains the widget state this icon source applies to. The return + * value is only useful/meaningful if the widget state is not + * wildcarded. + * + * Return value: widget state this source matches + **/ +GtkStateType +gtk_icon_source_get_state (const GtkIconSource *source) +{ + g_return_val_if_fail (source != NULL, 0); + + return source->state; +} + +/** + * gtk_icon_source_get_size: + * @source: a #GtkIconSource + * + * Obtains the icon size this source applies to. The return value + * is only useful/meaningful if the icon size is not wildcarded. + * + * Return value: icon size this source matches. + **/ +GtkIconSize +gtk_icon_source_get_size (const GtkIconSource *source) +{ + g_return_val_if_fail (source != NULL, 0); + + return source->size; +} + /* Note that the logical maximum is 20 per GtkTextDirection, so we could * eventually set this to >20 to never throw anything out. */ @@ -1077,7 +2051,7 @@ struct _CachedIcon GtkStyle *style; GtkTextDirection direction; GtkStateType state; - gchar *size; + GtkIconSize size; GdkPixbuf *pixbuf; }; @@ -1092,7 +2066,6 @@ ensure_cache_up_to_date (GtkIconSet *icon_set) static void cached_icon_free (CachedIcon *icon) { - g_free (icon->size); g_object_unref (G_OBJECT (icon->pixbuf)); g_free (icon); @@ -1103,7 +2076,7 @@ find_in_cache (GtkIconSet *icon_set, GtkStyle *style, GtkTextDirection direction, GtkStateType state, - const gchar *size) + GtkIconSize size) { GSList *tmp_list; GSList *prev; @@ -1119,7 +2092,7 @@ find_in_cache (GtkIconSet *icon_set, if (icon->style == style && icon->direction == direction && icon->state == state && - strcmp (icon->size, size) == 0) + icon->size == size) { if (prev) { @@ -1144,7 +2117,7 @@ add_to_cache (GtkIconSet *icon_set, GtkStyle *style, GtkTextDirection direction, GtkStateType state, - const gchar *size, + GtkIconSize size, GdkPixbuf *pixbuf) { CachedIcon *icon; @@ -1168,7 +2141,7 @@ add_to_cache (GtkIconSet *icon_set, icon->style = style; icon->direction = direction; icon->state = state; - icon->size = g_strdup (size); + icon->size = size; icon->pixbuf = pixbuf; if (icon->style) @@ -1259,7 +2232,7 @@ copy_cache (GtkIconSet *icon_set, g_object_ref (G_OBJECT (icon_copy->pixbuf)); - icon_copy->size = g_strdup (icon->size); + icon_copy->size = icon->size; copy = g_slist_prepend (copy, icon_copy); @@ -1336,3 +2309,57 @@ _gtk_icon_set_invalidate_caches (void) { ++cache_serial; } + +static void +listify_foreach (gpointer key, gpointer value, gpointer data) +{ + GSList **list = data; + + *list = g_slist_prepend (*list, key); +} + +static GSList * +g_hash_table_get_keys (GHashTable *table) +{ + GSList *list = NULL; + + g_hash_table_foreach (table, listify_foreach, &list); + + return list; +} + +/** + * _gtk_icon_factory_list_ids: + * + * Gets all known IDs stored in an existing icon factory. + * The strings in the returned list aren't copied. + * The list itself should be freed. + * + * Return value: List of ids in icon factories + **/ +GSList* +_gtk_icon_factory_list_ids (void) +{ + GSList *tmp_list; + GSList *ids; + + ids = NULL; + + ensure_default_icons (); + + tmp_list = all_icon_factories; + while (tmp_list != NULL) + { + GSList *these_ids; + + GtkIconFactory *factory = GTK_ICON_FACTORY (tmp_list->data); + + these_ids = g_hash_table_get_keys (factory->icons); + + ids = g_slist_concat (ids, these_ids); + + tmp_list = g_slist_next (tmp_list); + } + + return ids; +}