diff options
Diffstat (limited to 'src/icons.c')
-rw-r--r-- | src/icons.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/src/icons.c b/src/icons.c new file mode 100644 index 0000000..bb8e33d --- /dev/null +++ b/src/icons.c @@ -0,0 +1,252 @@ +/* + * icons.[ch] written by Paolo Bacchilega, who writes: + * "There is no problem for me, you can license my code + * under whatever licence you wish :)" + * + * $Id: icons.c 12639 2011-08-07 18:41:13Z jordan $ + */ + +#include <string.h> /* strcmp */ +#include <glib.h> +#include <gtk/gtk.h> +#include <gio/gio.h> +#include "icons.h" + +#define VOID_PIXBUF_KEY "void-pixbuf" + +static const char *get_static_string(const char *s) +{ + static GStringChunk *static_strings = NULL; + + if (s == NULL) + return NULL; + + if (static_strings == NULL) + static_strings = g_string_chunk_new(1024); + + return g_string_chunk_insert_const(static_strings, s); +} + +typedef struct { + GtkIconTheme *icon_theme; + int icon_size; + GHashTable *cache; +} IconCache; + + +static IconCache *icon_cache[7] = + { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + + +static GdkPixbuf *create_void_pixbuf(int width, int height) +{ + GdkPixbuf *p; + + p = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); + gdk_pixbuf_fill(p, 0xFFFFFF00); + + return p; +} + + +static int get_size_in_pixels(GtkWidget * widget, GtkIconSize icon_size) +{ + int width, height; + + gtk_icon_size_lookup_for_settings(gtk_widget_get_settings(widget), + icon_size, &width, &height); + return MAX(width, height); +} + + +static IconCache *icon_cache_new(GtkWidget * for_widget, int icon_size) +{ + IconCache *icon_cache; + + g_return_val_if_fail(for_widget != NULL, NULL); + + icon_cache = g_new0(IconCache, 1); + icon_cache->icon_theme = + gtk_icon_theme_get_for_screen(gtk_widget_get_screen(for_widget)); + icon_cache->icon_size = get_size_in_pixels(for_widget, icon_size); + icon_cache->cache = + g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + g_object_unref); + + g_hash_table_insert(icon_cache->cache, (void *) VOID_PIXBUF_KEY, + create_void_pixbuf(icon_cache->icon_size, + icon_cache->icon_size)); + + return icon_cache; +} + +static const char *_icon_cache_get_icon_key(GIcon * icon) +{ + const char *key = NULL; + + if (G_IS_THEMED_ICON(icon)) { + char **icon_names; + char *name; + + g_object_get(icon, "names", &icon_names, NULL); + name = g_strjoinv(",", icon_names); + + key = get_static_string(name); + + g_free(name); + g_strfreev(icon_names); + } else if (G_IS_FILE_ICON(icon)) { + GFile *file; + char *filename; + + file = g_file_icon_get_file(G_FILE_ICON(icon)); + filename = g_file_get_path(file); + + key = get_static_string(filename); + + g_free(filename); + g_object_unref(file); + } + + return key; +} + + +static GdkPixbuf *get_themed_icon_pixbuf(GThemedIcon * icon, + int size, + GtkIconTheme * icon_theme) +{ + char **icon_names = NULL; + GtkIconInfo *icon_info; + GdkPixbuf *pixbuf; + GError *error = NULL; + + g_object_get(icon, "names", &icon_names, NULL); + + icon_info = + gtk_icon_theme_choose_icon(icon_theme, (const char **) icon_names, + size, 0); + if (icon_info == NULL) + icon_info = + gtk_icon_theme_lookup_icon(icon_theme, "text-x-generic", size, + GTK_ICON_LOOKUP_USE_BUILTIN); + + pixbuf = gtk_icon_info_load_icon(icon_info, &error); + if (pixbuf == NULL) { + if (error && error->message) + g_warning("could not load icon pixbuf: %s\n", error->message); + g_clear_error(&error); + } + + gtk_icon_info_free(icon_info); + g_strfreev(icon_names); + + return pixbuf; +} + + +static GdkPixbuf *get_file_icon_pixbuf(GFileIcon * icon, int size) +{ + GFile *file; + char *filename; + GdkPixbuf *pixbuf; + + file = g_file_icon_get_file(icon); + filename = g_file_get_path(file); + pixbuf = gdk_pixbuf_new_from_file_at_size(filename, size, -1, NULL); + g_free(filename); + g_object_unref(file); + + return pixbuf; +} + + +static GdkPixbuf *_get_icon_pixbuf(GIcon * icon, int size, + GtkIconTheme * theme) +{ + if (icon == NULL) + return NULL; + if (G_IS_THEMED_ICON(icon)) + return get_themed_icon_pixbuf(G_THEMED_ICON(icon), size, theme); + if (G_IS_FILE_ICON(icon)) + return get_file_icon_pixbuf(G_FILE_ICON(icon), size); + return NULL; +} + + +static GdkPixbuf *icon_cache_get_mime_type_icon(IconCache * icon_cache, + const char *mime_type) +{ + GIcon *icon; + const char *key = NULL; + GdkPixbuf *pixbuf; + + icon = g_content_type_get_icon(mime_type); + key = _icon_cache_get_icon_key(icon); + + if (key == NULL) + key = VOID_PIXBUF_KEY; + + pixbuf = g_hash_table_lookup(icon_cache->cache, key); + if (pixbuf != NULL) { + g_object_ref(pixbuf); + g_object_unref(G_OBJECT(icon)); + return pixbuf; + } + + pixbuf = + _get_icon_pixbuf(icon, icon_cache->icon_size, + icon_cache->icon_theme); + if (pixbuf != NULL) + g_hash_table_insert(icon_cache->cache, (gpointer) key, + g_object_ref(pixbuf)); + + g_object_unref(G_OBJECT(icon)); + + return pixbuf; +} + +GdkPixbuf *gtr_get_mime_type_icon(const char *mime_type, + GtkIconSize icon_size, + GtkWidget * for_widget) +{ + int n; + + switch (icon_size) { + case GTK_ICON_SIZE_MENU: + n = 1; + break; + case GTK_ICON_SIZE_SMALL_TOOLBAR: + n = 2; + break; + case GTK_ICON_SIZE_LARGE_TOOLBAR: + n = 3; + break; + case GTK_ICON_SIZE_BUTTON: + n = 4; + break; + case GTK_ICON_SIZE_DND: + n = 5; + break; + case GTK_ICON_SIZE_DIALOG: + n = 6; + break; + default /*GTK_ICON_SIZE_INVALID */ : + n = 0; + break; + } + + if (icon_cache[n] == NULL) + icon_cache[n] = icon_cache_new(for_widget, icon_size); + + return icon_cache_get_mime_type_icon(icon_cache[n], mime_type); +} + + +const char *gtr_get_mime_type_from_filename(const char *file G_GNUC_UNUSED) +{ + char *tmp = g_content_type_guess(file, NULL, 0, NULL); + const char *ret = get_static_string(tmp); + g_free(tmp); + return ret; +} |