Fix issues reported by clang-tidy `cppcoreguidelines` checks (GTK client) (#4158)

* Fix `cppcoreguidelines-pro-type-cstyle-cast` clang-tidy issues

* Fix `cppcoreguidelines-pro-type-member-init` clang-tidy issues

* Fix `cppcoreguidelines-prefer-member-initializer` clang-tidy issues

* Introduce `PageBase` for `PrefsDialog` pages

This is in preparation for next PR fixing `Glib::Timer` memory
management.

* Fix `cppcoreguidelines-owning-memory` clang-tidy issues

* Fix `cppcoreguidelines-pro-bounds-array-to-pointer-decay` clang-tidy issues

* Fix `cppcoreguidelines-special-member-functions` clang-tidy issues

* Fix `cppcoreguidelines-init-variables` clang-tidy issues

* Fix `cppcoreguidelines-macro-usage` clang-tidy issues

* Fix `cppcoreguidelines-pro-bounds-constant-array-index` clang-tidy issues

* Fix `cppcoreguidelines-non-private-member-variables-in-classes` clang-tidy issues

* Fix `cppcoreguidelines-pro-type-vararg` clang-tidy issues

* Fix `cppcoreguidelines-pro-bounds-pointer-arithmetic` clang-tidy issue

* Fix `cppcoreguidelines-pro-type-reinterpret-cast` clang-tidy issues

* Fix `cppcoreguidelines-pro-type-static-cast-downcast` clang-tidy issues

* Extend clang-tidy configuration

Enable all `cppcoreguidelines` checks except for three (`avoid-magic-
numbers`, `avoid-non-const-global-variables`, `narrowing-conversions`)
which require [more] extensive refactoring and were left for later.
This commit is contained in:
Mike Gelfand 2022-11-13 18:36:16 +01:00 committed by GitHub
parent 0ecf084e0f
commit 49ce12ce38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 730 additions and 744 deletions

View File

@ -1,6 +1,10 @@
---
Checks: >
-*,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-narrowing-conversions,
modernize-*,
-modernize-use-trailing-return-type,
readability-*,

View File

@ -87,6 +87,7 @@ class Application::Impl
{
public:
Impl(Application& app, std::string const& config_dir, bool start_paused, bool is_iconified);
~Impl() = default;
TR_DISABLE_COPY_MOVE(Impl)
@ -293,10 +294,9 @@ bool Application::Impl::refresh_actions()
size_t const total = core_->get_torrent_count();
size_t const active = core_->get_active_torrent_count();
auto const torrent_count = core_->get_model()->children().size();
bool has_selection;
auto const sel_counts = get_selected_torrent_counts();
has_selection = sel_counts.total_count > 0;
bool const has_selection = sel_counts.total_count > 0;
gtr_action_set_sensitive("select-all", torrent_count != 0);
gtr_action_set_sensitive("deselect-all", torrent_count != 0);
@ -366,12 +366,11 @@ void register_magnet_link_handler()
}
catch (Gio::Error const& e)
{
auto const msg = fmt::format(
gtr_warning(fmt::format(
_("Couldn't register Transmission as a {content_type} handler: {error} ({error_code})"),
fmt::arg("content_type", content_type),
fmt::arg("error", e.what()),
fmt::arg("error_code", e.code()));
g_warning("%s", msg.c_str());
fmt::arg("error_code", e.code())));
}
}
@ -399,15 +398,15 @@ void Application::Impl::on_main_window_size_allocated()
if (!is_maximized)
{
#if !GTKMM_CHECK_VERSION(4, 0, 0)
int x;
int y;
int x = 0;
int y = 0;
wind_->get_position(x, y);
gtr_pref_int_set(TR_KEY_main_window_x, x);
gtr_pref_int_set(TR_KEY_main_window_y, y);
#endif
int w;
int h;
int w = 0;
int h = 0;
#if GTKMM_CHECK_VERSION(4, 0, 0)
wind_->get_default_size(w, h);
#else
@ -449,9 +448,9 @@ bool Application::Impl::on_rpc_changed_idle(tr_rpc_callback_type type, tr_torren
case TR_RPC_SESSION_CHANGED:
{
tr_variant tmp;
tr_variant* newval;
tr_variant* newval = nullptr;
tr_variant* oldvals = gtr_pref_get_all();
tr_quark key;
tr_quark key = TR_KEY_NONE;
std::vector<tr_quark> changed_keys;
auto const* const session = core_->get_session();
tr_variantInitDict(&tmp, 100);
@ -459,13 +458,9 @@ bool Application::Impl::on_rpc_changed_idle(tr_rpc_callback_type type, tr_torren
for (int i = 0; tr_variantDictChild(&tmp, i, &key, &newval); ++i)
{
bool changed;
bool changed = true;
if (tr_variant const* oldval = tr_variantDictFind(oldvals, key); oldval == nullptr)
{
changed = true;
}
else
if (tr_variant const* oldval = tr_variantDictFind(oldvals, key); oldval != nullptr)
{
auto const a = tr_variantToStr(oldval, TR_VARIANT_FMT_BENC);
auto const b = tr_variantToStr(newval, TR_VARIANT_FMT_BENC);
@ -529,7 +524,7 @@ namespace
gboolean signal_handler(gpointer user_data)
{
g_message(_("Got termination signal, trying to shut down cleanly. Do it again if it gets stuck."));
gtr_message(_("Got termination signal, trying to shut down cleanly. Do it again if it gets stuck."));
gtr_actions_handler("quit", user_data);
return G_SOURCE_REMOVE;
}
@ -567,7 +562,7 @@ void Application::Impl::on_startup()
std::ignore = FilterBar();
std::ignore = PathButton();
tr_session* session;
tr_session* session = nullptr;
#ifdef G_OS_UNIX
g_unix_signal_add(SIGINT, &signal_handler, this);
@ -976,8 +971,7 @@ void Application::Impl::on_app_exit()
refresh_actions_tag_.disconnect();
#if !GTKMM_CHECK_VERSION(4, 0, 0)
auto* c = static_cast<Gtk::Container*>(wind_.get());
c->remove(*static_cast<Gtk::Bin*>(c)->get_child());
wind_->remove();
#endif
wind_->set_show_menubar(false);
@ -989,7 +983,7 @@ void Application::Impl::on_app_exit()
#if GTKMM_CHECK_VERSION(4, 0, 0)
wind_->set_child(*p);
#else
c->add(*p);
wind_->add(*p);
#endif
auto* icon = Gtk::make_managed<Gtk::Image>();
@ -1427,15 +1421,13 @@ void Application::Impl::show_about_dialog()
bool Application::Impl::call_rpc_for_selected_torrents(std::string const& method)
{
tr_variant top;
tr_variant* args;
tr_variant* ids;
bool invoked = false;
auto* session = core_->get_session();
tr_variantInitDict(&top, 2);
tr_variantDictAddStrView(&top, TR_KEY_method, method);
args = tr_variantDictAddDict(&top, TR_KEY_arguments, 1);
ids = tr_variantDictAddList(args, TR_KEY_ids, 0);
auto* const args = tr_variantDictAddDict(&top, TR_KEY_arguments, 1);
auto* const ids = tr_variantDictAddList(args, TR_KEY_ids, 0);
sel_->selected_foreach(
[ids](auto const& /*path*/, auto const& iter)
{
@ -1667,7 +1659,7 @@ void Application::Impl::actions_handler(Glib::ustring const& action_name)
}
else
{
g_error("%s", fmt::format("Unhandled action: {}", action_name).c_str());
gtr_error(fmt::format("Unhandled action: {}", action_name));
}
if (changed)

View File

@ -1172,16 +1172,19 @@ void initPeerRow(
}
auto peer_addr4 = in_addr();
auto const collated_name = inet_pton(AF_INET, peer->addr, &peer_addr4) != 1 ?
peer->addr :
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto const* const peer_addr4_octets = reinterpret_cast<uint8_t const*>(&peer_addr4.s_addr);
auto const collated_name = inet_pton(AF_INET, std::data(peer->addr), &peer_addr4) != 1 ?
std::data(peer->addr) :
fmt::format(
"{:03}",
fmt::join(
reinterpret_cast<uint8_t const*>(&peer_addr4.s_addr),
reinterpret_cast<uint8_t const*>(&peer_addr4.s_addr) + sizeof(peer_addr4.s_addr),
peer_addr4_octets,
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
peer_addr4_octets + sizeof(peer_addr4.s_addr), // TODO(C++20): Use std::span
"."));
(*iter)[peer_cols.address] = peer->addr;
(*iter)[peer_cols.address] = std::data(peer->addr);
(*iter)[peer_cols.address_collated] = collated_name;
(*iter)[peer_cols.client] = client;
(*iter)[peer_cols.encryption_stock_id] = peer->isEncrypted ? "lock" : "";
@ -1251,7 +1254,7 @@ void refreshPeerRow(Gtk::TreeModel::iterator const& iter, tr_peer_stat const* pe
(*iter)[peer_cols.download_rate_string] = down_speed;
(*iter)[peer_cols.upload_rate_double] = peer->rateToPeer_KBps;
(*iter)[peer_cols.upload_rate_string] = up_speed;
(*iter)[peer_cols.flags] = peer->flagStr;
(*iter)[peer_cols.flags] = std::data(peer->flagStr);
(*iter)[peer_cols.was_updated] = true;
(*iter)[peer_cols.blocks_downloaded_count_int] = (int)peer->blocksToClient;
(*iter)[peer_cols.blocks_downloaded_count_string] = blocks_to_client;
@ -1533,7 +1536,7 @@ namespace
void setPeerViewColumns(Gtk::TreeView* peer_view)
{
std::vector<Gtk::TreeModelColumnBase const*> view_columns;
Gtk::TreeViewColumn* c;
Gtk::TreeViewColumn* c = nullptr;
bool const more = gtr_pref_flag_get(TR_KEY_show_extra_peer_details);
view_columns.push_back(&peer_cols.encryption_stock_id);
@ -1777,7 +1780,7 @@ std::array<std::string_view, 3> const text_dir_mark = { ""sv, "\u200E"sv, "\u200
void appendAnnounceInfo(tr_tracker_view const& tracker, time_t const now, Gtk::TextDirection direction, std::ostream& gstr)
{
auto const dir_mark = text_dir_mark[static_cast<int>(direction)];
auto const dir_mark = text_dir_mark.at(static_cast<int>(direction));
if (tracker.hasAnnounced && tracker.announceState != TR_TRACKER_INACTIVE)
{
@ -1813,7 +1816,7 @@ void appendAnnounceInfo(tr_tracker_view const& tracker, time_t const now, Gtk::T
// {markup_begin} and {markup_end} should surround the error
_("Got an error '{markup_begin}{error}{markup_end}' {time_span_ago}"),
fmt::arg("markup_begin", ErrMarkupBegin),
fmt::arg("error", Glib::Markup::escape_text(tracker.lastAnnounceResult)),
fmt::arg("error", Glib::Markup::escape_text(std::data(tracker.lastAnnounceResult))),
fmt::arg("markup_end", ErrMarkupEnd),
fmt::arg("time_span_ago", time_span_ago));
}
@ -1859,7 +1862,7 @@ void appendAnnounceInfo(tr_tracker_view const& tracker, time_t const now, Gtk::T
void appendScrapeInfo(tr_tracker_view const& tracker, time_t const now, Gtk::TextDirection direction, std::ostream& gstr)
{
auto const dir_mark = text_dir_mark[static_cast<int>(direction)];
auto const dir_mark = text_dir_mark.at(static_cast<int>(direction));
if (tracker.hasScraped)
{
@ -1885,7 +1888,7 @@ void appendScrapeInfo(tr_tracker_view const& tracker, time_t const now, Gtk::Tex
gstr << fmt::format(
// {markup_begin} and {markup_end} should surround the error text
_("Got a scrape error '{markup_begin}{error}{markup_end}' {time_span_ago}"),
fmt::arg("error", Glib::Markup::escape_text(tracker.lastScrapeResult)),
fmt::arg("error", Glib::Markup::escape_text(std::data(tracker.lastScrapeResult))),
fmt::arg("time_span_ago", time_span_ago),
fmt::arg("markup_begin", ErrMarkupBegin),
fmt::arg("markup_end", ErrMarkupEnd));
@ -1934,7 +1937,7 @@ void buildTrackerSummary(
Gtk::TextDirection direction)
{
// hostname
gstr << text_dir_mark[static_cast<int>(direction)];
gstr << text_dir_mark.at(static_cast<int>(direction));
gstr << (tracker.isBackup ? "<i>" : "<b>");
gstr << Glib::Markup::escape_text(!key.empty() ? fmt::format(FMT_STRING("{:s} - {:s}"), tracker.host, key) : tracker.host);
gstr << (tracker.isBackup ? "</i>" : "</b>");
@ -2167,6 +2170,7 @@ public:
DetailsDialog& parent,
Glib::RefPtr<Session> const& core,
tr_torrent const* torrent);
~EditTrackersDialog() override = default;
TR_DISABLE_COPY_MOVE(EditTrackersDialog)
@ -2285,6 +2289,7 @@ public:
DetailsDialog& parent,
Glib::RefPtr<Session> const& core,
tr_torrent const* torrent);
~AddTrackerDialog() override = default;
TR_DISABLE_COPY_MOVE(AddTrackerDialog)
@ -2344,14 +2349,12 @@ void AddTrackerDialog::on_response(int response)
if (tr_urlIsValidTracker(url.c_str()))
{
tr_variant top;
tr_variant* args;
tr_variant* trackers;
tr_variantInitDict(&top, 2);
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-set"sv);
args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
auto* const args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
tr_variantDictAddInt(args, TR_KEY_id, torrent_id_);
trackers = tr_variantDictAddList(args, TR_KEY_trackerAdd, 1);
auto* const trackers = tr_variantDictAddList(args, TR_KEY_trackerAdd, 1);
tr_variantListAddStr(trackers, url.raw());
core_->exec(&top);
@ -2395,14 +2398,12 @@ void DetailsDialog::Impl::on_tracker_list_remove_button_clicked()
auto const torrent_id = iter->get_value(tracker_cols.torrent_id);
auto const tracker_id = iter->get_value(tracker_cols.tracker_id);
tr_variant top;
tr_variant* args;
tr_variant* trackers;
tr_variantInitDict(&top, 2);
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-set"sv);
args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
auto* const args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
tr_variantDictAddInt(args, TR_KEY_id, torrent_id);
trackers = tr_variantDictAddList(args, TR_KEY_trackerRemove, 1);
auto* const trackers = tr_variantDictAddList(args, TR_KEY_trackerRemove, 1);
tr_variantListAddInt(trackers, tracker_id);
core_->exec(&top);

View File

@ -35,7 +35,7 @@ struct favicon_data
Glib::ustring get_url(std::string const& host, size_t image_type)
{
return fmt::format("http://{}/favicon.{}", host, image_types[image_type]);
return fmt::format("http://{}/favicon.{}", host, image_types.at(image_type));
}
std::string favicon_get_cache_dir()

View File

@ -302,8 +302,8 @@ void FileList::Impl::refresh()
}
else
{
Gtk::SortType order;
int sort_column_id;
Gtk::SortType order = TR_GTK_SORT_TYPE(ASCENDING);
int sort_column_id = 0;
store_->get_sort_column_id(sort_column_id, order);
RefreshData refresh_data{ sort_column_id, false, tor };
@ -426,8 +426,8 @@ namespace
struct build_data
{
Gtk::Widget* w;
tr_torrent* tor;
Gtk::Widget* w = nullptr;
tr_torrent* tor = nullptr;
Gtk::TreeStore::iterator iter;
Glib::RefPtr<Gtk::TreeStore> store;
};
@ -575,13 +575,27 @@ namespace
void renderDownload(Gtk::CellRenderer* renderer, Gtk::TreeModel::const_iterator const& iter)
{
auto* const toggle_renderer = dynamic_cast<Gtk::CellRendererToggle*>(renderer);
g_assert(toggle_renderer != nullptr);
if (toggle_renderer == nullptr)
{
return;
}
auto const enabled = iter->get_value(file_cols.enabled);
static_cast<Gtk::CellRendererToggle*>(renderer)->property_inconsistent() = enabled == MIXED;
static_cast<Gtk::CellRendererToggle*>(renderer)->property_active() = enabled == static_cast<int>(true);
toggle_renderer->property_inconsistent() = enabled == MIXED;
toggle_renderer->property_active() = enabled == static_cast<int>(true);
}
void renderPriority(Gtk::CellRenderer* renderer, Gtk::TreeModel::const_iterator const& iter)
{
auto* const text_renderer = dynamic_cast<Gtk::CellRendererText*>(renderer);
g_assert(text_renderer != nullptr);
if (text_renderer == nullptr)
{
return;
}
Glib::ustring text;
switch (auto const priority = iter->get_value(file_cols.priority); priority)
@ -603,7 +617,7 @@ void renderPriority(Gtk::CellRenderer* renderer, Gtk::TreeModel::const_iterator
break;
}
static_cast<Gtk::CellRendererText*>(renderer)->property_text() = text;
text_renderer->property_text() = text;
}
/* build a filename from tr_torrentGetCurrentDir() + the model's FC_LABELs */
@ -710,8 +724,8 @@ bool FileList::Impl::onViewPathToggled(Gtk::TreeViewColumn* col, Gtk::TreeModel:
*/
bool FileList::Impl::getAndSelectEventPath(double view_x, double view_y, Gtk::TreeViewColumn*& col, Gtk::TreeModel::Path& path)
{
int cell_x;
int cell_y;
int cell_x = 0;
int cell_y = 0;
if (view_->get_path_at_pos(view_x, view_y, path, col, cell_x, cell_y))
{
@ -729,7 +743,7 @@ bool FileList::Impl::getAndSelectEventPath(double view_x, double view_y, Gtk::Tr
bool FileList::Impl::onViewButtonPressed(guint button, TrGdkModifierType state, double view_x, double view_y)
{
Gtk::TreeViewColumn* col;
Gtk::TreeViewColumn* col = nullptr;
Gtk::TreeModel::Path path;
bool handled = false;
@ -747,7 +761,7 @@ struct rename_data
{
Glib::ustring newname;
Glib::ustring path_string;
gpointer impl;
gpointer impl = nullptr;
};
bool FileList::Impl::on_rename_done_idle(Glib::ustring const& path_string, Glib::ustring const& newname, int error)
@ -772,7 +786,7 @@ bool FileList::Impl::on_rename_done_idle(Glib::ustring const& path_string, Glib:
else
{
auto w = std::make_shared<Gtk::MessageDialog>(
*static_cast<Gtk::Window*>(TR_GTK_WIDGET_GET_ROOT(widget_)),
gtr_widget_get_window(widget_),
fmt::format(
_("Couldn't rename '{old_path}' as '{path}': {error} ({error_code})"),
fmt::arg("old_path", path_string),
@ -931,8 +945,8 @@ FileList::Impl::Impl(
{
/* add "progress" column */
auto const* title = _("Have");
int width;
int height;
int width = 0;
int height = 0;
view_->create_pango_layout(title)->get_pixel_size(width, height);
width += 30; /* room for the sort indicator */
auto* rend = Gtk::make_managed<Gtk::CellRendererProgress>();
@ -948,8 +962,8 @@ FileList::Impl::Impl(
{
/* add "enabled" column */
auto const* title = _("Download");
int width;
int height;
int width = 0;
int height = 0;
view_->create_pango_layout(title)->get_pixel_size(width, height);
width += 30; /* room for the sort indicator */
auto* rend = Gtk::make_managed<Gtk::CellRendererToggle>();
@ -965,8 +979,8 @@ FileList::Impl::Impl(
{
/* add priority column */
auto const* title = _("Priority");
int width;
int height;
int width = 0;
int height = 0;
view_->create_pango_layout(title)->get_pixel_size(width, height);
width += 30; /* room for the sort indicator */
auto* rend = Gtk::make_managed<Gtk::CellRendererText>();

View File

@ -185,7 +185,7 @@ bool tracker_filter_model_update(Glib::RefPtr<Gtk::TreeStore> const& tracker_mod
for (size_t i = 0, n = tr_torrentTrackerCount(tor); i < n; ++i)
{
auto const view = tr_torrentTracker(tor, i);
torrent_sites_and_hosts.try_emplace(view.sitename, view.host);
torrent_sites_and_hosts.try_emplace(std::data(view.sitename), view.host);
}
for (auto const& [sitename, host] : torrent_sites_and_hosts)
@ -391,7 +391,7 @@ bool test_tracker(tr_torrent const* tor, int active_tracker_type, Glib::ustring
for (size_t i = 0, n = tr_torrentTrackerCount(tor); i < n; ++i)
{
if (tr_torrentTracker(tor, i).sitename == host)
if (auto const tracker = tr_torrentTracker(tor, i); std::data(tracker.sitename) == host)
{
return true;
}
@ -696,26 +696,18 @@ bool FilterBar::Impl::update_count_label()
auto const visibleCount = static_cast<int>(filter_model_->children().size());
/* get the tracker count */
int trackerCount;
int trackerCount = 0;
if (auto const iter = tracker_->get_active(); iter)
{
trackerCount = iter->get_value(tracker_filter_cols.count);
}
else
{
trackerCount = 0;
}
/* get the activity count */
int activityCount;
int activityCount = 0;
if (auto const iter = activity_->get_active(); iter)
{
activityCount = iter->get_value(activity_filter_cols.count);
}
else
{
activityCount = 0;
}
/* set the text */
show_lb_->set_markup_with_mnemonic(
@ -802,7 +794,7 @@ FilterBar::Impl::Impl(FilterBar& widget, tr_session* session, Glib::RefPtr<Gtk::
filter_model_row_inserted_tag_ = filter_model_->signal_row_inserted().connect(
[this](auto const& /*path*/, auto const& /*iter*/) { update_count_label_idle(); });
static_cast<Gtk::TreeStore*>(tracker_->get_model().get())->set_data(SESSION_KEY, session);
gtr_ptr_dynamic_cast<Gtk::TreeStore>(tracker_->get_model())->set_data(SESSION_KEY, session);
filter_model_->set_visible_func(sigc::mem_fun(*this, &Impl::is_row_visible));
@ -855,6 +847,8 @@ T* FilterBar::Impl::get_template_child(char const* name) const
auto full_type_name = std::string("gtkmm__CustomObject_");
Glib::append_canonical_typename(full_type_name, typeid(FilterBar).name());
return Glib::wrap(reinterpret_cast<typename T::BaseObjectType*>(
gtk_widget_get_template_child(GTK_WIDGET(widget_.gobj()), g_type_from_name(full_type_name.c_str()), name)));
return Glib::wrap(G_TYPE_CHECK_INSTANCE_CAST(
gtk_widget_get_template_child(GTK_WIDGET(widget_.gobj()), g_type_from_name(full_type_name.c_str()), name),
T::get_base_type(),
typename T::BaseObjectType));
}

View File

@ -296,7 +296,7 @@ Glib::RefPtr<Gio::MenuModel> MainWindow::Impl::createSpeedMenu(
Glib::RefPtr<Gio::SimpleActionGroup> const& actions,
tr_direction dir)
{
auto& info = speed_menu_info_[dir];
auto& info = speed_menu_info_.at(dir);
auto m = Gio::Menu::create();

View File

@ -83,6 +83,7 @@ class MakeDialog::Impl
{
public:
Impl(MakeDialog& dialog, Glib::RefPtr<Gtk::Builder> const& builder, Glib::RefPtr<Session> const& core);
~Impl() = default;
TR_DISABLE_COPY_MOVE(Impl)

View File

@ -3,8 +3,7 @@
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.
#include <cerrno>
#include <cstdio>
#include <fstream>
#include <map>
#include <memory>
@ -12,6 +11,7 @@
#include <glibmm/i18n.h>
#include <fmt/core.h>
#include <fmt/ostream.h>
#include <libtransmission/transmission.h>
#include <libtransmission/log.h>
@ -37,7 +37,7 @@ public:
Gtk::TreeModelColumn<unsigned int> sequence;
Gtk::TreeModelColumn<Glib::ustring> name;
Gtk::TreeModelColumn<Glib::ustring> message;
Gtk::TreeModelColumn<tr_log_message*> tr_msg;
Gtk::TreeModelColumn<tr_log_message const*> tr_msg;
};
MessageLogColumnsModel const message_log_cols;
@ -179,27 +179,12 @@ Glib::ustring gtr_asctime(time_t t)
void MessageLogWindow::Impl::doSave(Gtk::Window& parent, Glib::ustring const& filename)
{
auto* fp = std::fopen(filename.c_str(), "w+");
try
{
auto stream = std::ofstream();
stream.exceptions(std::ios_base::failbit | std::ios_base::badbit);
stream.open(Glib::locale_from_utf8(filename), std::ios_base::trunc);
if (fp == nullptr)
{
auto const errcode = errno;
auto w = std::make_shared<Gtk::MessageDialog>(
parent,
fmt::format(
_("Couldn't save '{path}': {error} ({error_code})"),
fmt::arg("path", filename),
fmt::arg("error", g_strerror(errcode)),
fmt::arg("error_code", errcode)),
false,
TR_GTK_MESSAGE_TYPE(ERROR),
TR_GTK_BUTTONS_TYPE(CLOSE));
w->set_secondary_text(Glib::strerror(errno));
w->signal_response().connect([w](int /*response*/) mutable { w.reset(); });
w->show();
}
else
{
for (auto const& row : store_->children())
{
auto const* const node = row.get_value(message_log_cols.tr_msg);
@ -208,10 +193,24 @@ void MessageLogWindow::Impl::doSave(Gtk::Window& parent, Glib::ustring const& fi
auto const it = level_names_.find(node->level);
auto const* const level_str = it != std::end(level_names_) ? it->second : "???";
fmt::print(fp, "{}\t{}\t{}\t{}\n", date, level_str, node->name, node->message);
fmt::print(stream, "{}\t{}\t{}\t{}\n", date, level_str, node->name, node->message);
}
std::fclose(fp);
}
catch (std::ios_base::failure const& e)
{
auto w = std::make_shared<Gtk::MessageDialog>(
parent,
fmt::format(
_("Couldn't save '{path}': {error} ({error_code})"),
fmt::arg("path", filename),
fmt::arg("error", e.code().message()),
fmt::arg("error_code", e.code().value())),
false,
TR_GTK_MESSAGE_TYPE(ERROR),
TR_GTK_BUTTONS_TYPE(CLOSE));
w->set_secondary_text(e.code().message());
w->signal_response().connect([w](int /*response*/) mutable { w.reset(); });
w->show();
}
}
@ -296,7 +295,7 @@ void renderTime(Gtk::CellRendererText* renderer, Gtk::TreeModel::const_iterator
void appendColumn(Gtk::TreeView* view, Gtk::TreeModelColumnBase const& col)
{
Gtk::TreeViewColumn* c;
Gtk::TreeViewColumn* c = nullptr;
if (col == message_log_cols.name)
{
@ -349,36 +348,38 @@ namespace
tr_log_message* addMessages(Glib::RefPtr<Gtk::ListStore> const& store, tr_log_message* head)
{
tr_log_message* i;
static unsigned int sequence = 0;
auto const default_name = Glib::get_application_name();
for (i = head; i != nullptr && i->next != nullptr; i = i->next)
while (head != nullptr && head->next != nullptr)
{
char const* name = !std::empty(i->name) ? i->name.c_str() : default_name.c_str();
auto const& message = *head;
head = head->next;
char const* name = !std::empty(message.name) ? message.name.c_str() : default_name.c_str();
auto row_it = store->prepend();
auto& row = *row_it;
row[message_log_cols.tr_msg] = i;
row[message_log_cols.tr_msg] = &message;
row[message_log_cols.name] = name;
row[message_log_cols.message] = i->message;
row[message_log_cols.message] = message.message;
row[message_log_cols.sequence] = ++sequence;
/* if it's an error message, dump it to the terminal too */
if (i->level == TR_LOG_ERROR)
if (message.level == TR_LOG_ERROR)
{
auto gstr = fmt::format("{}:{} {}", i->file, i->line, i->message);
auto gstr = fmt::format("{}:{} {}", message.file, message.line, message.message);
if (!std::empty(i->name))
if (!std::empty(message.name))
{
gstr += fmt::format(" ({})", i->name.c_str());
gstr += fmt::format(" ({})", message.name.c_str());
}
g_warning("%s", gstr.c_str());
gtr_warning(gstr);
}
}
return i; /* tail */
return head; /* tail */
}
} // namespace
@ -447,6 +448,13 @@ MessageLogWindow::Impl::Impl(
: window_(window)
, core_(core)
, view_(gtr_get_widget<Gtk::TreeView>(builder, "messages_view"))
, store_(Gtk::ListStore::create(message_log_cols))
, filter_(Gtk::TreeModelFilter::create(store_))
, sort_(Gtk::TreeModelSort::create(filter_))
, maxLevel_(static_cast<tr_log_level>(gtr_pref_int_get(TR_KEY_message_level)))
, refresh_tag_(Glib::signal_timeout().connect_seconds(
sigc::mem_fun(*this, &Impl::onRefresh),
SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS))
, level_names_{ {
{ TR_LOG_CRITICAL, C_("Logging level", "Critical") },
{ TR_LOG_ERROR, C_("Logging level", "Error") },
@ -485,15 +493,10 @@ MessageLogWindow::Impl::Impl(
*** messages
**/
store_ = Gtk::ListStore::create(message_log_cols);
addMessages(store_, myHead);
onRefresh(); /* much faster to populate *before* it has listeners */
filter_ = Gtk::TreeModelFilter::create(store_);
sort_ = Gtk::TreeModelSort::create(filter_);
sort_->set_sort_column(message_log_cols.sequence, TR_GTK_SORT_TYPE(ASCENDING));
maxLevel_ = static_cast<tr_log_level>(gtr_pref_int_get(TR_KEY_message_level));
filter_->set_visible_func(sigc::mem_fun(*this, &Impl::isRowVisible));
view_->set_model(sort_);
@ -505,9 +508,5 @@ MessageLogWindow::Impl::Impl(
appendColumn(view_, message_log_cols.name);
appendColumn(view_, message_log_cols.message);
refresh_tag_ = Glib::signal_timeout().connect_seconds(
sigc::mem_fun(*this, &Impl::onRefresh),
SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS);
scroll_to_bottom();
}

View File

@ -136,14 +136,11 @@ void dbus_proxy_ready_callback(Glib::RefPtr<Gio::AsyncResult>& res)
}
catch (Glib::Error const& e)
{
g_warning(
"%s",
fmt::format(
_("Couldn't create proxy for '{bus}': {error} ({error_code})"),
fmt::arg("bus", NotificationsDbusName),
fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)),
fmt::arg("error_code", e.code()))
.c_str());
gtr_warning(fmt::format(
_("Couldn't create proxy for '{bus}': {error} ({error_code})"),
fmt::arg("bus", NotificationsDbusName),
fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)),
fmt::arg("error_code", e.code())));
return;
}

View File

@ -66,6 +66,7 @@ public:
Glib::RefPtr<Gtk::Builder> const& builder,
Glib::RefPtr<Session> const& core,
std::unique_ptr<tr_ctor, void (*)(tr_ctor*)> ctor);
~Impl() = default;
TR_DISABLE_COPY_MOVE(Impl)
@ -289,7 +290,7 @@ OptionsDialog::Impl::Impl(
destination_chooser->signal_selection_changed().connect([this, destination_chooser]()
{ downloadDirChanged(destination_chooser); });
bool flag;
bool flag = false;
if (!tr_ctorGetPaused(ctor_.get(), TR_FORCE, &flag))
{
g_assert_not_reached();

View File

@ -14,6 +14,7 @@ class PathButton::Impl
{
public:
explicit Impl(PathButton& widget);
~Impl() = default;
TR_DISABLE_COPY_MOVE(Impl)
@ -133,7 +134,7 @@ void PathButton::Impl::show_dialog()
auto const title = title_.get_value();
auto dialog = std::make_shared<Gtk::FileChooserDialog>(!title.empty() ? title : _("Select a File"), action_.get_value());
dialog->set_transient_for(*static_cast<Gtk::Window*>(widget_.get_root()));
dialog->set_transient_for(gtr_widget_get_window(widget_));
dialog->add_button(_("_Cancel"), Gtk::ResponseType::CANCEL);
dialog->add_button(_("_Open"), Gtk::ResponseType::ACCEPT);
dialog->set_modal(true);

View File

@ -129,7 +129,7 @@ tr_variant* gtr_pref_get_all()
int64_t gtr_pref_int_get(tr_quark const key)
{
int64_t i;
int64_t i = 0;
return tr_variantDictFindInt(getPrefs(), key, &i) ? i : 0;
}
@ -141,7 +141,7 @@ void gtr_pref_int_set(tr_quark const key, int64_t value)
double gtr_pref_double_get(tr_quark const key)
{
double d;
double d = 0;
return tr_variantDictFindReal(getPrefs(), key, &d) ? d : 0.0;
}
@ -157,7 +157,7 @@ void gtr_pref_double_set(tr_quark const key, double value)
bool gtr_pref_flag_get(tr_quark const key)
{
bool boolVal;
bool boolVal = false;
return tr_variantDictFindBool(getPrefs(), key, &boolVal) ? boolVal : false;
}

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@ TrVariantPtr create_variant(tr_variant&& other)
[](tr_variant* ptr)
{
tr_variantClear(ptr);
delete ptr;
std::default_delete<tr_variant>()(ptr);
});
*result = std::move(other);
tr_variantInitBool(&other, false);
@ -109,13 +109,35 @@ public:
void commit_prefs_change(tr_quark key);
public:
sigc::signal<void(ErrorCode, Glib::ustring const&)> signal_add_error;
sigc::signal<void(tr_ctor*)> signal_add_prompt;
sigc::signal<void(int)> signal_blocklist_updated;
sigc::signal<void(bool)> signal_busy;
sigc::signal<void(tr_quark)> signal_prefs_changed;
sigc::signal<void(bool)> signal_port_tested;
auto& signal_add_error()
{
return signal_add_error_;
}
auto& signal_add_prompt()
{
return signal_add_prompt_;
}
auto& signal_blocklist_updated()
{
return signal_blocklist_updated_;
}
auto& signal_busy()
{
return signal_busy_;
}
auto& signal_prefs_changed()
{
return signal_prefs_changed_;
}
auto& signal_port_tested()
{
return signal_port_tested_;
}
private:
Glib::RefPtr<Session> get_core_ptr() const;
@ -157,6 +179,13 @@ private:
private:
Session& core_;
sigc::signal<void(ErrorCode, Glib::ustring const&)> signal_add_error_;
sigc::signal<void(tr_ctor*)> signal_add_prompt_;
sigc::signal<void(int)> signal_blocklist_updated_;
sigc::signal<void(bool)> signal_busy_;
sigc::signal<void(tr_quark)> signal_prefs_changed_;
sigc::signal<void(bool)> signal_port_tested_;
Glib::RefPtr<Gio::FileMonitor> monitor_;
sigc::connection monitor_tag_;
Glib::RefPtr<Gio::File> monitor_dir_;
@ -253,7 +282,7 @@ void Session::Impl::add_to_busy(int addMe)
if (wasBusy != is_busy())
{
signal_busy.emit(is_busy());
signal_busy_.emit(is_busy());
}
}
@ -304,69 +333,15 @@ int compare_eta(int a, int b)
return a < b ? 1 : -1;
}
int compare_double(double a, double b)
template<typename T>
int compare_generic(T&& a, T&& b)
{
int ret;
if (a < b)
{
ret = -1;
}
else if (a > b)
{
ret = 1;
}
else
{
ret = 0;
}
return ret;
}
int compare_uint64(uint64_t a, uint64_t b)
{
int ret;
if (a < b)
{
ret = -1;
}
else if (a > b)
{
ret = 1;
}
else
{
ret = 0;
}
return ret;
}
int compare_int(int a, int b)
{
int ret;
if (a < b)
{
ret = -1;
}
else if (a > b)
{
ret = 1;
}
else
{
ret = 0;
}
return ret;
return a < b ? -1 : (a > b ? 1 : 0);
}
int compare_ratio(double a, double b)
{
int ret;
int ret = 0;
if ((int)a == TR_RATIO_INF && (int)b == TR_RATIO_INF)
{
@ -382,27 +357,7 @@ int compare_ratio(double a, double b)
}
else
{
ret = compare_double(a, b);
}
return ret;
}
int compare_time(time_t a, time_t b)
{
int ret;
if (a < b)
{
ret = -1;
}
else if (a > b)
{
ret = 1;
}
else
{
ret = 0;
ret = compare_generic(a, b);
}
return ret;
@ -452,13 +407,13 @@ int compare_by_activity(Gtk::TreeModel::const_iterator const& a, Gtk::TreeModel:
auto const bUp = b->get_value(torrent_cols.speed_up);
auto const bDown = b->get_value(torrent_cols.speed_down);
ret = compare_double(aUp + aDown, bUp + bDown);
ret = compare_generic(aUp + aDown, bUp + bDown);
if (ret == 0)
{
auto const* const sa = tr_torrentStatCached(ta);
auto const* const sb = tr_torrentStatCached(tb);
ret = compare_uint64(sa->peersSendingToUs + sa->peersGettingFromUs, sb->peersSendingToUs + sb->peersGettingFromUs);
ret = compare_generic(sa->peersSendingToUs + sa->peersGettingFromUs, sb->peersSendingToUs + sb->peersGettingFromUs);
}
if (ret == 0)
@ -473,7 +428,7 @@ int compare_by_age(Gtk::TreeModel::const_iterator const& a, Gtk::TreeModel::cons
{
auto* const ta = static_cast<tr_torrent*>(a->get_value(torrent_cols.torrent));
auto* const tb = static_cast<tr_torrent*>(b->get_value(torrent_cols.torrent));
int ret = compare_time(tr_torrentStatCached(ta)->addedDate, tr_torrentStatCached(tb)->addedDate);
int ret = compare_generic(tr_torrentStatCached(ta)->addedDate, tr_torrentStatCached(tb)->addedDate);
if (ret == 0)
{
@ -487,7 +442,7 @@ int compare_by_size(Gtk::TreeModel::const_iterator const& a, Gtk::TreeModel::con
{
auto const size_a = tr_torrentTotalSize(static_cast<tr_torrent*>(a->get_value(torrent_cols.torrent)));
auto const size_b = tr_torrentTotalSize(static_cast<tr_torrent*>(b->get_value(torrent_cols.torrent)));
int ret = compare_uint64(size_a, size_b);
int ret = compare_generic(size_a, size_b);
if (ret == 0)
{
@ -501,11 +456,11 @@ int compare_by_progress(Gtk::TreeModel::const_iterator const& a, Gtk::TreeModel:
{
auto const* const sa = tr_torrentStatCached(static_cast<tr_torrent*>(a->get_value(torrent_cols.torrent)));
auto const* const sb = tr_torrentStatCached(static_cast<tr_torrent*>(b->get_value(torrent_cols.torrent)));
int ret = compare_double(sa->percentComplete, sb->percentComplete);
int ret = compare_generic(sa->percentComplete, sb->percentComplete);
if (ret == 0)
{
ret = compare_double(sa->seedRatioPercentDone, sb->seedRatioPercentDone);
ret = compare_generic(sa->seedRatioPercentDone, sb->seedRatioPercentDone);
}
if (ret == 0)
@ -534,7 +489,7 @@ int compare_by_state(Gtk::TreeModel::const_iterator const& a, Gtk::TreeModel::co
{
auto const sa = a->get_value(torrent_cols.activity);
auto const sb = b->get_value(torrent_cols.activity);
int ret = compare_int(sa, sb);
int ret = compare_generic(sa, sb);
if (ret == 0)
{
@ -638,13 +593,12 @@ void rename_torrent(Glib::RefPtr<Gio::File> const& file)
}
catch (Glib::Error const& e)
{
auto const errmsg = fmt::format(
gtr_message(fmt::format(
_("Couldn't rename '{old_path}' as '{path}': {error} ({error_code})"),
fmt::arg("old_path", old_name),
fmt::arg("path", new_name),
fmt::arg("error", e.what()),
fmt::arg("error_code", e.code()));
g_message("%s", errmsg.c_str());
fmt::arg("error_code", e.code())));
}
}
@ -821,6 +775,7 @@ void Session::Impl::on_pref_changed(tr_quark const key)
Glib::RefPtr<Session> Session::create(tr_session* session)
{
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
return Glib::make_refptr_for_instance(new Session(session));
}
@ -847,7 +802,7 @@ Session::Impl::Impl(Session& core, tr_session* session)
on_pref_changed(TR_KEY_watch_dir_enabled);
on_pref_changed(TR_KEY_peer_limit_global);
on_pref_changed(TR_KEY_inhibit_desktop_hibernation);
signal_prefs_changed.connect([this](auto key) { on_pref_changed(key); });
signal_prefs_changed_.connect([this](auto key) { on_pref_changed(key); });
tr_sessionSetMetadataCallback(
session,
@ -1065,7 +1020,7 @@ int Session::Impl::add_ctor(tr_ctor* ctor, bool do_prompt, bool do_notify)
* don't want to be nagging users to clean up their watch dirs */
if (tr_ctorGetSourceFile(ctor) == nullptr || !adding_from_watch_dir_)
{
signal_add_error.emit(ERR_ADD_TORRENT_DUP, metainfo->name().c_str());
signal_add_error_.emit(ERR_ADD_TORRENT_DUP, metainfo->name().c_str());
}
tr_ctorFree(ctor);
@ -1080,7 +1035,7 @@ int Session::Impl::add_ctor(tr_ctor* ctor, bool do_prompt, bool do_notify)
return 0;
}
signal_add_prompt.emit(ctor);
signal_add_prompt_.emit(ctor);
return 0;
}
@ -1131,15 +1086,14 @@ void Session::Impl::add_file_async_callback(
bool do_prompt,
bool do_notify)
{
gsize length;
char* contents;
try
{
gsize length = 0;
char* contents = nullptr;
if (!file->load_contents_finish(result, contents, length))
{
auto const errmsg = fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", file->get_parse_name()));
g_message("%s", errmsg.c_str());
gtr_message(fmt::format(_("Couldn't read '{path}'"), fmt::arg("path", file->get_parse_name())));
}
else if (tr_ctorSetMetainfo(ctor, contents, length, nullptr))
{
@ -1152,12 +1106,11 @@ void Session::Impl::add_file_async_callback(
}
catch (Glib::Error const& e)
{
auto const errmsg = fmt::format(
gtr_message(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", file->get_parse_name()),
fmt::arg("error", e.what()),
fmt::arg("error_code", e.code()));
g_message("%s", errmsg.c_str());
fmt::arg("error_code", e.code())));
}
dec_busy();
@ -1252,7 +1205,7 @@ void Session::torrents_added()
void Session::Impl::torrents_added()
{
update();
signal_add_error.emit(ERR_NO_MORE_TORRENTS, {});
signal_add_error_.emit(ERR_NO_MORE_TORRENTS, {});
}
void Session::torrent_changed(tr_torrent_id_t id)
@ -1550,7 +1503,7 @@ void Session::Impl::maybe_inhibit_hibernation()
void Session::Impl::commit_prefs_change(tr_quark const key)
{
signal_prefs_changed.emit(key);
signal_prefs_changed_.emit(key);
gtr_pref_save(session_);
}
@ -1620,7 +1573,7 @@ bool core_read_rpc_response_idle(TrVariantPtr const& response)
}
else
{
g_warning("%s", fmt::format(_("Couldn't find pending RPC request for tag {tag}"), fmt::arg("tag", tag)).c_str());
gtr_warning(fmt::format(_("Couldn't find pending RPC request for tag {tag}"), fmt::arg("tag", tag)));
}
}
@ -1642,7 +1595,7 @@ void Session::Impl::send_rpc_request(
{
if (session_ == nullptr)
{
g_error("GTK+ client doesn't support connections to remote servers yet.");
gtr_error("GTK+ client doesn't support connections to remote servers yet.");
}
else
{
@ -1651,7 +1604,7 @@ void Session::Impl::send_rpc_request(
/* make the request */
#ifdef DEBUG_RPC
g_message("%s", fmt::format("request: [{}]", tr_variantToStr(request, TR_VARIANT_FMT_JSON_LEAN)).c_str());
gtr_message(fmt::format("request: [{}]", tr_variantToStr(request, TR_VARIANT_FMT_JSON_LEAN)));
#endif
tr_rpc_request_exec_json(session_, request, core_read_rpc_response, nullptr);
@ -1676,8 +1629,8 @@ void Session::port_test()
tag,
[this](auto* response)
{
tr_variant* args;
bool is_open;
tr_variant* args = nullptr;
bool is_open = false;
if (!tr_variantDictFindDict(response, TR_KEY_arguments, &args) ||
!tr_variantDictFindBool(args, TR_KEY_port_is_open, &is_open))
@ -1685,7 +1638,7 @@ void Session::port_test()
is_open = false;
}
impl_->signal_port_tested.emit(is_open);
impl_->signal_port_tested().emit(is_open);
});
tr_variantClear(&request);
}
@ -1708,8 +1661,8 @@ void Session::blocklist_update()
tag,
[this](auto* response)
{
tr_variant* args;
int64_t ruleCount;
tr_variant* args = nullptr;
int64_t ruleCount = 0;
if (!tr_variantDictFindDict(response, TR_KEY_arguments, &args) ||
!tr_variantDictFindInt(args, TR_KEY_blocklist_size, &ruleCount))
@ -1722,7 +1675,7 @@ void Session::blocklist_update()
gtr_pref_int_set(TR_KEY_blocklist_date, tr_time());
}
impl_->signal_blocklist_updated.emit(ruleCount);
impl_->signal_blocklist_updated().emit(ruleCount);
});
tr_variantClear(&request);
}
@ -1802,30 +1755,30 @@ void Session::open_folder(tr_torrent_id_t torrent_id) const
sigc::signal<void(Session::ErrorCode, Glib::ustring const&)>& Session::signal_add_error()
{
return impl_->signal_add_error;
return impl_->signal_add_error();
}
sigc::signal<void(tr_ctor*)>& Session::signal_add_prompt()
{
return impl_->signal_add_prompt;
return impl_->signal_add_prompt();
}
sigc::signal<void(int)>& Session::signal_blocklist_updated()
{
return impl_->signal_blocklist_updated;
return impl_->signal_blocklist_updated();
}
sigc::signal<void(bool)>& Session::signal_busy()
{
return impl_->signal_busy;
return impl_->signal_busy();
}
sigc::signal<void(tr_quark)>& Session::signal_prefs_changed()
{
return impl_->signal_prefs_changed;
return impl_->signal_prefs_changed();
}
sigc::signal<void(bool)>& Session::signal_port_tested()
{
return impl_->signal_port_tested;
return impl_->signal_port_tested();
}

View File

@ -29,16 +29,12 @@
#include "SystemTrayIcon.h"
#include "Utils.h"
#define TR_SYS_TRAY_IMPL_NONE 0
#define TR_SYS_TRAY_IMPL_APPINDICATOR 1
#define TR_SYS_TRAY_IMPL_STATUS_ICON 2
#ifdef HAVE_APPINDICATOR
#define TR_SYS_TRAY_IMPL TR_SYS_TRAY_IMPL_APPINDICATOR
#define TR_SYS_TRAY_IMPL_APPINDICATOR
#elif !GTKMM_CHECK_VERSION(4, 0, 0)
#define TR_SYS_TRAY_IMPL TR_SYS_TRAY_IMPL_STATUS_ICON
#define TR_SYS_TRAY_IMPL_STATUS_ICON
#else
#define TR_SYS_TRAY_IMPL TR_SYS_TRAY_IMPL_NONE
#define TR_SYS_TRAY_IMPL_NONE
#endif
using namespace std::literals;
@ -46,12 +42,12 @@ using namespace std::literals;
namespace
{
#if TR_SYS_TRAY_IMPL != TR_SYS_TRAY_IMPL_NONE
#if !defined(TR_SYS_TRAY_IMPL_NONE)
auto const TrayIconName = Glib::ustring("transmission-tray-icon"s);
auto const AppIconName = Glib::ustring("transmission"s);
#endif
#if TR_SYS_TRAY_IMPL == TR_SYS_TRAY_IMPL_APPINDICATOR
#if defined(TR_SYS_TRAY_IMPL_APPINDICATOR)
auto const AppName = Glib::ustring("transmission-gtk"s);
#endif
@ -76,18 +72,18 @@ private:
private:
Glib::RefPtr<Session> const core_;
#if TR_SYS_TRAY_IMPL != TR_SYS_TRAY_IMPL_NONE
#if !defined(TR_SYS_TRAY_IMPL_NONE)
Gtk::Menu* menu_;
#endif
#if TR_SYS_TRAY_IMPL == TR_SYS_TRAY_IMPL_APPINDICATOR
#if defined(TR_SYS_TRAY_IMPL_APPINDICATOR)
AppIndicator* indicator_;
#elif TR_SYS_TRAY_IMPL == TR_SYS_TRAY_IMPL_STATUS_ICON
#elif defined(TR_SYS_TRAY_IMPL_STATUS_ICON)
Glib::RefPtr<Gtk::StatusIcon> icon_;
#endif
};
#if TR_SYS_TRAY_IMPL == TR_SYS_TRAY_IMPL_APPINDICATOR
#if defined(TR_SYS_TRAY_IMPL_APPINDICATOR)
SystemTrayIcon::Impl::~Impl()
{
@ -98,7 +94,7 @@ void SystemTrayIcon::Impl::refresh()
{
}
#elif TR_SYS_TRAY_IMPL == TR_SYS_TRAY_IMPL_STATUS_ICON
#elif defined(TR_SYS_TRAY_IMPL_STATUS_ICON)
SystemTrayIcon::Impl::~Impl() = default;
@ -126,7 +122,7 @@ SystemTrayIcon::Impl::~Impl() = default;
namespace
{
#if TR_SYS_TRAY_IMPL != TR_SYS_TRAY_IMPL_NONE
#if !defined(TR_SYS_TRAY_IMPL_NONE)
Glib::ustring getIconName()
{
@ -162,14 +158,14 @@ SystemTrayIcon::~SystemTrayIcon() = default;
void SystemTrayIcon::refresh()
{
#if TR_SYS_TRAY_IMPL != TR_SYS_TRAY_IMPL_NONE
#if !defined(TR_SYS_TRAY_IMPL_NONE)
impl_->refresh();
#endif
}
bool SystemTrayIcon::is_available()
{
#if TR_SYS_TRAY_IMPL != TR_SYS_TRAY_IMPL_NONE
#if !defined(TR_SYS_TRAY_IMPL_NONE)
return true;
#else
return false;
@ -184,18 +180,18 @@ std::unique_ptr<SystemTrayIcon> SystemTrayIcon::create(Gtk::Window& main_window,
SystemTrayIcon::Impl::Impl([[maybe_unused]] Gtk::Window& main_window, Glib::RefPtr<Session> const& core)
: core_(core)
{
#if TR_SYS_TRAY_IMPL != TR_SYS_TRAY_IMPL_NONE
#if !defined(TR_SYS_TRAY_IMPL_NONE)
auto const icon_name = getIconName();
menu_ = Gtk::make_managed<Gtk::Menu>(gtr_action_get_object<Gio::Menu>("icon-popup"));
menu_->attach_to_widget(main_window);
#endif
#if TR_SYS_TRAY_IMPL == TR_SYS_TRAY_IMPL_APPINDICATOR
#if defined(TR_SYS_TRAY_IMPL_APPINDICATOR)
indicator_ = app_indicator_new(AppName.c_str(), icon_name.c_str(), APP_INDICATOR_CATEGORY_SYSTEM_SERVICES);
app_indicator_set_status(indicator_, APP_INDICATOR_STATUS_ACTIVE);
app_indicator_set_menu(indicator_, Glib::unwrap(menu_));
app_indicator_set_title(indicator_, Glib::get_application_name().c_str());
#elif TR_SYS_TRAY_IMPL == TR_SYS_TRAY_IMPL_STATUS_ICON
#elif defined(TR_SYS_TRAY_IMPL_STATUS_ICON)
icon_ = Gtk::StatusIcon::create(icon_name);
icon_->signal_activate().connect(sigc::mem_fun(*this, &Impl::activated));
icon_->signal_popup_menu().connect(sigc::mem_fun(*this, &Impl::popup));

View File

@ -29,9 +29,6 @@
****
***/
#define REQ_HEIGHT(Obj) IF_GTKMM4((Obj).get_height(), (Obj).height)
#define REQ_WIDTH(Obj) IF_GTKMM4((Obj).get_width(), (Obj).width)
namespace
{
@ -41,6 +38,16 @@ auto const SmallScale = 0.9;
auto const CompactIconSize = IF_GTKMM4(Gtk::IconSize::NORMAL, Gtk::ICON_SIZE_MENU);
auto const FullIconSize = IF_GTKMM4(Gtk::IconSize::LARGE, Gtk::ICON_SIZE_DND);
auto get_height(Gtk::Requisition const& req)
{
return req.IF_GTKMM4(get_height(), height);
}
auto get_width(Gtk::Requisition const& req)
{
return req.IF_GTKMM4(get_width(), width);
}
auto getProgressString(tr_torrent const* tor, uint64_t total_size, tr_stat const* st)
{
Glib::ustring gstr;
@ -48,7 +55,7 @@ auto getProgressString(tr_torrent const* tor, uint64_t total_size, tr_stat const
bool const isDone = st->leftUntilDone == 0;
uint64_t const haveTotal = st->haveUnchecked + st->haveValid;
bool const isSeed = st->haveValid >= total_size;
double seedRatio;
double seedRatio = 0;
bool const hasSeedRatio = tr_torrentGetSeedRatio(tor, &seedRatio);
if (!isDone) // downloading
@ -331,20 +338,30 @@ public:
Gdk::Rectangle const& background_area,
Gtk::CellRendererState flags);
public:
Glib::Property<gpointer> torrent;
Glib::Property<int> bar_height;
auto& property_torrent()
{
return property_torrent_;
}
/* Use this instead of tr_stat.pieceUploadSpeed so that the model can
control when the speed displays get updated. This is done to keep
the individual torrents' speeds and the status bar's overall speed
in sync even if they refresh at slightly different times */
Glib::Property<double> upload_speed_KBps;
auto& property_bar_height()
{
return property_bar_height_;
}
/* @see upload_speed_Bps */
Glib::Property<double> download_speed_KBps;
auto& property_upload_speed_KBps()
{
return property_upload_speed_KBps_;
}
Glib::Property<bool> compact;
auto& property_download_speed_KBps()
{
return property_download_speed_KBps_;
}
auto& property_compact()
{
return property_compact_;
}
private:
void render_progress_bar(
@ -366,6 +383,12 @@ private:
private:
TorrentCellRenderer& renderer_;
Glib::Property<gpointer> property_torrent_;
Glib::Property<int> property_bar_height_;
Glib::Property<double> property_upload_speed_KBps_;
Glib::Property<double> property_download_speed_KBps_;
Glib::Property<bool> property_compact_;
Gtk::CellRendererText* text_renderer_ = nullptr;
Gtk::CellRendererProgress* progress_renderer_ = nullptr;
Gtk::CellRendererPixbuf* icon_renderer_ = nullptr;
@ -421,19 +444,23 @@ void TorrentCellRenderer::Impl::set_icon(
void TorrentCellRenderer::Impl::get_size_compact(Gtk::Widget& widget, int& width, int& height) const
{
int xpad;
int ypad;
int xpad = 0;
int ypad = 0;
Gtk::Requisition min_size;
Gtk::Requisition icon_size;
Gtk::Requisition name_size;
Gtk::Requisition stat_size;
auto* const tor = static_cast<tr_torrent*>(torrent.get_value());
auto* const tor = static_cast<tr_torrent*>(property_torrent_.get_value());
auto const* const st = tr_torrentStatCached(tor);
auto const icon = get_icon(tor);
auto const name = Glib::ustring(tr_torrentName(tor));
auto const gstr_stat = getShortStatusString(tor, st, upload_speed_KBps.get_value(), download_speed_KBps.get_value());
auto const gstr_stat = getShortStatusString(
tor,
st,
property_upload_speed_KBps_.get_value(),
property_download_speed_KBps_.get_value());
renderer_.get_padding(xpad, ypad);
/* get the idealized cell dimensions */
@ -451,27 +478,32 @@ void TorrentCellRenderer::Impl::get_size_compact(Gtk::Widget& widget, int& width
*** LAYOUT
**/
width = xpad * 2 + REQ_WIDTH(icon_size) + GUI_PAD + CompactBarWidth + GUI_PAD + REQ_WIDTH(stat_size);
height = ypad * 2 + std::max(REQ_HEIGHT(name_size), bar_height.get_value());
width = xpad * 2 + get_width(icon_size) + GUI_PAD + CompactBarWidth + GUI_PAD + get_width(stat_size);
height = ypad * 2 + std::max(get_height(name_size), property_bar_height_.get_value());
}
void TorrentCellRenderer::Impl::get_size_full(Gtk::Widget& widget, int& width, int& height) const
{
int xpad;
int ypad;
int xpad = 0;
int ypad = 0;
Gtk::Requisition min_size;
Gtk::Requisition icon_size;
Gtk::Requisition name_size;
Gtk::Requisition stat_size;
Gtk::Requisition prog_size;
auto* const tor = static_cast<tr_torrent*>(torrent.get_value());
auto* const tor = static_cast<tr_torrent*>(property_torrent_.get_value());
auto const* const st = tr_torrentStatCached(tor);
auto const total_size = tr_torrentTotalSize(tor);
auto const icon = get_icon(tor);
auto const name = Glib::ustring(tr_torrentName(tor));
auto const gstr_stat = getStatusString(tor, st, upload_speed_KBps.get_value(), download_speed_KBps.get_value(), true);
auto const gstr_stat = getStatusString(
tor,
st,
property_upload_speed_KBps_.get_value(),
property_download_speed_KBps_.get_value(),
true);
auto const gstr_prog = getProgressString(tor, total_size, st);
renderer_.get_padding(xpad, ypad);
@ -494,19 +526,19 @@ void TorrentCellRenderer::Impl::get_size_full(Gtk::Widget& widget, int& width, i
*** LAYOUT
**/
width = xpad * 2 + REQ_WIDTH(icon_size) + GUI_PAD + std::max(REQ_WIDTH(prog_size), REQ_WIDTH(stat_size));
height = ypad * 2 + REQ_HEIGHT(name_size) + REQ_HEIGHT(prog_size) + GUI_PAD_SMALL + bar_height.get_value() + GUI_PAD_SMALL +
REQ_HEIGHT(stat_size);
width = xpad * 2 + get_width(icon_size) + GUI_PAD + std::max(get_width(prog_size), get_width(stat_size));
height = ypad * 2 + get_height(name_size) + get_height(prog_size) + GUI_PAD_SMALL + property_bar_height_.get_value() +
GUI_PAD_SMALL + get_height(stat_size);
}
void TorrentCellRenderer::get_preferred_width_vfunc(Gtk::Widget& widget, int& minimum_width, int& natural_width) const
{
if (impl_->torrent.get_value() != nullptr)
if (impl_->property_torrent().get_value() != nullptr)
{
int w;
int h;
int w = 0;
int h = 0;
if (impl_->compact.get_value())
if (impl_->property_compact().get_value())
{
impl_->get_size_compact(widget, w, h);
}
@ -522,12 +554,12 @@ void TorrentCellRenderer::get_preferred_width_vfunc(Gtk::Widget& widget, int& mi
void TorrentCellRenderer::get_preferred_height_vfunc(Gtk::Widget& widget, int& minimum_height, int& natural_height) const
{
if (impl_->torrent.get_value() != nullptr)
if (impl_->property_torrent().get_value() != nullptr)
{
int w;
int h;
int w = 0;
int h = 0;
if (impl_->compact.get_value())
if (impl_->property_compact().get_value())
{
impl_->get_size_compact(widget, w, h);
}
@ -544,22 +576,10 @@ void TorrentCellRenderer::get_preferred_height_vfunc(Gtk::Widget& widget, int& m
namespace
{
double get_percent_done(tr_torrent const* tor, tr_stat const* st, bool* seed)
int get_percent_done(tr_torrent const* tor, tr_stat const* st)
{
double d;
if (st->activity == TR_STATUS_SEED && tr_torrentGetSeedRatio(tor, &d))
{
*seed = true;
d = MAX(0.0, st->seedRatioPercentDone);
}
else
{
*seed = false;
d = MAX(0.0, st->percentDone);
}
return d;
auto const seed = st->activity == TR_STATUS_SEED && tr_torrentGetSeedRatio(tor, nullptr);
return static_cast<int>(seed ? std::max(0.0F, st->seedRatioPercentDone) : std::max(0.0F, st->percentDone));
}
Gdk::RGBA const& get_progress_bar_color(tr_stat const& st)
@ -683,17 +703,16 @@ void TorrentCellRenderer::Impl::render_compact(
Gdk::Rectangle const& background_area,
Gtk::CellRendererState flags)
{
int xpad;
int ypad;
int min_width;
int width;
bool seed;
int xpad = 0;
int ypad = 0;
int min_width = 0;
int width = 0;
auto* const tor = static_cast<tr_torrent*>(torrent.get_value());
auto* const tor = static_cast<tr_torrent*>(property_torrent_.get_value());
auto const* const st = tr_torrentStatCached(tor);
bool const active = st->activity != TR_STATUS_STOPPED && st->activity != TR_STATUS_DOWNLOAD_WAIT &&
st->activity != TR_STATUS_SEED_WAIT;
auto const percentDone = get_percent_done(tor, st, &seed);
auto const percent_done = get_percent_done(tor, st);
bool const sensitive = active || st->error != 0;
if (st->activity == TR_STATUS_STOPPED)
@ -713,7 +732,11 @@ void TorrentCellRenderer::Impl::render_compact(
auto const icon = get_icon(tor);
auto const name = Glib::ustring(tr_torrentName(tor));
auto const& progress_color = get_progress_bar_color(*st);
auto const gstr_stat = getShortStatusString(tor, st, upload_speed_KBps.get_value(), download_speed_KBps.get_value());
auto const gstr_stat = getShortStatusString(
tor,
st,
property_upload_speed_KBps_.get_value(),
property_download_speed_KBps_.get_value());
renderer_.get_padding(xpad, ypad);
auto fill_area = background_area;
@ -764,7 +787,6 @@ void TorrentCellRenderer::Impl::render_compact(
icon_renderer_->property_sensitive() = sensitive;
render_impl(*icon_renderer_, snapshot, widget, icon_area, icon_area, flags);
auto const percent_done = static_cast<int>(percentDone * 100.0);
progress_renderer_->property_value() = percent_done;
progress_renderer_->property_text() = fmt::format(FMT_STRING("{:d}%"), percent_done);
progress_renderer_->property_sensitive() = sensitive;
@ -786,18 +808,17 @@ void TorrentCellRenderer::Impl::render_full(
Gdk::Rectangle const& background_area,
Gtk::CellRendererState flags)
{
int xpad;
int ypad;
int xpad = 0;
int ypad = 0;
Gtk::Requisition min_size;
Gtk::Requisition size;
bool seed;
auto* const tor = static_cast<tr_torrent*>(torrent.get_value());
auto* const tor = static_cast<tr_torrent*>(property_torrent_.get_value());
auto const* const st = tr_torrentStatCached(tor);
auto const total_size = tr_torrentTotalSize(tor);
bool const active = st->activity != TR_STATUS_STOPPED && st->activity != TR_STATUS_DOWNLOAD_WAIT &&
st->activity != TR_STATUS_SEED_WAIT;
auto const percentDone = get_percent_done(tor, st, &seed);
auto const percent_done = get_percent_done(tor, st);
bool const sensitive = active || st->error != 0;
if (st->activity == TR_STATUS_STOPPED)
@ -818,15 +839,19 @@ void TorrentCellRenderer::Impl::render_full(
auto const name = Glib::ustring(tr_torrentName(tor));
auto const& progress_color = get_progress_bar_color(*st);
auto const gstr_prog = getProgressString(tor, total_size, st);
auto const gstr_stat = getStatusString(tor, st, upload_speed_KBps.get_value(), download_speed_KBps.get_value());
auto const gstr_stat = getStatusString(
tor,
st,
property_upload_speed_KBps_.get_value(),
property_download_speed_KBps_.get_value());
renderer_.get_padding(xpad, ypad);
/* get the idealized cell dimensions */
Gdk::Rectangle icon_area;
set_icon(*icon_renderer_, icon, FullIconSize);
icon_renderer_->get_preferred_size(widget, min_size, size);
icon_area.set_width(REQ_WIDTH(size));
icon_area.set_height(REQ_HEIGHT(size));
icon_area.set_width(get_width(size));
icon_area.set_height(get_height(size));
Gdk::Rectangle name_area;
text_renderer_->property_text() = name;
@ -834,19 +859,19 @@ void TorrentCellRenderer::Impl::render_full(
text_renderer_->property_ellipsize() = TR_PANGO_ELLIPSIZE_MODE(NONE);
text_renderer_->property_scale() = 1.0;
text_renderer_->get_preferred_size(widget, min_size, size);
name_area.set_height(REQ_HEIGHT(size));
name_area.set_height(get_height(size));
Gdk::Rectangle prog_area;
text_renderer_->property_text() = gstr_prog;
text_renderer_->property_weight() = TR_PANGO_WEIGHT(NORMAL);
text_renderer_->property_scale() = SmallScale;
text_renderer_->get_preferred_size(widget, min_size, size);
prog_area.set_height(REQ_HEIGHT(size));
prog_area.set_height(get_height(size));
Gdk::Rectangle stat_area;
text_renderer_->property_text() = gstr_stat;
text_renderer_->get_preferred_size(widget, min_size, size);
stat_area.set_height(REQ_HEIGHT(size));
stat_area.set_height(get_height(size));
Gdk::Rectangle prct_area;
@ -887,7 +912,7 @@ void TorrentCellRenderer::Impl::render_full(
prct_area.set_x(prog_area.get_x());
prct_area.set_y(prog_area.get_y() + prog_area.get_height() + GUI_PAD_SMALL);
prct_area.set_width(prog_area.get_width());
prct_area.set_height(bar_height.get_value());
prct_area.set_height(property_bar_height_.get_value());
/* status */
stat_area.set_x(prct_area.get_x());
@ -913,7 +938,7 @@ void TorrentCellRenderer::Impl::render_full(
text_renderer_->property_weight() = TR_PANGO_WEIGHT(NORMAL);
render_impl(*text_renderer_, snapshot, widget, prog_area, prog_area, flags);
progress_renderer_->property_value() = static_cast<int>(percentDone * 100.0);
progress_renderer_->property_value() = percent_done;
progress_renderer_->property_text() = Glib::ustring();
progress_renderer_->property_sensitive() = sensitive;
render_progress_bar(snapshot, widget, prct_area, flags, progress_color);
@ -934,9 +959,9 @@ void TorrentCellRenderer::IF_GTKMM4(snapshot_vfunc, render_vfunc)(
widget.set_direction(Gtk::TEXT_DIR_RTL);
#endif
if (impl_->torrent.get_value() != nullptr)
if (impl_->property_torrent().get_value() != nullptr)
{
if (impl_->compact.get_value())
if (impl_->property_compact().get_value())
{
impl_->render_compact(snapshot, widget, background_area, flags);
}
@ -967,42 +992,41 @@ TorrentCellRenderer::TorrentCellRenderer()
TorrentCellRenderer::~TorrentCellRenderer() = default;
TorrentCellRenderer::Impl::Impl(TorrentCellRenderer& renderer)
: torrent(renderer, "torrent", nullptr)
, bar_height(renderer, "bar-height", DefaultBarHeight)
, upload_speed_KBps(renderer, "piece-upload-speed", 0)
, download_speed_KBps(renderer, "piece-download-speed", 0)
, compact(renderer, "compact", false)
, renderer_(renderer)
: renderer_(renderer)
, property_torrent_(renderer, "torrent", nullptr)
, property_bar_height_(renderer, "bar-height", DefaultBarHeight)
, property_upload_speed_KBps_(renderer, "piece-upload-speed", 0)
, property_download_speed_KBps_(renderer, "piece-download-speed", 0)
, property_compact_(renderer, "compact", false)
, text_renderer_(Gtk::make_managed<Gtk::CellRendererText>())
, progress_renderer_(Gtk::make_managed<Gtk::CellRendererProgress>())
, icon_renderer_(Gtk::make_managed<Gtk::CellRendererPixbuf>())
{
text_renderer_ = Gtk::make_managed<Gtk::CellRendererText>();
text_renderer_->property_xpad() = 0;
text_renderer_->property_ypad() = 0;
progress_renderer_ = Gtk::make_managed<Gtk::CellRendererProgress>();
icon_renderer_ = Gtk::make_managed<Gtk::CellRendererPixbuf>();
}
Glib::PropertyProxy<gpointer> TorrentCellRenderer::property_torrent()
{
return impl_->torrent.get_proxy();
return impl_->property_torrent().get_proxy();
}
Glib::PropertyProxy<double> TorrentCellRenderer::property_piece_upload_speed()
{
return impl_->upload_speed_KBps.get_proxy();
return impl_->property_upload_speed_KBps().get_proxy();
}
Glib::PropertyProxy<double> TorrentCellRenderer::property_piece_download_speed()
{
return impl_->download_speed_KBps.get_proxy();
return impl_->property_download_speed_KBps().get_proxy();
}
Glib::PropertyProxy<int> TorrentCellRenderer::property_bar_height()
{
return impl_->bar_height.get_proxy();
return impl_->property_bar_height().get_proxy();
}
Glib::PropertyProxy<bool> TorrentCellRenderer::property_compact()
{
return impl_->compact.get_proxy();
return impl_->property_compact().get_proxy();
}

View File

@ -27,8 +27,16 @@ public:
TR_DISABLE_COPY_MOVE(TorrentCellRenderer)
Glib::PropertyProxy<gpointer> property_torrent();
/* Use this instead of tr_stat.pieceUploadSpeed so that the model can
control when the speed displays get updated. This is done to keep
the individual torrents' speeds and the status bar's overall speed
in sync even if they refresh at slightly different times */
Glib::PropertyProxy<double> property_piece_upload_speed();
/* @see property_piece_upload_speed */
Glib::PropertyProxy<double> property_piece_download_speed();
Glib::PropertyProxy<int> property_bar_height();
Glib::PropertyProxy<bool> property_compact();

View File

@ -6,6 +6,7 @@
#include <array>
#include <functional>
#include <memory>
#include <stdexcept>
#include <utility>
#include <giomm.h> /* g_file_trash() */
@ -60,6 +61,28 @@ char const* const speed_T_str = N_("TB/s");
****
***/
void gtr_message(std::string const& message)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
g_message("%s", message.c_str());
}
void gtr_warning(std::string const& message)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
g_warning("%s", message.c_str());
}
void gtr_error(std::string const& message)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
g_error("%s", message.c_str());
}
/***
****
***/
Glib::ustring gtr_get_unicode_string(GtrUnicode uni)
{
switch (uni)
@ -223,30 +246,9 @@ std::string tr_format_time_relative(time_t timestamp, time_t origin)
return timestamp < origin ? tr_format_future_time(origin - timestamp) : tr_format_past_time(timestamp - origin);
}
namespace
{
Gtk::Window* getWindow(Gtk::Widget* w)
{
if (w == nullptr)
{
return nullptr;
}
if (auto* const window = dynamic_cast<Gtk::Window*>(w); window != nullptr)
{
return window;
}
return static_cast<Gtk::Window*>(w->get_ancestor(Gtk::Window::get_type()));
}
} // namespace
void gtr_add_torrent_error_dialog(Gtk::Widget& child, tr_torrent* duplicate_torrent, std::string const& filename)
{
Glib::ustring secondary;
auto* win = getWindow(&child);
if (duplicate_torrent != nullptr)
{
@ -261,7 +263,7 @@ void gtr_add_torrent_error_dialog(Gtk::Widget& child, tr_torrent* duplicate_torr
}
auto w = std::make_shared<Gtk::MessageDialog>(
*win,
gtr_widget_get_window(child),
_("Couldn't open torrent"),
false,
TR_GTK_MESSAGE_TYPE(ERROR),
@ -390,14 +392,11 @@ bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error)
}
catch (Glib::Error const& e)
{
g_message(
"%s",
fmt::format(
_("Couldn't move '{path}' to trash: {error} ({error_code})"),
fmt::arg("path", filename),
fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)),
fmt::arg("error_code", e.code()))
.c_str());
gtr_message(fmt::format(
_("Couldn't move '{path}' to trash: {error} ({error_code})"),
fmt::arg("path", filename),
fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)),
fmt::arg("error_code", e.code())));
tr_error_set(error, e.code(), TR_GLIB_EXCEPTION_WHAT(e));
}
}
@ -410,14 +409,11 @@ bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error)
}
catch (Glib::Error const& e)
{
g_message(
"%s",
fmt::format(
_("Couldn't remove '{path}': {error} ({error_code})"),
fmt::arg("path", filename),
fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)),
fmt::arg("error_code", e.code()))
.c_str());
gtr_message(fmt::format(
_("Couldn't remove '{path}': {error} ({error_code})"),
fmt::arg("path", filename),
fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)),
fmt::arg("error_code", e.code())));
tr_error_clear(error);
tr_error_set(error, e.code(), TR_GLIB_EXCEPTION_WHAT(e));
result = false;
@ -469,7 +465,7 @@ void gtr_open_uri(Glib::ustring const& uri)
if (!opened)
{
g_message("%s", fmt::format(_("Couldn't open '{url}'"), fmt::arg("url", uri)).c_str());
gtr_message(fmt::format(_("Couldn't open '{url}'"), fmt::arg("url", uri)));
}
}
}
@ -630,6 +626,20 @@ void gtr_widget_set_visible(Gtk::Widget& w, bool b)
w.set_visible(b);
}
Gtk::Window& gtr_widget_get_window(Gtk::Widget& widget)
{
if (auto* const window = dynamic_cast<Gtk::Window*>(TR_GTK_WIDGET_GET_ROOT(widget)); window != nullptr)
{
return *window;
}
#if defined(G_DISABLE_ASSERT)
throw std::logic_error("Supplied widget doesn't have a window");
#else
g_assert_not_reached();
#endif
}
void gtr_window_set_skip_taskbar_hint([[maybe_unused]] Gtk::Window& window, [[maybe_unused]] bool value)
{
#if GTK_CHECK_VERSION(4, 0, 0)
@ -671,12 +681,10 @@ void gtr_window_raise([[maybe_unused]] Gtk::Window& window)
void gtr_unrecognized_url_dialog(Gtk::Widget& parent, Glib::ustring const& url)
{
auto* window = getWindow(&parent);
Glib::ustring gstr;
auto w = std::make_shared<Gtk::MessageDialog>(
*window,
gtr_widget_get_window(parent),
fmt::format(_("Unsupported URL: '{url}'"), fmt::arg("url", url)),
false /*use markup*/,
TR_GTK_MESSAGE_TYPE(ERROR),

View File

@ -130,6 +130,18 @@ extern char const* const speed_M_str;
extern char const* const speed_G_str;
extern char const* const speed_T_str;
/***
****
***/
void gtr_message(std::string const& message);
void gtr_warning(std::string const& message);
void gtr_error(std::string const& message);
/***
****
***/
enum class GtrUnicode
{
Up,
@ -167,6 +179,8 @@ Glib::ustring gtr_get_help_uri();
/* backwards-compatible wrapper around gtk_widget_set_visible() */
void gtr_widget_set_visible(Gtk::Widget&, bool);
Gtk::Window& gtr_widget_get_window(Gtk::Widget& widget);
void gtr_window_set_skip_taskbar_hint(Gtk::Window& window, bool value);
void gtr_window_set_urgency_hint(Gtk::Window& window, bool value);
void gtr_window_raise(Gtk::Window& window);

View File

@ -55,7 +55,7 @@ int main(int argc, char** argv)
Gio::File::create_for_path(".");
Glib::wrap_register(
g_type_from_name("GLocalFile"),
[](GObject* object) -> Glib::ObjectBase* { return new Gio::File((GFile*)object); });
[](GObject* object) -> Glib::ObjectBase* { return new Gio::File(G_FILE(object)); });
g_type_ensure(Gio::File::get_type());
/* default settings */
@ -93,7 +93,7 @@ int main(int argc, char** argv)
fmt::print(
stderr,
_("Run '{program} --help' to see a full list of available command line options.\n"),
fmt::arg("program", argv[0]));
fmt::arg("program", *argv));
return 1;
}