/* * icons.[ch] written by Paolo Bacchilega, who writes: * "There is no problem for me, you can license my code * under whatever licence you wish :)" * */ #include #include #include #include "icons.h" #define VOID_PIXBUF_KEY "void-pixbuf" static char const* get_static_string(char const* 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(GtkIconSize icon_size) { int width = 0; int height = 0; gtk_icon_size_lookup(icon_size, &width, &height); return MAX(width, height); } static IconCache* icon_cache_new(GtkWidget* for_widget, int icon_size) { g_return_val_if_fail(for_widget != NULL, NULL); IconCache* icons = g_new0(IconCache, 1); icons->icon_theme = gtk_icon_theme_get_for_screen(gtk_widget_get_screen(for_widget)); icons->icon_size = get_size_in_pixels(icon_size); icons->cache = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref); g_hash_table_insert(icons->cache, (void*)VOID_PIXBUF_KEY, create_void_pixbuf(icons->icon_size, icons->icon_size)); return icons; } static char const* _icon_cache_get_icon_key(GIcon* icon) { char const* 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, (char const**)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 != NULL && error->message != NULL) { g_warning("could not load icon pixbuf: %s\n", error->message); } g_clear_error(&error); } #if GTK_CHECK_VERSION(3, 8, 0) g_object_unref(icon_info); #else gtk_icon_info_free(icon_info); #endif 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* icons, char const* mime_type) { GIcon* icon = g_content_type_get_icon(mime_type); char const* key = _icon_cache_get_icon_key(icon); if (key == NULL) { key = VOID_PIXBUF_KEY; } g_return_val_if_fail(icons != NULL, NULL); GdkPixbuf* pixbuf = g_hash_table_lookup(icons->cache, key); if (pixbuf != NULL) { g_object_ref(pixbuf); g_object_unref(G_OBJECT(icon)); return pixbuf; } pixbuf = _get_icon_pixbuf(icon, icons->icon_size, icons->icon_theme); if (pixbuf != NULL) { g_hash_table_insert(icons->cache, (gpointer)key, g_object_ref(pixbuf)); } g_object_unref(G_OBJECT(icon)); return pixbuf; } GdkPixbuf* gtr_get_mime_type_icon(char const* 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); } char const* gtr_get_mime_type_from_filename(char const* file) { char* tmp = g_content_type_guess(file, NULL, 0, NULL); char const* ret = get_static_string(tmp); g_free(tmp); return ret; }