/** * @file imageloader.cc * @copyright (C) 2001-2006 Marcus Bjurman\n * @copyright (C) 2007-2012 Piotr Eljasiak\n * @copyright (C) 2013-2023 Uwe Scholz\n * * @copyright This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * @copyright This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @copyright You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "gnome-cmd-includes.h" #include "imageloader.h" #include "utils.h" #include "gnome-cmd-data.h" using namespace std; struct CacheEntry { gboolean dead_end; GdkPixmap *pixmap; GdkBitmap *mask; GdkPixmap *lnk_pixmap; GdkBitmap *lnk_mask; }; static const gchar *file_type_pixmap_files[] = { "file-type-icons/file_type_regular.xpm", "file-type-icons/file_type_regular.xpm", "file-type-icons/file_type_dir.xpm", "file-type-icons/file_type_fifo.xpm", "file-type-icons/file_type_socket.xpm", "file-type-icons/file_type_char_device.xpm", "file-type-icons/file_type_block_device.xpm", "file-type-icons/file_type_symlink.xpm" }; #define NUM_FILE_TYPE_PIXMAPS G_N_ELEMENTS(file_type_pixmap_files) static const gchar *pixmap_files[NUM_PIXMAPS] = {"", "gnome_cmd_arrow_up.xpm", "gnome_cmd_arrow_down.xpm", "gnome_cmd_arrow_blank.xpm", "gnome-commander.svg", "exec_wheel.xpm", "menu_bookmark.xpm", "overlay_symlink.xpm", "overlay_umount.xpm", "internal-viewer.svg"}; static const gchar *categories[][2] = {{"text", "gnome-text-plain.png"}, {"video", "gnome-video-plain.png"}, {"image", "gnome-image-plain.png"}, {"audio", "gnome-audio-plain.png"}, {"pack", "gnome-pack-plain.png"}, {"font", "gnome-font-plain.png"}}; static GnomeCmdPixmap *pixmaps[NUM_PIXMAPS]; static CacheEntry file_type_pixmaps[NUM_FILE_TYPE_PIXMAPS]; static GHashTable *mime_cache = nullptr; static GdkPixbuf *symlink_pixbuf = nullptr; static const gint ICON_SIZE = 16; static gboolean load_icon (const gchar *icon_path, GdkPixmap **pm, GdkBitmap **bm, GdkPixmap **lpm, GdkBitmap **lbm); /* * Load application pixmaps */ void IMAGE_init () { mime_cache = g_hash_table_new (g_str_hash, g_str_equal); // Load misc icons for (gint i=1; ipixmap, &e->mask, &e->lnk_pixmap, &e->lnk_mask)) { gchar *path2 = g_build_filename ("../pixmaps", pixmap_files[i], nullptr); g_warning (_("Couldn’t load installed pixmap, trying to load %s instead"), path2); if (!load_icon (path2, &e->pixmap, &e->mask, &e->lnk_pixmap, &e->lnk_mask)) g_warning (_("Can’t find the pixmap anywhere. Make sure you have installed the program or is executing gnome-commander from the gnome-commander-%s/src directory"), PACKAGE_VERSION); g_free (path2); } g_free (path); } register_gnome_commander_stock_icons (); } GnomeCmdPixmap *IMAGE_get_gnome_cmd_pixmap (Pixmap pixmap_id) { return pixmap_id > 0 && pixmap_id < NUM_PIXMAPS ? pixmaps[pixmap_id] : nullptr; } /** * Takes a mime-type as argument and returns the filename * of the image representing it. */ inline char *get_mime_icon_name (const gchar *mime_type) { gint i; gchar *icon_name; gchar *tmp = g_strdup (mime_type); gint l = strlen(tmp); // replace '/' with '-' for (i=0; ipixbuf; } sym_w = gdk_pixbuf_get_width (symlink_pixbuf); sym_h = gdk_pixbuf_get_height (symlink_pixbuf); // Scale the pixmap if needed h = gnome_cmd_data.options.icon_size; if (h != gdk_pixbuf_get_height (pixbuf)) { scale = (gfloat)h/(gfloat)gdk_pixbuf_get_height (pixbuf); w = (gint)(scale*(gfloat)gdk_pixbuf_get_width (pixbuf)); GdkPixbuf *tmp = gdk_pixbuf_scale_simple (pixbuf, w, h, gnome_cmd_data.options.icon_scale_quality); g_object_unref (pixbuf); pixbuf = tmp; } // Create a copy with a symlink overlay w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); x = w - sym_w; y = h - sym_h; if (x < 0) { sym_w -= x; x = 0; } if (y < 0) { sym_h -= y; y = 0; } lnk_pixbuf = gdk_pixbuf_copy (pixbuf); gdk_pixbuf_copy_area (symlink_pixbuf, 0, 0, sym_w, sym_h, lnk_pixbuf, x, y); gdk_pixbuf_render_pixmap_and_mask (pixbuf, pm, bm, 128); gdk_pixbuf_render_pixmap_and_mask (lnk_pixbuf, lpm, lbm, 128); g_object_unref (pixbuf); g_object_unref (lnk_pixbuf); return TRUE; } /** * Tries to load an image for the specifed mime-type in the specifed directory. * If symlink is true a smaller symlink image is painted over the image to indicate this. */ static gboolean get_mime_icon_in_dir (const gchar *icon_dir, guint32 type, const gchar *mime_type, gboolean symlink, GdkPixmap **pixmap, GdkBitmap **mask) { if (!mime_type) return FALSE; if (type == G_FILE_TYPE_SYMBOLIC_LINK) return FALSE; auto entry = static_cast (g_hash_table_lookup (mime_cache, mime_type)); if (!entry) { // We're looking up this mime-type for the first time gchar *icon_path = nullptr; gchar *icon_path2 = nullptr; gchar *icon_path3 = nullptr; GdkPixmap *pm = nullptr; GdkBitmap *bm = nullptr; GdkPixmap *lpm = nullptr; GdkBitmap *lbm = nullptr; DEBUG ('y', "Looking up pixmap for: %s\n", mime_type); icon_path = get_mime_document_type_icon_path (mime_type, icon_dir); DEBUG('z', "\nSearching for icon for %s\n", mime_type); DEBUG('z', "Trying %s\n", icon_path); if (icon_path) load_icon (icon_path, &pm, &bm, &lpm, &lbm); if (!pm) { icon_path2 = get_category_icon_path (mime_type, icon_dir); DEBUG('z', "Trying %s\n", icon_path2); if (icon_path2) load_icon (icon_path2, &pm, &bm, &lpm, &lbm); } if (!pm) { icon_path3 = get_mime_file_type_icon_path (type, icon_dir); DEBUG('z', "Trying %s\n", icon_path3); if (icon_path3) load_icon (icon_path3, &pm, &bm, &lpm, &lbm); } g_free (icon_path); g_free (icon_path2); g_free (icon_path3); entry = g_new0 (CacheEntry, 1); entry->dead_end = (pm == nullptr || bm == nullptr); entry->pixmap = pm; entry->mask = bm; entry->lnk_pixmap = lpm; entry->lnk_mask = lbm; DEBUG('z', "Icon found?: %s\n", entry->dead_end ? "No" : "Yes"); g_hash_table_insert (mime_cache, g_strdup (mime_type), entry); } *pixmap = symlink ? entry->lnk_pixmap : entry->pixmap; *mask = symlink ? entry->lnk_mask : entry->mask; return !entry->dead_end; } static gboolean get_mime_icon (guint32 type, const gchar *mime_type, gboolean symlink, GdkPixmap **pixmap, GdkBitmap **mask) { if (get_mime_icon_in_dir (gnome_cmd_data.options.theme_icon_dir, type, mime_type, symlink, pixmap, mask)) return TRUE; else return FALSE; } inline gboolean get_type_icon (guint32 type, gboolean symlink, GdkPixmap **pixmap, GdkBitmap **mask) { if (type >= NUM_FILE_TYPE_PIXMAPS) return FALSE; *pixmap = symlink ? file_type_pixmaps[type].lnk_pixmap : file_type_pixmaps[type].pixmap; *mask = symlink ? file_type_pixmaps[type].lnk_mask : file_type_pixmaps[type].mask; return TRUE; } gboolean IMAGE_get_pixmap_and_mask (guint32 type, const gchar *mime_type, gboolean symlink, GdkPixmap **pixmap, GdkBitmap **mask) { #if defined (__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch-enum" #endif switch (gnome_cmd_data.options.layout) { case GNOME_CMD_LAYOUT_TYPE_ICONS: return get_type_icon (type, symlink, pixmap, mask); case GNOME_CMD_LAYOUT_MIME_ICONS: if (!get_mime_icon (type, mime_type, symlink, pixmap, mask)) return get_type_icon (type, symlink, pixmap, mask); return TRUE; default: return FALSE; } #if defined (__GNUC__) #pragma GCC diagnostic pop #endif return FALSE; } static gboolean remove_entry (const gchar *key, CacheEntry *entry, gpointer user_data) { g_return_val_if_fail (entry, TRUE); if (!entry->dead_end) { g_object_unref (entry->pixmap); g_object_unref (entry->mask); } g_free (entry); return TRUE; } void IMAGE_clear_mime_cache () { g_return_if_fail (mime_cache != nullptr); g_hash_table_foreach_remove (mime_cache, (GHRFunc) remove_entry, nullptr); } void IMAGE_free () { for (int i=0; i