filetypes.c

Go to the documentation of this file.
00001 /*
00002  * File Name: filetypes.c
00003  */
00004 
00005 /*
00006  * This file is part of ctb.
00007  *
00008  * ctb is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * ctb is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021  
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 //----------------------------------------------------------------------------
00028 // Include Files
00029 //----------------------------------------------------------------------------
00030 
00031 #include "config.h"
00032 
00033 #include <gconf/gconf-client.h>
00034 #include <gdk/gdk.h>
00035 #include <glib.h>
00036 #include <string.h>
00037 
00038 #include "ctb_log.h"
00039 #include "filetypes.h"
00040 #include "i18n.h"
00041 
00042 
00043 //----------------------------------------------------------------------------
00044 // Type Declarations
00045 //----------------------------------------------------------------------------
00046 
00047 // detailed info per filetype
00048 typedef struct
00049         {
00050             gchar       *extension;             // file extension excluding the '.'
00051             gchar       *reference_ext;         // extension from which to use this details
00052             gboolean    is_directory;           // extension used for directory or file
00053             gchar       *icon_name;             // name of the icon, also used for bitmap filename
00054             gchar       *description;           // type description for this extension
00055             gchar       *viewer_cmd;            // command to start the corresponding viewer application
00056             GdkPixbuf   *pixbuf_icon    [N_FILEMODEL_THUMB_SIZES];  // cache for bitmaps loaded from icon files
00057             gboolean    generate_thumbnail;     // set to generate thumbnails for this filetype
00058         } filetype_info_t;
00059 
00060 
00061 //----------------------------------------------------------------------------
00062 // Constants
00063 //----------------------------------------------------------------------------
00064 
00065 static const gchar      *ICONS_DIRECTORY = DATADIR;
00066 static const gchar      *ICONFILE_PREFIX = "icon-";
00067 static const gchar      *ICONFILE_POSTFIX[ N_FILEMODEL_THUMB_SIZES ] =
00068                         {
00069                             "-mini.png",
00070                             "-small.png",
00071                             "-medium.png",
00072                             "-large.png"
00073                         };
00074 
00075 static const gchar      *ICONNAME_APPLICATION = "application";
00076 static const gchar      *ICONNAME_LIBRARY     = "sdcard";
00077 
00078 #define CTB_GCONF_PATH  "/apps/er/sys/ctb"
00079 #define REGKEY_SHOW_SDCARD  "show_sdcard"
00080 static const gchar      *REGKEY_FILETYPE_DIR = CTB_GCONF_PATH "/filetypes";
00081 
00082 // known filetypes
00083 static filetype_info_t  g_hardcoded_filetypes[] =
00084             {
00085                 // ext                      ref   is_dir icon_name  description     viewer_cmd icon thumb
00086                 { ""                      , NULL, TRUE , "folder",  N_("Folder"),   NULL,      {}, FALSE },
00087                 { ""                      , NULL, FALSE, "unknown", N_("Unknown"),  NULL,      {}, FALSE },
00088                 { FILE_EXT_SHORTCUT       , NULL, FALSE, "unknown", N_("Shortcut"), NULL,      {}, FALSE },
00089                 { FILE_EXT_SHORTCUT_TO_DIR, NULL, FALSE, "folder",  N_("Shortcut"), NULL,      {}, FALSE },
00090                 { NULL,                     NULL, FALSE, NULL,      NULL,           NULL,      {}, FALSE },
00091             };
00092 
00093 #define GCONF_BUFFER_SIZE                   128
00094 
00095 //----------------------------------------------------------------------------
00096 // Static Variables
00097 //----------------------------------------------------------------------------
00098 
00099 static GArray           *g_filetype_info = NULL;    // element: filetype_info_t*
00100 static GTree            *g_icon_cache = NULL;
00101 static GConfClient      *g_gconfclient = NULL;
00102 static gboolean         g_showdir = FALSE;
00103 
00104 
00105 //============================================================================
00106 // Local Function Definitions
00107 //============================================================================
00108 
00109 static filetype_info_t* find_filetype_info(const gchar    *file_ext,
00110                                            const gboolean is_directory,
00111                                            const gboolean with_default );
00112 
00113 //============================================================================
00114 // Functions Implementation
00115 //============================================================================
00116 
00117 static gchar *read_gconf_value(const gchar *dir,
00118                                const gchar *key,
00119                                GConfClient *client)
00120 {
00121     gchar buffer[GCONF_BUFFER_SIZE];
00122     gchar* value;
00123     g_assert(strlen(dir) + 1 + strlen(key) < GCONF_BUFFER_SIZE);
00124     snprintf(buffer, GCONF_BUFFER_SIZE-1, "%s/%s", dir, key);
00125     value = gconf_client_get_string(client, buffer, NULL);
00126     if (value == NULL) {
00127         ERRORPRINTF("gconf: cannot read %s", buffer);
00128     }
00129     return value;
00130 }
00131 
00132 
00133 static gboolean read_gconf_boolean(const gchar *dir,
00134                                    const gchar *key,
00135                                    GConfClient *client)
00136 {
00137     gboolean value = FALSE;
00138     gchar buffer[GCONF_BUFFER_SIZE];
00139     g_assert(strlen(dir) + 1 + strlen(key) < GCONF_BUFFER_SIZE);
00140     snprintf(buffer, GCONF_BUFFER_SIZE-1, "%s/%s", dir, key);
00141 
00142     value = gconf_client_get_bool(client, buffer, NULL);
00143     return value;
00144 }
00145 
00146 
00147 static void add_filetype_from_gconf(const gchar *dir,
00148         GConfClient *client)
00149 {
00150     gchar buffer[GCONF_BUFFER_SIZE];
00151     gchar *descr = NULL;
00152     gchar *viewer_cmd = NULL;
00153     gchar *icon_name = NULL;
00154     gchar *reference_ext = NULL;
00155     GSList *ext = NULL;
00156     gboolean generate_thumbnail = FALSE;
00157 
00158     descr = read_gconf_value(dir, "descr", client);
00159     if (!descr) goto out_error;
00160 
00161     viewer_cmd = read_gconf_value(dir, "viewer_cmd", client);
00162     if (!viewer_cmd) goto out_error;
00163 
00164     icon_name = read_gconf_value(dir, "icon_name", client);
00165     if (!icon_name) goto out_error;
00166 
00167     generate_thumbnail = read_gconf_boolean(dir, "generate_thumbnail", client);
00168 
00169     g_assert(strlen(dir) + strlen("/extensions") < GCONF_BUFFER_SIZE);
00170     snprintf(buffer, GCONF_BUFFER_SIZE-1, "%s/extensions", dir);
00171     GSList *extensions = gconf_client_get_list(client, buffer, GCONF_VALUE_STRING, NULL);
00172     if (extensions == NULL) {
00173         ERRORPRINTF("gconf: cannot read %s", buffer);
00174         goto out_error;
00175     }
00176 
00177     for (ext = extensions; ext; ext = g_slist_next(ext)) {
00178         if (find_filetype_info(ext->data, FALSE, FALSE) != NULL) {
00179             ERRORPRINTF("gconf: ext %s is already registered, skipping", (gchar*)ext->data);
00180             continue;
00181         }
00182 
00183         filetype_info_t newtype;
00184         memset(&newtype, 0x00, sizeof(newtype));
00185         newtype.extension          = g_strdup(ext->data);
00186         newtype.reference_ext      = g_strdup(reference_ext);
00187         newtype.is_directory       = FALSE;
00188         newtype.icon_name          = g_strdup(icon_name);
00189         newtype.description        = g_strdup(descr);
00190         newtype.viewer_cmd         = g_strdup(viewer_cmd);
00191         newtype.generate_thumbnail = generate_thumbnail;
00192         g_array_append_val(g_filetype_info, newtype);
00193 
00194         if (reference_ext == NULL) reference_ext = ext->data;
00195     }
00196     g_slist_foreach (extensions, (GFunc)g_free, NULL);
00197     g_slist_free(extensions);
00198 out_error:
00199     g_free(icon_name);
00200     g_free(viewer_cmd);
00201     g_free(descr);
00202 }
00203 
00204 
00205 static void add_filetypes_from_gconf()
00206 {
00207     GSList *types = NULL;
00208     GConfClient *client = gconf_client_get_default();
00209 
00210     gboolean exists = gconf_client_dir_exists(client, REGKEY_FILETYPE_DIR, NULL);
00211     if (exists == FALSE) {
00212         ERRORPRINTF("gconf: %s does not exist", REGKEY_FILETYPE_DIR);
00213         goto unref;
00214     }
00215 
00216     types = gconf_client_all_dirs(client, REGKEY_FILETYPE_DIR, NULL);
00217     if (types == NULL) {
00218         ERRORPRINTF("gconf: cannot read dir entries of %s", REGKEY_FILETYPE_DIR);
00219         goto unref;
00220     }
00221 
00222     g_slist_foreach (types, (GFunc)add_filetype_from_gconf, client);
00223     g_slist_foreach (types, (GFunc)g_free, NULL);
00224     g_slist_free(types);
00225 unref:
00226     g_object_unref(client);
00227 }
00228 
00229 
00230 static void add_hardcoded_filetypes()
00231 {
00232     filetype_info_t   *known_type = NULL;
00233     filetype_info_t   details;
00234 
00235     // fill array with hardcoded filetypes
00236     for ( known_type = g_hardcoded_filetypes ; known_type->extension ; known_type++ )
00237     {
00238         // set details
00239         memset(&details, 0x00, sizeof(details));
00240         details.extension       = g_strdup(known_type->extension     );
00241         details.reference_ext   = g_strdup(known_type->reference_ext );
00242         details.is_directory    = known_type->is_directory;
00243         details.icon_name       = g_strdup(known_type->icon_name     );
00244         details.description     = g_strdup(known_type->description   );
00245         details.viewer_cmd      = g_strdup(known_type->viewer_cmd    );
00246 
00247         // add to array
00248         g_array_append_val(g_filetype_info, details);
00249     }
00250 }
00251 
00252 
00253 static void on_gconf_key_changed(GConfClient *client,
00254                                  guint cnxn_id,
00255                                  GConfEntry *entry,
00256                                  gpointer user_data)
00257 {
00258     const gchar* key = gconf_entry_get_key(entry);
00259     if (strcmp(key, CTB_GCONF_PATH"/"REGKEY_SHOW_SDCARD) == 0) {
00260         const GConfValue* value = gconf_entry_get_value(entry);
00261         gboolean show = gconf_value_get_bool(value);
00262         g_showdir = show;
00263     }
00264 }
00265 
00266 
00267 void filetypes_init ( gboolean watch )
00268 {
00269     g_filetype_info = g_array_new( TRUE, TRUE, sizeof(filetype_info_t) );
00270     g_assert(g_filetype_info);
00271 
00272     add_hardcoded_filetypes();
00273     add_filetypes_from_gconf();
00274 
00275     if (watch) {
00276         g_gconfclient = gconf_client_get_default();
00277         g_assert(g_gconfclient);
00278         g_showdir = read_gconf_boolean(CTB_GCONF_PATH, REGKEY_SHOW_SDCARD, g_gconfclient);
00279 
00280         gconf_client_add_dir(g_gconfclient,
00281                              CTB_GCONF_PATH,
00282                              GCONF_CLIENT_PRELOAD_NONE,
00283                              NULL);
00284 
00285         gconf_client_notify_add(g_gconfclient,
00286                                 CTB_GCONF_PATH,
00287                                 on_gconf_key_changed,
00288                                 NULL,
00289                                 NULL,
00290                                 NULL);
00291     }
00292 }
00293 
00294 
00295 gboolean filetypes_showdir()
00296 {
00297     return g_showdir;
00298 }
00299 
00300 
00301 static filetype_info_t* find_filetype_info (const gchar *file_ext,
00302                                             const gboolean is_directory,
00303                                             const gboolean with_default )
00304 {
00305 
00306     g_assert(g_filetype_info);
00307 
00308 //    LOGPRINTF("file_ext [%s] is_dir [%d]", file_ext, is_directory);
00309     if (file_ext == NULL)
00310     {
00311         file_ext = "";
00312     }
00313 
00314     gboolean done  = FALSE;
00315     gboolean found = FALSE;
00316     filetype_info_t *ret = NULL;
00317     while ( !done )
00318     {
00319         filetype_info_t *details = (filetype_info_t*) g_filetype_info->data;
00320         while (details->extension)
00321         {
00322             if (details->is_directory == is_directory 
00323                  && g_ascii_strcasecmp( details->extension, file_ext ) == 0 )
00324             {
00325                 ret = details;
00326                 found = TRUE;
00327                 break;
00328             }
00329             else
00330             {
00331                 details++;
00332             }
00333         }
00334 
00335         if ( found )
00336         {
00337             gchar *ref_ext = details->reference_ext;
00338 //            LOGPRINTF( "found filetype [%s] ref [%s] icon_name [%s] descr [%s]",
00339 //                    file_ext, ref_ext, details->icon_name, details->description );
00340             if (ref_ext)
00341             {
00342                 return find_filetype_info( ref_ext, is_directory, with_default );
00343             }
00344             done = TRUE;
00345         }
00346         else if (*file_ext)
00347         {
00348             LOGPRINTF("unkown filetype [%s] is_dir [%d]", file_ext, is_directory);
00349             if (with_default)
00350             {
00351                 file_ext = "";
00352             }
00353             else
00354             {
00355                 done = TRUE;
00356             }
00357         }
00358         else
00359         {
00360             ERRORPRINTF("no default fileinfo for is_dir [%d]", is_directory);
00361             done = TRUE;
00362         }
00363     }
00364 
00365     return ret;
00366 }
00367 
00368 
00369 GdkPixbuf* get_icon_from_file_extension (const gchar                *file_ext,
00370                                          const gboolean              is_directory,
00371                                          const filemodel_thumbsize_t icon_size     )
00372 {
00373     GdkPixbuf *icon               = NULL;
00374 
00375     filetype_info_t *details = find_filetype_info(file_ext, is_directory, TRUE);
00376     if (details)
00377     {
00378         // get normal icon
00379         GdkPixbuf **p_pixbuf_icon = &(details->pixbuf_icon[icon_size]);
00380         icon = *p_pixbuf_icon;
00381         if (icon == NULL)
00382         {
00383             // load filetype icon from file
00384             gchar* icon_file = g_strdup_printf( "%s/%s%s%s",
00385                     ICONS_DIRECTORY,
00386                     ICONFILE_PREFIX,
00387                     details->icon_name,
00388                     ICONFILE_POSTFIX[icon_size] );
00389             GError *err = NULL;
00390             icon = gdk_pixbuf_new_from_file( icon_file, &err );
00391             if (icon) *p_pixbuf_icon = icon;
00392             else
00393             {
00394                 ERRORPRINTF("cannot load iconfile [%s] error [%s]", icon_file, err->message);
00395                 g_clear_error(&err);
00396             }
00397             g_free(icon_file);
00398         }
00399     }
00400     return icon;
00401 }
00402 
00403 
00404 GdkPixbuf* get_icon_application ( const filemodel_thumbsize_t icon_size)
00405 {
00406     return get_icon_from_file(ICONNAME_APPLICATION, icon_size);
00407 }
00408 
00409 
00410 GdkPixbuf* get_icon_library ( const filemodel_thumbsize_t icon_size)
00411 {
00412     return get_icon_from_file(ICONNAME_LIBRARY, icon_size);
00413 }
00414 
00415 
00416 GdkPixbuf* get_icon_delete_toggle(gboolean toggled, filemodel_thumbsize_t icon_size)
00417 {
00418     if (toggled) {
00419         return get_icon_from_file("delete-toggled", icon_size);
00420     } else {
00421         return get_icon_from_file("delete-untoggled", icon_size);
00422     }
00423 }
00424 
00425 gint compareString(gconstpointer a, gconstpointer b) {
00426     return strcmp((const gchar*)a, (const gchar*)b);
00427 }
00428 
00429 
00430 GdkPixbuf* get_icon_from_file(const gchar* icon_name, filemodel_thumbsize_t icon_size)
00431 {
00432     if (g_icon_cache == NULL) g_icon_cache = g_tree_new(compareString);
00433 
00434     g_assert(icon_name && *icon_name);
00435     gchar icon_file[256];
00436     snprintf(icon_file, 255, "%s/%s%s%s",
00437                                  ICONS_DIRECTORY,
00438                                  ICONFILE_PREFIX,
00439                                  icon_name,
00440                                  ICONFILE_POSTFIX[icon_size]);
00441     int len = strlen(ICONS_DIRECTORY) + strlen(ICONFILE_PREFIX) + 1;
00442     gchar* short_name = icon_file + len;
00443     gpointer cache = g_tree_lookup(g_icon_cache, short_name);
00444     GdkPixbuf *icon = NULL;
00445     if (cache) {
00446         icon = (GdkPixbuf *)cache;
00447     } else {
00448         GError *err = NULL;
00449         icon = gdk_pixbuf_new_from_file(icon_file, &err);
00450         if (icon) {
00451             g_tree_insert(g_icon_cache, g_strdup(short_name), icon);
00452         } else  {
00453             ERRORPRINTF("cannot load iconfile [%s] error [%s]", icon_file, err->message);
00454             g_clear_error(&err);
00455         }
00456     }
00457     return icon;
00458 }
00459 
00460 
00461 static void apply_icon_overlay ( const filemodel_thumbsize_t icon_size,
00462                                  GdkPixbuf *icon,
00463                                  const gchar *overlay_name)
00464 {
00465     if (icon == NULL) return;
00466 
00467     GdkPixbuf *overlay = get_icon_from_file(overlay_name, icon_size);
00468 
00469     // apply overlay to icon bitmap
00470     if (overlay)
00471     {
00472         gdk_pixbuf_composite( overlay,                      // src
00473                               icon,                         // dest
00474                               0, 0,                         // dest x, y
00475                               gdk_pixbuf_get_width(icon),   // dest width
00476                               gdk_pixbuf_get_height(icon),  // dest height
00477                               0.0, 0.0,                     // offset x, y
00478                               1.0, 1.0,                     // scale  x, y
00479                               GDK_INTERP_NEAREST,           // interpolation type: not needed, take the fastest
00480                               0xFF );                       // overall_alpha
00481     }
00482 }
00483 
00484 
00485 void apply_icon_overlay_shortcut ( const filemodel_thumbsize_t icon_size,
00486                                          GdkPixbuf             *icon     )
00487 {
00488     apply_icon_overlay( icon_size, icon, "overlay-shortcut");
00489 }
00490 
00491 
00492 void apply_icon_overlay_delete ( const filemodel_thumbsize_t icon_size,
00493                                  GdkPixbuf             *icon,
00494                                  gboolean toggled)
00495 {
00496     if (toggled)
00497         apply_icon_overlay( icon_size, icon, "overlay-delete-toggled");
00498     else
00499         apply_icon_overlay( icon_size, icon, "overlay-delete-untoggled");
00500 }
00501 
00502 
00503 const gchar* get_type_descr_from_file_extension ( const gchar    *file_ext,
00504                                                   const gboolean is_directory)
00505 {
00506     filetype_info_t *details = find_filetype_info(file_ext, is_directory, TRUE);
00507 
00508     const gchar *description = "";
00509     if (details)
00510     {
00511         if (details->description)
00512         {
00513             description = _( details->description );
00514         }
00515         else
00516         {
00517             ERRORPRINTF( "filetype [%s] is_dir [%d] has no description",
00518                          details->description, is_directory);
00519         }
00520     }
00521 
00522     return description;
00523 }
00524 
00525 
00526 gboolean is_drz_file_extension(const gchar *file_ext)
00527 {
00528     if ( strcmp( file_ext, FILE_EXT_DRZ ) == 0 )
00529     {
00530         return TRUE;
00531     }
00532     return FALSE;
00533 }
00534 
00535 
00536 gboolean is_shortcut_file_extension(const gchar *file_ext)
00537 {
00538     if (   strcmp( file_ext, FILE_EXT_SHORTCUT       ) == 0
00539         || strcmp( file_ext, FILE_EXT_SHORTCUT_TO_DIR) == 0 )
00540     {
00541         return TRUE;
00542     }
00543     return FALSE;
00544 }
00545 
00546 
00547 gboolean is_shortcut_file(const char* filename)
00548 {
00549     const char* ext = g_extension_pointer(filename);
00550     return is_shortcut_file_extension(ext);
00551 }
00552 
00553 
00554 // get viewer command for specified file extension
00555 const gchar* get_viewer_from_file_extension ( const gchar *file_ext )
00556 {
00557     filetype_info_t *details = find_filetype_info(file_ext, FALSE, FALSE);
00558 
00559     const gchar *viewer_cmd = (details) ?  details->viewer_cmd : NULL;
00560     return viewer_cmd;
00561 }
00562 
00563 
00564 gboolean get_generate_thumbnail ( const gchar *file_ext )
00565 {
00566     filetype_info_t *details = find_filetype_info(file_ext, FALSE, FALSE);
00567     return details->generate_thumbnail;
00568 }
00569 
00570 
00571 
00572 // copied from libgnome-2.6.1.1 gnome-util.c:
00573 /**
00574  * g_extension_pointer:
00575  * @path: A filename or file path.
00576  *
00577  * Extracts the extension from the end of a filename (the part after the final
00578  * '.' in the filename).
00579  *
00580  * Returns: A pointer to the extension part of the filename, or a
00581  * pointer to the end of the string if the filename does not
00582  * have an extension.
00583  */
00584 const char *
00585 g_extension_pointer (const char * path)
00586 {
00587    char * s;
00588 
00589    g_return_val_if_fail(path != NULL, NULL);
00590 
00591    /* get the dot in the last element of the path */
00592    char *t = strrchr(path, G_DIR_SEPARATOR);
00593    if (t != NULL)
00594       s = strrchr(t, '.');
00595    else
00596       s = strrchr(path, '.');
00597 
00598    if (s == NULL)
00599       return path + strlen(path); /* There is no extension. */
00600    else {
00601       ++s;      /* pass the . */
00602       return s;
00603    }
00604 }
Generated by  doxygen 1.6.2-20100208