source: branches/1.7x/gtk/icons.c @ 9869

Last change on this file since 9869 was 9869, checked in by charles, 13 years ago

(1.7x gtk) backport to 1.7x branch: r9563 #2605 "GIcon memory leak in GTK+ client"

File size: 7.3 KB
Line 
1/*
2 * icons.[ch] written by Paolo Bacchilega, who writes:
3 * "There is no problem for me, you can license my code under whatever licence you wish :)"
4 */
5
6#include <string.h> /* strcmp */
7#include <glib.h>
8#include <gtk/gtk.h>
9#include "icons.h"
10
11#ifdef HAVE_GIO
12 #if GTK_CHECK_VERSION( 2, 12, 0 )
13   #define USE_GIO_ICONS
14 #endif
15#endif
16
17#ifdef USE_GIO_ICONS
18 #include <gio/gio.h>
19#endif
20
21#define VOID_PIXBUF_KEY "void-pixbuf"
22
23#ifdef USE_GIO_ICONS
24static const char *
25get_static_string( const char *s )
26{
27    static GStringChunk * static_strings = NULL;
28
29     if( s == NULL )
30         return NULL;
31
32     if( static_strings == NULL )
33         static_strings = g_string_chunk_new( 1024 );
34
35    return g_string_chunk_insert_const( static_strings, s );
36}
37#endif
38
39
40typedef struct {
41    GtkIconTheme * icon_theme;
42    int            icon_size;
43    GHashTable   * cache;
44} IconCache;
45
46
47static IconCache *icon_cache[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
48
49
50static GdkPixbuf*
51create_void_pixbuf (int width,
52                    int height)
53{
54    GdkPixbuf *p;
55
56    p = gdk_pixbuf_new( GDK_COLORSPACE_RGB,
57                        TRUE,
58                        8,
59                        width,
60                        height);
61    gdk_pixbuf_fill( p, 0xFFFFFF00 );
62
63    return p;
64}
65
66
67static int
68get_size_in_pixels( GtkWidget   * widget,
69                    GtkIconSize   icon_size )
70{
71    int width, height;
72
73    gtk_icon_size_lookup_for_settings( gtk_widget_get_settings( widget ),
74                                       icon_size,
75                                       &width, 
76                                       &height );
77    return MAX( width, height );
78}
79
80
81static IconCache * 
82icon_cache_new (GtkWidget * for_widget,
83                int         icon_size)
84{
85    IconCache * icon_cache;
86       
87    g_return_val_if_fail( for_widget != NULL, NULL );
88       
89    icon_cache = g_new0( IconCache, 1 );
90    icon_cache->icon_theme = gtk_icon_theme_get_for_screen( gtk_widget_get_screen( for_widget )); 
91    icon_cache->icon_size = get_size_in_pixels( for_widget, icon_size );
92    icon_cache->cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
93       
94    g_hash_table_insert( icon_cache->cache, (void*)VOID_PIXBUF_KEY, create_void_pixbuf( icon_cache->icon_size, icon_cache->icon_size ));
95       
96    return icon_cache;
97}
98
99#ifdef USE_GIO_ICONS
100static const char *
101_icon_cache_get_icon_key( GIcon * icon )
102{
103    const char * key = NULL;
104       
105    if ( G_IS_THEMED_ICON( icon )) {
106        char ** icon_names;
107        char  * name;
108       
109        g_object_get( icon, "names", &icon_names, NULL );
110        name = g_strjoinv( ",", icon_names );
111               
112        key = get_static_string( name );
113               
114        g_free( name );
115        g_strfreev( icon_names );       
116    }
117    else if ( G_IS_FILE_ICON( icon )) {
118        GFile * file;
119        char  * filename;
120
121        file = g_file_icon_get_file( G_FILE_ICON( icon ));
122        filename = g_file_get_path( file );
123               
124        key = get_static_string( filename );
125               
126        g_free( filename );
127        g_object_unref( file );
128    }
129       
130    return key;
131}
132
133
134static GdkPixbuf *
135get_themed_icon_pixbuf( GThemedIcon  *icon,
136                        int           size,
137                        GtkIconTheme *icon_theme )
138{
139    char        ** icon_names = NULL;
140    GtkIconInfo  * icon_info;
141    GdkPixbuf    * pixbuf;
142    GError       * error = NULL;
143
144    g_object_get( icon, "names", &icon_names, NULL );
145
146    icon_info = gtk_icon_theme_choose_icon( icon_theme, (const char **)icon_names, size, 0 );
147    if ( icon_info == NULL )
148        icon_info = gtk_icon_theme_lookup_icon( icon_theme, "text-x-generic", size, GTK_ICON_LOOKUP_USE_BUILTIN );
149
150    pixbuf = gtk_icon_info_load_icon( icon_info, &error );
151    if ( pixbuf == NULL ) {
152        if( error && error->message )
153            g_warning( "could not load icon pixbuf: %s\n", error->message );
154        g_clear_error( &error );
155    }
156
157    gtk_icon_info_free( icon_info );
158    g_strfreev( icon_names );
159
160    return pixbuf;
161}
162
163
164static GdkPixbuf *
165get_file_icon_pixbuf( GFileIcon *icon,
166                      int        size )
167{
168    GFile     * file;
169    char      * filename;
170    GdkPixbuf * pixbuf;
171       
172    file = g_file_icon_get_file( icon );
173    filename = g_file_get_path( file );
174    pixbuf = gdk_pixbuf_new_from_file_at_size( filename, size, -1, NULL );
175    g_free( filename );
176    g_object_unref( file );
177       
178    return pixbuf;
179}
180
181
182static GdkPixbuf *
183_get_icon_pixbuf( GIcon        *icon,
184                  int           size,
185                  GtkIconTheme *theme )
186{
187    if ( icon == NULL )
188        return NULL;
189    if ( G_IS_THEMED_ICON (icon) )
190        return get_themed_icon_pixbuf( G_THEMED_ICON( icon ), size, theme );
191    if ( G_IS_FILE_ICON (icon) )
192        return get_file_icon_pixbuf( G_FILE_ICON( icon ), size );
193    return NULL;
194}
195
196                 
197static GdkPixbuf *
198icon_cache_get_mime_type_icon( IconCache  * icon_cache,
199                               const char * mime_type )
200{
201    GIcon      * icon;
202    const char * key = NULL;
203    GdkPixbuf  * pixbuf;
204
205    icon = g_content_type_get_icon( mime_type );
206    key = _icon_cache_get_icon_key( icon );
207       
208    if (key == NULL)
209        key = VOID_PIXBUF_KEY;
210
211    pixbuf = g_hash_table_lookup( icon_cache->cache, key );
212    if (pixbuf != NULL) {
213        g_object_ref( pixbuf );
214        g_object_unref( G_OBJECT( icon ) );
215        return pixbuf;
216    }
217
218    pixbuf = _get_icon_pixbuf( icon, icon_cache->icon_size, icon_cache->icon_theme );
219    if( pixbuf != NULL )
220        g_hash_table_insert( icon_cache->cache, (gpointer) key, g_object_ref( pixbuf ) );
221
222    g_object_unref( G_OBJECT( icon ) );
223       
224    return pixbuf;
225}
226
227#else /* USE_GIO_ICONS */
228
229static GdkPixbuf *
230icon_cache_get_mime_type_icon( IconCache  * icon_cache,
231                               const char * mime_type )
232{
233    GdkPixbuf  * pixbuf;
234    const char * stock_name;
235
236    if( !strcmp( mime_type, DIRECTORY_MIME_TYPE ) )
237        stock_name = GTK_STOCK_DIRECTORY;
238    else
239        stock_name = GTK_STOCK_FILE;
240
241    pixbuf = g_hash_table_lookup( icon_cache->cache, stock_name );
242
243    if( pixbuf != NULL )
244    {
245        g_object_ref( pixbuf );
246        return pixbuf;
247    }
248
249    pixbuf = gtk_icon_theme_load_icon( icon_cache->icon_theme,
250                                       stock_name,
251                                       icon_cache->icon_size,
252                                       0, NULL );
253    g_hash_table_insert( icon_cache->cache, (gpointer) stock_name, g_object_ref( pixbuf ));
254    return pixbuf;
255}
256
257#endif
258
259
260GdkPixbuf * 
261get_mime_type_icon( const char   * mime_type,
262                    GtkIconSize    icon_size,
263                    GtkWidget    * for_widget )
264{
265    int n;
266   
267    switch ( icon_size ) {
268        case GTK_ICON_SIZE_MENU:            n = 1; break;
269        case GTK_ICON_SIZE_SMALL_TOOLBAR:   n = 2; break;
270        case GTK_ICON_SIZE_LARGE_TOOLBAR:   n = 3; break;
271        case GTK_ICON_SIZE_BUTTON:          n = 4; break;
272        case GTK_ICON_SIZE_DND:             n = 5; break;
273        case GTK_ICON_SIZE_DIALOG:          n = 6; break; 
274        default /*GTK_ICON_SIZE_INVALID*/:  n = 0; break;
275    }   
276
277    if( icon_cache[n] == NULL )
278        icon_cache[n] = icon_cache_new( for_widget, icon_size );
279
280    return icon_cache_get_mime_type_icon( icon_cache[n], mime_type );
281}                   
282
283
284const char * 
285get_mime_type_from_filename( const char * file G_GNUC_UNUSED )
286{
287#ifdef USE_GIO_ICONS
288    char * tmp = g_content_type_guess( file, NULL, 0, NULL );
289    const char * ret = get_static_string( tmp );
290    g_free( tmp );
291    return ret;
292#else
293    return "uncertain";
294#endif
295}
Note: See TracBrowser for help on using the repository browser.