/* * 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 #include #include "IconCache.h" #include "Utils.h" using namespace std::literals; Glib::ustring const DirectoryMimeType = "folder"s; Glib::ustring const UnknownMimeType = "unknown"s; namespace { auto const VoidPixbufKey = "void-pixbuf"s; struct IconCache { Glib::RefPtr icon_theme; int icon_size; std::unordered_map> cache; }; std::array, 7> icon_cache; Glib::RefPtr create_void_pixbuf(int width, int height) { auto const p = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, width, height); p->fill(0xFFFFFF00); return p; } int get_size_in_pixels(Gtk::IconSize icon_size) { int width = 0; int height = 0; Gtk::IconSize::lookup(icon_size, width, height); return std::max(width, height); } std::unique_ptr icon_cache_new(Gtk::Widget& for_widget, Gtk::IconSize icon_size) { auto icons = std::make_unique(); icons->icon_theme = Gtk::IconTheme::get_for_screen(for_widget.get_screen()); icons->icon_size = get_size_in_pixels(icon_size); icons->cache.try_emplace(VoidPixbufKey, create_void_pixbuf(icons->icon_size, icons->icon_size)); return icons; } std::string _icon_cache_get_icon_key(Glib::RefPtr const& icon) { std::string key; if (auto* const ticon = dynamic_cast(gtr_get_ptr(icon)); ticon != nullptr) { std::ostringstream names; for (auto const& name : ticon->get_names()) { names << name << ','; } key = names.str(); } else if (auto* const ficon = dynamic_cast(gtr_get_ptr(icon)); ficon != nullptr) { key = ficon->get_file()->get_path(); } return key; } Glib::RefPtr get_themed_icon_pixbuf(Gio::ThemedIcon& icon, int size, Gtk::IconTheme& icon_theme) { auto const icon_names = icon.get_names(); auto icon_info = icon_theme.choose_icon(icon_names, size); if (!bool{ icon_info }) { icon_info = icon_theme.lookup_icon("text-x-generic", size, Gtk::ICON_LOOKUP_USE_BUILTIN); } try { return icon_info.load_icon(); } catch (Glib::Error const& e) { g_warning("could not load icon pixbuf: %s\n", e.what().c_str()); return {}; } } Glib::RefPtr get_file_icon_pixbuf(Gio::FileIcon& icon, int size) { try { return Gdk::Pixbuf::create_from_file(icon.get_file()->get_path(), size, -1, false); } catch (Glib::Error const&) { return {}; } } Glib::RefPtr _get_icon_pixbuf(Glib::RefPtr const& icon, int size, Gtk::IconTheme& theme) { if (icon == nullptr) { return {}; } if (auto* const ticon = dynamic_cast(gtr_get_ptr(icon)); ticon != nullptr) { return get_themed_icon_pixbuf(*ticon, size, theme); } if (auto* const ficon = dynamic_cast(gtr_get_ptr(icon)); ficon != nullptr) { return get_file_icon_pixbuf(*ficon, size); } return {}; } Glib::RefPtr icon_cache_get_mime_type_icon(IconCache& icons, Glib::ustring const& mime_type) { auto icon = Gio::content_type_get_icon(mime_type); auto key = _icon_cache_get_icon_key(icon); if (key.empty()) { key = VoidPixbufKey; } if (auto pixbuf_it = icons.cache.find(key); pixbuf_it != icons.cache.end()) { return pixbuf_it->second; } auto const pixbuf = _get_icon_pixbuf(icon, icons.icon_size, *gtr_get_ptr(icons.icon_theme)); if (pixbuf != nullptr) { icons.cache.try_emplace(key, pixbuf); } return pixbuf; } } // namespace Glib::RefPtr gtr_get_mime_type_icon( Glib::ustring const& mime_type, Gtk::IconSize icon_size, Gtk::Widget& 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] == nullptr) { icon_cache[n] = icon_cache_new(for_widget, icon_size); } return icon_cache_get_mime_type_icon(*icon_cache[n], mime_type); } Glib::ustring gtr_get_mime_type_from_filename(std::string const& file) { bool result_uncertain; return Gio::content_type_guess(file, {}, result_uncertain); }