mirror of
https://github.com/transmission/transmission
synced 2024-12-27 01:57:52 +00:00
213 lines
4.9 KiB
C++
213 lines
4.9 KiB
C++
/*
|
|
* 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 <array>
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
|
|
#include <glibmm.h>
|
|
#include <giomm.h>
|
|
|
|
#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<Gtk::IconTheme> icon_theme;
|
|
int icon_size;
|
|
std::unordered_map<std::string, Glib::RefPtr<Gdk::Pixbuf>> cache;
|
|
};
|
|
|
|
std::array<std::unique_ptr<IconCache>, 7> icon_cache;
|
|
|
|
Glib::RefPtr<Gdk::Pixbuf> 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<IconCache> icon_cache_new(Gtk::Widget& for_widget, Gtk::IconSize icon_size)
|
|
{
|
|
auto icons = std::make_unique<IconCache>();
|
|
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<Gio::Icon> const& icon)
|
|
{
|
|
std::string key;
|
|
|
|
if (auto* const ticon = dynamic_cast<Gio::ThemedIcon*>(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<Gio::FileIcon*>(gtr_get_ptr(icon)); ficon != nullptr)
|
|
{
|
|
key = ficon->get_file()->get_path();
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
Glib::RefPtr<Gdk::Pixbuf> 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<Gdk::Pixbuf> 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& e)
|
|
{
|
|
return {};
|
|
}
|
|
}
|
|
|
|
Glib::RefPtr<Gdk::Pixbuf> _get_icon_pixbuf(Glib::RefPtr<Gio::Icon> const& icon, int size, Gtk::IconTheme& theme)
|
|
{
|
|
if (icon == nullptr)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (auto* const ticon = dynamic_cast<Gio::ThemedIcon*>(gtr_get_ptr(icon)); ticon != nullptr)
|
|
{
|
|
return get_themed_icon_pixbuf(*ticon, size, theme);
|
|
}
|
|
|
|
if (auto* const ficon = dynamic_cast<Gio::FileIcon*>(gtr_get_ptr(icon)); ficon != nullptr)
|
|
{
|
|
return get_file_icon_pixbuf(*ficon, size);
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
Glib::RefPtr<Gdk::Pixbuf> 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<Gdk::Pixbuf> 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);
|
|
}
|