Ticket #628: mime_type_icons.patch

File mime_type_icons.patch, 17.2 KB (added by paobac, 13 years ago)

added a cache to speed up the icon loading

  • gtk/icons.c

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

     
     1
     2#ifndef ICONS_H
     3#define ICONS_H
     4
     5#define DIRECTORY_MIME_TYPE "folder"
     6
     7const char * get_mime_type_from_filename( const char *file );
     8
     9GdkPixbuf * get_mime_type_icon( const char   * mime_type,
     10                                GtkIconSize    icon_size,
     11                                GtkWidget    * for_widget );
     12
     13#endif
  • gtk/tr-core.c

     
    4545#include "tr-torrent.h"
    4646#include "util.h"
    4747#include "actions.h"
     48#include "icons.h"
    4849
    4950static void     maybeInhibitHibernation( TrCore * core );
    5051
     
    6465    gboolean        have_inhibit_cookie;
    6566    gboolean        dbus_error;
    6667    guint           inhibit_cookie;
    67     GtkTreeModel *  model;
     68    GtkWindow *     window;
     69    GtkTreeModel  * model;
    6870    tr_session *    session;
    6971};
    7072
     
    617619        G_TYPE_STRING,    /* collated name */
    618620        TR_TORRENT_TYPE,  /* TrTorrent object */
    619621        G_TYPE_POINTER,   /* tr_torrent* */
    620         G_TYPE_INT        /* tr_stat()->status */
     622        G_TYPE_INT,       /* tr_stat()->status */
     623        GDK_TYPE_PIXBUF,  /* icon */
    621624    };
    622625
    623626    p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE( self,
     
    704707    }
    705708}
    706709
     710void
     711tr_core_set_window( TrCore    * core,
     712                    GtkWindow * w )
     713{
     714        core->priv->window = w;
     715}
     716
    707717GtkTreeModel *
    708718tr_core_model( TrCore * core )
    709719{
     
    792802    char *          collated = doCollate( inf->name );
    793803    GtkListStore *  store = GTK_LIST_STORE( tr_core_model( self ) );
    794804    GtkTreeIter     unused;
     805    GdkPixbuf *     icon;
     806    const char *    mime_type;
     807   
     808    if (inf->fileCount > 1)
     809        mime_type = DIRECTORY_MIME_TYPE;
     810    else
     811        mime_type = get_mime_type_from_filename( inf->files[0].name );   
     812    icon = get_mime_type_icon( mime_type, GTK_ICON_SIZE_DIALOG, GTK_WIDGET( self->priv->window ));
    795813
    796814    gtk_list_store_insert_with_values( store, &unused, 0,
     815                                       MC_ICON,          icon,
    797816                                       MC_NAME,          inf->name,
    798817                                       MC_NAME_COLLATED, collated,
    799818                                       MC_TORRENT,       gtor,
     
    802821                                       -1 );
    803822
    804823    /* cleanup */
     824    if (icon != NULL)
     825        g_object_unref( icon );
    805826    g_object_unref( G_OBJECT( gtor ) );
    806827    g_free( collated );
    807828}
  • gtk/tr-core.h

     
    101101
    102102void           tr_core_close( TrCore* );
    103103
     104void tr_core_set_window( TrCore    * core,
     105                         GtkWindow * w );
     106
    104107/* Return the model used without incrementing the reference count */
    105108GtkTreeModel * tr_core_model( TrCore * self );
    106109
     
    218221    MC_TORRENT,
    219222    MC_TORRENT_RAW,
    220223    MC_ACTIVITY,
     224    MC_ICON,
    221225    MC_ROW_COUNT
    222226};
    223227
  • gtk/main.c

     
    481481        g_signal_connect( win, "size-allocate",
    482482                          G_CALLBACK( onMainWindowSizeAllocated ), cbdata );
    483483
     484        tr_core_set_window( cbdata->core, win );
     485
    484486        appsetup( win, argfiles, cbdata, startpaused, startminimized );
    485487        tr_sessionSetRPCCallback( h, onRPCChanged, cbdata );
    486488        gtr_blocklist_maybe_autoupdate( cbdata->core );
  • gtk/Makefile.am

     
    3535    details.h \
    3636    dialogs.h \
    3737    hig.h \
     38    icons.h \
    3839    file-list.h \
    3940    lock.h \
    4041    logo.h \
     
    6869    dialogs.c \
    6970    file-list.c \
    7071    hig.c \
     72    icons.c \
    7173    main.c \
    7274    makemeta-ui.c \
    7375    msgwin.c \
  • gtk/file-list.c

     
    3434
    3535#include "file-list.h"
    3636#include "hig.h"
     37#include "icons.h"
    3738
    3839enum
    3940{
     
    4950
    5051enum
    5152{
    52     FC_STOCK,
     53    FC_ICON,
    5354    FC_LABEL,
    5455    FC_PROG,
    5556    FC_KEY,
     
    103104***/
    104105
    105106static void
    106 parsepath( const tr_torrent * tor,
    107            GtkTreeStore *     store,
    108            GtkTreeIter *      ret,
    109            const char *       path,
    110            tr_file_index_t    index,
    111            uint64_t           size )
     107parsepath( GtkWidget         * w,
     108           const tr_torrent  * tor,
     109           GtkTreeStore      * store,
     110           GtkTreeIter       * ret,
     111           const char        * path,
     112           tr_file_index_t     index,
     113           uint64_t            size )
    112114{
    113115    GtkTreeModel * model;
    114     GtkTreeIter *  parent, start, iter;
    115     char *         file, * lower, * mykey;
    116     const char *   stock;
     116    GtkTreeIter  * parent, start, iter;
     117    char         * file, * lower, * mykey;
    117118    int            priority = 0;
    118119    gboolean       enabled = TRUE;
    119120    gboolean       is_file;
    120 
     121    GdkPixbuf    * icon;
     122    const char   * mime_type;
     123   
    121124    model  = GTK_TREE_MODEL( store );
    122125    parent = NULL;
    123126    file   = g_path_get_basename( path );
    124127    if( 0 != strcmp( file, path ) )
    125128    {
    126129        char * dir = g_path_get_dirname( path );
    127         parsepath( tor, store, &start, dir, index, size );
     130        parsepath( w, tor, store, &start, dir, index, size );
    128131        parent = &start;
    129132        g_free( dir );
    130133    }
     
    145148    gtk_tree_store_append( store, &iter, parent );
    146149    if( ( is_file = !ret ) )
    147150    {
    148         stock = GTK_STOCK_FILE;
    149151        priority = tr_torrentGetFilePriority( tor, index );
    150152        enabled  = tr_torrentGetFileDL( tor, index );
     153        mime_type = get_mime_type_from_filename( file );
    151154    }
    152155    else
    153156    {
    154         stock = GTK_STOCK_DIRECTORY;
    155157        size  = 0;
     158        mime_type = DIRECTORY_MIME_TYPE;
    156159    }
    157160
     161    icon = get_mime_type_icon( mime_type, GTK_ICON_SIZE_MENU, w );
     162
    158163#if 0
    159164    gtk_tree_store_set( store, &iter, FC_INDEX, index,
    160                         FC_LABEL, file,
    161                         FC_KEY, mykey,
    162                         FC_STOCK, stock,
    163                         FC_PRIORITY, priority,
    164                         FC_ENABLED, enabled,
    165                         FC_IS_FILE, is_file,
    166                         FC_SIZE, size,
    167                         FC_HAVE, 0,
    168                         -1 );
     165                                      FC_LABEL, file,
     166                                      FC_KEY, mykey,
     167                                      FC_ICON, icon,
     168                                      FC_PRIORITY, priority,
     169                                      FC_ENABLED, enabled,
     170                                      FC_IS_FILE, is_file,
     171                                      FC_SIZE, size,
     172                                      FC_HAVE, 0,
     173                                      -1 );
    169174#else
    170175    gtk_tree_store_set( store, &iter, FC_INDEX, index, -1 );
    171176    gtk_tree_store_set( store, &iter, FC_LABEL, file, -1 );
    172177    gtk_tree_store_set( store, &iter, FC_KEY, mykey, -1 );
    173     gtk_tree_store_set( store, &iter, FC_STOCK, stock, -1 );
     178    gtk_tree_store_set( store, &iter, FC_ICON, icon, -1 );
    174179    gtk_tree_store_set( store, &iter, FC_PRIORITY, priority, -1 );
    175180    gtk_tree_store_set( store, &iter, FC_ENABLED, enabled, -1 );
    176181    gtk_tree_store_set( store, &iter, FC_IS_FILE, is_file, -1 );
     
    178183    gtk_tree_store_set( store, &iter, FC_HAVE, 0, -1 );
    179184#endif
    180185
     186    if (icon != NULL)
     187        g_object_unref( icon );
     188
    181189done:
    182190    g_free( mykey );
    183191    g_free( lower );
     
    447455
    448456    /* instantiate the model */
    449457    store = gtk_tree_store_new ( N_FILE_COLS,
    450                                  G_TYPE_STRING,    /* stock */
     458                                 GDK_TYPE_PIXBUF,  /* icon */
    451459                                 G_TYPE_STRING,    /* label */
    452460                                 G_TYPE_INT,       /* prog [0..100] */
    453461                                 G_TYPE_STRING,    /* key */
     
    478486            const char * base =
    479487                g_path_is_absolute( path ) ? g_path_skip_root( path ) :
    480488                path;
    481             parsepath( tor, store, NULL, base, i, inf->files[i].length );
     489            parsepath( w, tor, store, NULL, base, i, inf->files[i].length );
    482490        }
    483491
    484492        refresh( data );
     
    804812                                                NULL ) );
    805813    rend = gtk_cell_renderer_pixbuf_new( );
    806814    gtk_tree_view_column_pack_start( col, rend, FALSE );
    807     gtk_tree_view_column_add_attribute( col, rend, "stock-id", FC_STOCK );
     815    gtk_tree_view_column_add_attribute( col, rend, "pixbuf", FC_ICON );
    808816    /* add text renderer */
    809817    rend = gtk_cell_renderer_text_new( );
    810818    g_object_set( rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
  • gtk/tr-window.c

     
    150150
    151151    p->selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
    152152
     153    p->column = col = GTK_TREE_VIEW_COLUMN (g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,                 
     154        "title", _("Torrent"),
     155        "resizable", TRUE,
     156        "sizing", GTK_TREE_VIEW_COLUMN_FIXED,
     157        NULL));
     158
     159    r = gtk_cell_renderer_pixbuf_new();
     160    gtk_tree_view_column_pack_start( col, r, FALSE );
     161    gtk_tree_view_column_add_attribute( col, r, "pixbuf", MC_ICON );
     162
    153163    p->renderer = r = torrent_cell_renderer_new( );
    154     p->column = col = gtk_tree_view_column_new_with_attributes(
    155                     _( "Torrent" ), r, "torrent", MC_TORRENT_RAW, NULL );
    156     g_object_set( G_OBJECT( col ), "resizable", TRUE,
    157                   "sizing", GTK_TREE_VIEW_COLUMN_FIXED,
    158                   NULL );
     164    gtk_tree_view_column_pack_start( col, r, FALSE );
     165    gtk_tree_view_column_add_attribute( col, r, "torrent", MC_TORRENT_RAW );
     166   
     167    /*p->column = col = gtk_tree_view_column_new_with_attributes(
     168        _("Torrent"), r, "torrent", MC_TORRENT_RAW, NULL );
     169    g_object_set( G_OBJECT(col), "resizable", TRUE,
     170                                 "sizing", GTK_TREE_VIEW_COLUMN_FIXED,
     171                                 NULL );*/
    159172    gtk_tree_view_append_column( GTK_TREE_VIEW( view ), col );
    160173    g_object_set( r, "xpad", GUI_PAD_SMALL, "ypad", GUI_PAD_SMALL, NULL );
    161174