mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 02:18:42 +00:00
perf: faster file-lists in the GTK client's details dialog (#2993)
* perf: faster file tree building in GTK client * perf: faster GTK client FileList * use a std::map for faster node lookup when building a file tree * use tr_get_mime_type_for_filename() for mime-type lookup * remove unnecessary layer of indirection when building the keys for lookuops in the mime-type icon cache * be more careful to only call operator= on proxies whose values have actually changed, since that assignment is expensive
This commit is contained in:
198
gtk/FileList.cc
198
gtk/FileList.cc
@@ -6,7 +6,11 @@
|
|||||||
#include <climits> /* INT_MAX */
|
#include <climits> /* INT_MAX */
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring> // strchr
|
#include <cstring> // strchr
|
||||||
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <glibmm.h>
|
#include <glibmm.h>
|
||||||
#include <glibmm/i18n.h>
|
#include <glibmm/i18n.h>
|
||||||
@@ -23,6 +27,8 @@
|
|||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -145,51 +151,32 @@ bool refreshFilesForeach(
|
|||||||
bool const is_file = iter->children().empty();
|
bool const is_file = iter->children().empty();
|
||||||
|
|
||||||
auto const old_enabled = iter->get_value(file_cols.enabled);
|
auto const old_enabled = iter->get_value(file_cols.enabled);
|
||||||
auto const old_priority = iter->get_value(file_cols.priority);
|
|
||||||
auto const index = iter->get_value(file_cols.index);
|
|
||||||
auto const old_have = iter->get_value(file_cols.have);
|
auto const old_have = iter->get_value(file_cols.have);
|
||||||
auto const size = iter->get_value(file_cols.size);
|
auto const old_priority = iter->get_value(file_cols.priority);
|
||||||
auto const old_prog = iter->get_value(file_cols.prog);
|
auto const old_progress = iter->get_value(file_cols.prog);
|
||||||
|
auto const old_size = iter->get_value(file_cols.size);
|
||||||
|
|
||||||
|
auto new_enabled = old_enabled;
|
||||||
|
auto new_have = old_have;
|
||||||
|
auto new_priority = old_priority;
|
||||||
|
auto new_progress = old_progress;
|
||||||
|
auto new_size = old_size;
|
||||||
|
|
||||||
if (is_file)
|
if (is_file)
|
||||||
{
|
{
|
||||||
auto const* tor = refresh_data.tor;
|
auto const index = iter->get_value(file_cols.index);
|
||||||
auto const file = tr_torrentFile(tor, index);
|
auto const file = tr_torrentFile(refresh_data.tor, index);
|
||||||
int const enabled = file.wanted;
|
|
||||||
int const priority = file.priority;
|
|
||||||
auto const progress = file.progress;
|
|
||||||
uint64_t const have = file.have;
|
|
||||||
int const prog = std::clamp(int(100 * progress), 0, 100);
|
|
||||||
|
|
||||||
if (priority != old_priority || enabled != old_enabled || have != old_have || prog != old_prog)
|
new_enabled = file.wanted;
|
||||||
{
|
new_priority = file.priority;
|
||||||
/* Changing a value in the sort column can trigger a resort
|
new_have = file.have;
|
||||||
* which breaks this foreach () call. (See #3529)
|
new_progress = std::clamp(int(100 * file.progress), 0, 100);
|
||||||
* As a workaround: if that's about to happen, temporarily disable
|
|
||||||
* sorting until we finish walking the tree. */
|
|
||||||
if (!refresh_data.resort_needed &&
|
|
||||||
(((refresh_data.sort_column_id == file_cols.priority.index()) && (priority != old_priority)) ||
|
|
||||||
((refresh_data.sort_column_id == file_cols.enabled.index()) && (enabled != old_enabled))))
|
|
||||||
{
|
|
||||||
refresh_data.resort_needed = true;
|
|
||||||
|
|
||||||
store->set_sort_column(GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, Gtk::SORT_ASCENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
(*iter)[file_cols.priority] = priority;
|
|
||||||
(*iter)[file_cols.enabled] = enabled;
|
|
||||||
(*iter)[file_cols.have] = have;
|
|
||||||
(*iter)[file_cols.prog] = prog;
|
|
||||||
(*iter)[file_cols.prog_str] = fmt::format(FMT_STRING("{:d}%"), prog);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint64_t sub_size = 0;
|
new_size = 0;
|
||||||
uint64_t have = 0;
|
new_enabled = NOT_SET;
|
||||||
int prog;
|
new_priority = NOT_SET;
|
||||||
int enabled = NOT_SET;
|
|
||||||
int priority = NOT_SET;
|
|
||||||
|
|
||||||
/* since gtk_tree_model_foreach() is depth-first, we can
|
/* since gtk_tree_model_foreach() is depth-first, we can
|
||||||
* get the `sub' info by walking the immediate children */
|
* get the `sub' info by walking the immediate children */
|
||||||
@@ -203,41 +190,73 @@ bool refreshFilesForeach(
|
|||||||
|
|
||||||
if ((child_enabled != false) && (child_enabled != NOT_SET))
|
if ((child_enabled != false) && (child_enabled != NOT_SET))
|
||||||
{
|
{
|
||||||
sub_size += child_size;
|
new_size += child_size;
|
||||||
have += child_have;
|
new_have += child_have;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabled == NOT_SET)
|
if (new_enabled == NOT_SET)
|
||||||
{
|
{
|
||||||
enabled = child_enabled;
|
new_enabled = child_enabled;
|
||||||
}
|
}
|
||||||
else if (enabled != child_enabled)
|
else if (new_enabled != child_enabled)
|
||||||
{
|
{
|
||||||
enabled = MIXED;
|
new_enabled = MIXED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priority == NOT_SET)
|
if (new_priority == NOT_SET)
|
||||||
{
|
{
|
||||||
priority = child_priority;
|
new_priority = child_priority;
|
||||||
}
|
}
|
||||||
else if (priority != child_priority)
|
else if (new_priority != child_priority)
|
||||||
{
|
{
|
||||||
priority = MIXED;
|
new_priority = MIXED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prog = sub_size != 0 ? (int)(100.0 * have / sub_size) : 1;
|
new_progress = new_size != 0 ? (int)(100.0 * new_have / new_size) : 1;
|
||||||
|
|
||||||
if (size != sub_size || have != old_have || priority != old_priority || enabled != old_enabled || prog != old_prog)
|
|
||||||
{
|
|
||||||
(*iter)[file_cols.size] = sub_size;
|
|
||||||
(*iter)[file_cols.size_str] = tr_strlsize(sub_size);
|
|
||||||
(*iter)[file_cols.have] = have;
|
|
||||||
(*iter)[file_cols.priority] = priority;
|
|
||||||
(*iter)[file_cols.enabled] = enabled;
|
|
||||||
(*iter)[file_cols.prog] = prog;
|
|
||||||
(*iter)[file_cols.prog_str] = fmt::format(FMT_STRING("{:d}%"), prog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_priority != old_priority || new_enabled != old_enabled)
|
||||||
|
{
|
||||||
|
/* Changing a value in the sort column can trigger a resort
|
||||||
|
* which breaks this foreach () call. (See #3529)
|
||||||
|
* As a workaround: if that's about to happen, temporarily disable
|
||||||
|
* sorting until we finish walking the tree. */
|
||||||
|
if (!refresh_data.resort_needed &&
|
||||||
|
(((refresh_data.sort_column_id == file_cols.priority.index()) && (new_priority != old_priority)) ||
|
||||||
|
((refresh_data.sort_column_id == file_cols.enabled.index()) && (new_enabled != old_enabled))))
|
||||||
|
{
|
||||||
|
refresh_data.resort_needed = true;
|
||||||
|
|
||||||
|
store->set_sort_column(GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, Gtk::SORT_ASCENDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_enabled != old_enabled)
|
||||||
|
{
|
||||||
|
(*iter)[file_cols.enabled] = new_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_priority != old_priority)
|
||||||
|
{
|
||||||
|
(*iter)[file_cols.priority] = new_priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_size != old_size)
|
||||||
|
{
|
||||||
|
(*iter)[file_cols.size] = new_size;
|
||||||
|
(*iter)[file_cols.size_str] = tr_strlsize(new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_have != old_have)
|
||||||
|
{
|
||||||
|
(*iter)[file_cols.have] = new_have;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_progress != old_progress)
|
||||||
|
{
|
||||||
|
(*iter)[file_cols.prog] = new_progress;
|
||||||
|
(*iter)[file_cols.prog_str] = fmt::format(FMT_STRING("{:d}%"), new_progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; /* keep walking */
|
return false; /* keep walking */
|
||||||
@@ -270,9 +289,7 @@ void gtr_tree_model_foreach_postorder(Glib::RefPtr<Gtk::TreeModel> const& model,
|
|||||||
|
|
||||||
void FileList::Impl::refresh()
|
void FileList::Impl::refresh()
|
||||||
{
|
{
|
||||||
tr_torrent* tor = core_->find_torrent(torrent_id_);
|
if (tr_torrent* tor = core_->find_torrent(torrent_id_); tor == nullptr)
|
||||||
|
|
||||||
if (tor == nullptr)
|
|
||||||
{
|
{
|
||||||
widget_.clear();
|
widget_.clear();
|
||||||
}
|
}
|
||||||
@@ -424,14 +441,14 @@ void buildTree(FileRowNode& node, build_data& build)
|
|||||||
auto const& child_data = node.data();
|
auto const& child_data = node.data();
|
||||||
bool const isLeaf = node.child_count() == 0;
|
bool const isLeaf = node.child_count() == 0;
|
||||||
|
|
||||||
auto const mime_type = isLeaf ? gtr_get_mime_type_from_filename(child_data.name) : DirectoryMimeType;
|
auto const mime_type = isLeaf ? tr_get_mime_type_for_filename(child_data.name.raw()) : DirectoryMimeType;
|
||||||
auto const icon = gtr_get_mime_type_icon(mime_type, Gtk::ICON_SIZE_MENU, *build.w);
|
auto const icon = gtr_get_mime_type_icon(mime_type, Gtk::ICON_SIZE_MENU, *build.w);
|
||||||
auto const file = isLeaf ? tr_torrentFile(build.tor, child_data.index) : tr_file_view{};
|
auto const file = isLeaf ? tr_torrentFile(build.tor, child_data.index) : tr_file_view{};
|
||||||
int const priority = isLeaf ? file.priority : 0;
|
int const priority = isLeaf ? file.priority : 0;
|
||||||
bool const enabled = isLeaf ? file.wanted : true;
|
bool const enabled = isLeaf ? file.wanted : true;
|
||||||
auto name_esc = Glib::Markup::escape_text(child_data.name);
|
auto name_esc = Glib::Markup::escape_text(child_data.name);
|
||||||
|
|
||||||
auto const child_iter = build.store->append(build.iter->children());
|
auto const child_iter = build.store->prepend(build.iter->children());
|
||||||
(*child_iter)[file_cols.index] = child_data.index;
|
(*child_iter)[file_cols.index] = child_data.index;
|
||||||
(*child_iter)[file_cols.label] = child_data.name;
|
(*child_iter)[file_cols.label] = child_data.name;
|
||||||
(*child_iter)[file_cols.label_esc] = name_esc;
|
(*child_iter)[file_cols.label_esc] = name_esc;
|
||||||
@@ -449,21 +466,6 @@ void buildTree(FileRowNode& node, build_data& build)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileRowNode* find_child(FileRowNode* parent, Glib::ustring const& name)
|
|
||||||
{
|
|
||||||
for (auto* child = parent->first_child(); child != nullptr; child = child->next_sibling())
|
|
||||||
{
|
|
||||||
auto const& child_data = child->data();
|
|
||||||
|
|
||||||
if (child_data.name == name)
|
|
||||||
{
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void FileList::set_torrent(int torrent_id)
|
void FileList::set_torrent(int torrent_id)
|
||||||
@@ -471,6 +473,15 @@ void FileList::set_torrent(int torrent_id)
|
|||||||
impl_->set_torrent(torrent_id);
|
impl_->set_torrent(torrent_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PairHash
|
||||||
|
{
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
auto operator()(std::pair<T1, T2> const& pair) const
|
||||||
|
{
|
||||||
|
return std::hash<T1>{}(pair.first) ^ std::hash<T2>{}(pair.second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void FileList::Impl::set_torrent(int torrentId)
|
void FileList::Impl::set_torrent(int torrentId)
|
||||||
{
|
{
|
||||||
/* unset the old fields */
|
/* unset the old fields */
|
||||||
@@ -486,32 +497,34 @@ void FileList::Impl::set_torrent(int torrentId)
|
|||||||
if (auto* const tor = core_->find_torrent(torrent_id_); tor != nullptr)
|
if (auto* const tor = core_->find_torrent(torrent_id_); tor != nullptr)
|
||||||
{
|
{
|
||||||
// build a GNode tree of the files
|
// build a GNode tree of the files
|
||||||
FileRowNode root;
|
auto root = FileRowNode{};
|
||||||
auto& root_data = root.data();
|
auto& root_data = root.data();
|
||||||
root_data.name = tr_torrentName(tor);
|
root_data.name = tr_torrentName(tor);
|
||||||
root_data.index = -1;
|
root_data.index = -1;
|
||||||
root_data.length = 0;
|
root_data.length = 0;
|
||||||
|
|
||||||
|
auto nodes = std::unordered_map<std::pair<FileRowNode* /*parent*/, std::string_view>, FileRowNode*, PairHash>{};
|
||||||
|
|
||||||
for (tr_file_index_t i = 0, n_files = tr_torrentFileCount(tor); i < n_files; ++i)
|
for (tr_file_index_t i = 0, n_files = tr_torrentFileCount(tor); i < n_files; ++i)
|
||||||
{
|
{
|
||||||
auto* parent = &root;
|
auto* parent = &root;
|
||||||
auto const file = tr_torrentFile(tor, i);
|
auto const file = tr_torrentFile(tor, i);
|
||||||
|
|
||||||
for (char const *last = file.name, *next = strchr(last, '/'); last != nullptr;
|
auto path = std::string_view{ file.name };
|
||||||
last = next != nullptr ? next + 1 : nullptr, next = last != nullptr ? strchr(last, '/') : nullptr)
|
auto token = std::string_view{};
|
||||||
|
while (tr_strvSep(&path, &token, '/'))
|
||||||
{
|
{
|
||||||
bool const isLeaf = next == nullptr;
|
auto*& node = nodes[std::make_pair(parent, token)];
|
||||||
auto name = Glib::ustring(isLeaf ? last : std::string(last, next - last));
|
|
||||||
auto* node = find_child(parent, name);
|
|
||||||
|
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
{
|
{
|
||||||
node = new FileRowNode();
|
auto const is_leaf = std::empty(path);
|
||||||
auto& row = node->data();
|
|
||||||
row.name = std::move(name);
|
node = parent->prepend_data({});
|
||||||
row.index = isLeaf ? (int)i : -1;
|
auto& node_data = node->data();
|
||||||
row.length = isLeaf ? file.length : 0;
|
node_data.name = std::string{ token };
|
||||||
parent->append(*node);
|
node_data.index = is_leaf ? (int)i : -1;
|
||||||
|
node_data.length = is_leaf ? file.length : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent = node;
|
parent = node;
|
||||||
@@ -537,7 +550,8 @@ void FileList::Impl::set_torrent(int torrentId)
|
|||||||
/* set default sort by label */
|
/* set default sort by label */
|
||||||
store_->set_sort_column(file_cols.label, Gtk::SORT_ASCENDING);
|
store_->set_sort_column(file_cols.label, Gtk::SORT_ASCENDING);
|
||||||
|
|
||||||
view_->expand_all();
|
view_->expand_row(Gtk::TreeModel::Path("0"), false);
|
||||||
|
// view_->expand_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@@ -731,7 +745,7 @@ bool FileList::Impl::on_rename_done_idle(Glib::ustring const& path_string, Glib:
|
|||||||
if (auto const iter = store_->get_iter(path_string); iter)
|
if (auto const iter = store_->get_iter(path_string); iter)
|
||||||
{
|
{
|
||||||
bool const isLeaf = iter->children().empty();
|
bool const isLeaf = iter->children().empty();
|
||||||
auto const mime_type = isLeaf ? gtr_get_mime_type_from_filename(newname) : DirectoryMimeType;
|
auto const mime_type = isLeaf ? tr_get_mime_type_for_filename(newname.raw()) : DirectoryMimeType;
|
||||||
auto const icon = gtr_get_mime_type_icon(mime_type, Gtk::ICON_SIZE_MENU, *view_);
|
auto const icon = gtr_get_mime_type_icon(mime_type, Gtk::ICON_SIZE_MENU, *view_);
|
||||||
|
|
||||||
(*iter)[file_cols.label] = newname;
|
(*iter)[file_cols.label] = newname;
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <glibmm.h>
|
#include <glibmm.h>
|
||||||
#include <giomm.h>
|
#include <giomm.h>
|
||||||
@@ -17,8 +19,8 @@
|
|||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
Glib::ustring const DirectoryMimeType = "folder"s;
|
std::string_view const DirectoryMimeType = "folder"sv;
|
||||||
Glib::ustring const UnknownMimeType = "unknown"s;
|
std::string_view const UnknownMimeType = "unknown"sv;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -29,7 +31,7 @@ struct IconCache
|
|||||||
{
|
{
|
||||||
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
||||||
int icon_size;
|
int icon_size;
|
||||||
std::unordered_map<std::string, Glib::RefPtr<Gdk::Pixbuf>> cache;
|
std::map<std::string, Glib::RefPtr<Gdk::Pixbuf>, std::less<>> cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<std::unique_ptr<IconCache>, 7> icon_cache;
|
std::array<std::unique_ptr<IconCache>, 7> icon_cache;
|
||||||
@@ -58,28 +60,6 @@ std::unique_ptr<IconCache> icon_cache_new(Gtk::Widget& for_widget, Gtk::IconSize
|
|||||||
return icons;
|
return icons;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string _icon_cache_get_icon_key(Glib::RefPtr<Gio::Icon> const& icon)
|
|
||||||
{
|
|
||||||
std::string key;
|
|
||||||
|
|
||||||
if (auto const* 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)
|
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 const icon_names = icon.get_names();
|
||||||
@@ -134,25 +114,21 @@ Glib::RefPtr<Gdk::Pixbuf> _get_icon_pixbuf(Glib::RefPtr<Gio::Icon> const& icon,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> icon_cache_get_mime_type_icon(IconCache& icons, Glib::ustring const& mime_type)
|
Glib::RefPtr<Gdk::Pixbuf> icon_cache_get_mime_type_icon(IconCache& icons, std::string_view mime_type)
|
||||||
{
|
{
|
||||||
auto icon = Gio::content_type_get_icon(mime_type);
|
auto& cache = icons.cache;
|
||||||
auto key = _icon_cache_get_icon_key(icon);
|
|
||||||
if (key.empty())
|
if (auto mime_it = cache.find(mime_type); mime_it != std::end(cache))
|
||||||
{
|
{
|
||||||
key = VoidPixbufKey;
|
return mime_it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto pixbuf_it = icons.cache.find(key); pixbuf_it != icons.cache.end())
|
auto mime_type_str = std::string{ mime_type };
|
||||||
{
|
auto icon = Gio::content_type_get_icon(mime_type_str);
|
||||||
return pixbuf_it->second;
|
auto pixbuf = _get_icon_pixbuf(icon, icons.icon_size, *gtr_get_ptr(icons.icon_theme));
|
||||||
}
|
|
||||||
|
|
||||||
auto const pixbuf = _get_icon_pixbuf(icon, icons.icon_size, *gtr_get_ptr(icons.icon_theme));
|
|
||||||
|
|
||||||
if (pixbuf != nullptr)
|
if (pixbuf != nullptr)
|
||||||
{
|
{
|
||||||
icons.cache.try_emplace(key, pixbuf);
|
cache.try_emplace(std::move(mime_type_str), pixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pixbuf;
|
return pixbuf;
|
||||||
@@ -160,10 +136,7 @@ Glib::RefPtr<Gdk::Pixbuf> icon_cache_get_mime_type_icon(IconCache& icons, Glib::
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> gtr_get_mime_type_icon(
|
Glib::RefPtr<Gdk::Pixbuf> gtr_get_mime_type_icon(std::string_view mime_type, Gtk::IconSize icon_size, Gtk::Widget& for_widget)
|
||||||
Glib::ustring const& mime_type,
|
|
||||||
Gtk::IconSize icon_size,
|
|
||||||
Gtk::Widget& for_widget)
|
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@@ -205,9 +178,3 @@ Glib::RefPtr<Gdk::Pixbuf> gtr_get_mime_type_icon(
|
|||||||
|
|
||||||
return icon_cache_get_mime_type_icon(*icon_cache[n], mime_type);
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,16 +7,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string_view>
|
||||||
|
|
||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
|
|
||||||
extern Glib::ustring const DirectoryMimeType;
|
extern std::string_view const DirectoryMimeType;
|
||||||
extern Glib::ustring const UnknownMimeType;
|
extern std::string_view const UnknownMimeType;
|
||||||
|
|
||||||
Glib::ustring gtr_get_mime_type_from_filename(std::string const& file);
|
Glib::RefPtr<Gdk::Pixbuf> gtr_get_mime_type_icon(std::string_view mime_type, Gtk::IconSize icon_size, Gtk::Widget& for_widget);
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> gtr_get_mime_type_icon(
|
|
||||||
Glib::ustring const& mime_type,
|
|
||||||
Gtk::IconSize icon_size,
|
|
||||||
Gtk::Widget& for_widget);
|
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ namespace
|
|||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> get_icon(tr_torrent const* tor, Gtk::IconSize icon_size, Gtk::Widget& for_widget)
|
Glib::RefPtr<Gdk::Pixbuf> get_icon(tr_torrent const* tor, Gtk::IconSize icon_size, Gtk::Widget& for_widget)
|
||||||
{
|
{
|
||||||
Glib::ustring mime_type;
|
auto mime_type = std::string_view{};
|
||||||
|
|
||||||
if (auto const n_files = tr_torrentFileCount(tor); n_files == 0)
|
if (auto const n_files = tr_torrentFileCount(tor); n_files == 0)
|
||||||
{
|
{
|
||||||
@@ -364,7 +364,7 @@ Glib::RefPtr<Gdk::Pixbuf> get_icon(tr_torrent const* tor, Gtk::IconSize icon_siz
|
|||||||
{
|
{
|
||||||
auto const* const name = tr_torrentFile(tor, 0).name;
|
auto const* const name = tr_torrentFile(tor, 0).name;
|
||||||
|
|
||||||
mime_type = strchr(name, '/') != nullptr ? DirectoryMimeType : gtr_get_mime_type_from_filename(name);
|
mime_type = strchr(name, '/') != nullptr ? DirectoryMimeType : tr_get_mime_type_for_filename(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gtr_get_mime_type_icon(mime_type, icon_size, for_widget);
|
return gtr_get_mime_type_icon(mime_type, icon_size, for_widget);
|
||||||
|
|||||||
Reference in New Issue
Block a user