diff --git a/gtk/Actions.cc b/gtk/Actions.cc index 15a6b81c7..0b3c4d553 100644 --- a/gtk/Actions.cc +++ b/gtk/Actions.cc @@ -6,8 +6,9 @@ * */ +#include #include -#include +#include #include #include @@ -21,158 +22,89 @@ #include "Session.h" #include "Utils.h" +using namespace std::string_view_literals; + namespace { Session* myCore = nullptr; -void action_cb(Glib::RefPtr const& a, void* user_data) +void action_cb(Gio::SimpleAction& action, void* user_data) { - gtr_actions_handler(a->get_name(), user_data); + gtr_actions_handler(action.get_name(), user_data); } -struct ActionEntryBase +void sort_changed_cb(Gio::SimpleAction& action, Glib::VariantBase const& value, void* /*user_data*/) { - char const* name; - char const* stock_id; - char const* label; - char const* accelerator; - char const* tooltip; -}; - -ActionEntryBase sort_radio_entries[] = { - { "sort-by-activity", nullptr, N_("Sort by _Activity"), nullptr, nullptr }, - { "sort-by-name", nullptr, N_("Sort by _Name"), nullptr, nullptr }, - { "sort-by-progress", nullptr, N_("Sort by _Progress"), nullptr, nullptr }, - { "sort-by-queue", nullptr, N_("Sort by _Queue"), nullptr, nullptr }, - { "sort-by-ratio", nullptr, N_("Sort by Rati_o"), nullptr, nullptr }, - { "sort-by-state", nullptr, N_("Sort by Stat_e"), nullptr, nullptr }, - { "sort-by-age", nullptr, N_("Sort by A_ge"), nullptr, nullptr }, - { "sort-by-time-left", nullptr, N_("Sort by Time _Left"), nullptr, nullptr }, - { "sort-by-size", nullptr, N_("Sort by Si_ze"), nullptr, nullptr }, -}; - -void sort_changed_cb(Glib::RefPtr const& action, void* /*user_data*/) -{ - if (!action->get_active()) - { - return; - } - - myCore->set_pref(TR_KEY_sort_mode, action->get_name()); + action.set_state(value); + myCore->set_pref(TR_KEY_sort_mode, Glib::VariantBase::cast_dynamic>(value).get()); } -struct : ActionEntryBase -{ - bool is_active; -} show_toggle_entries[] = { - { "toggle-main-window", nullptr, N_("_Show Transmission"), nullptr, nullptr, true }, - { "toggle-message-log", nullptr, N_("Message _Log"), nullptr, nullptr, false }, +std::array const show_toggle_entries = { + "toggle-main-window"sv, + "toggle-message-log"sv, }; -void toggle_pref_cb(Glib::RefPtr const& action, void* /*user_data*/) +void toggle_pref_cb(Gio::SimpleAction& action, void* /*user_data*/) { - auto const key = action->get_name(); - bool const val = action->get_active(); + auto const key = action.get_name(); + bool val = false; + action.get_state(val); - myCore->set_pref(tr_quark_new({ key.c_str(), key.size() }), val); + action.set_state(Glib::Variant::create(!val)); + + myCore->set_pref(tr_quark_new({ key.c_str(), key.size() }), !val); } -struct : ActionEntryBase -{ - bool is_active; -} pref_toggle_entries[] = { - { "alt-speed-enabled", nullptr, N_("Enable Alternative Speed _Limits"), nullptr, nullptr, false }, - { "compact-view", nullptr, N_("_Compact View"), "C", nullptr, false }, - { "sort-reversed", nullptr, N_("Re_verse Sort Order"), nullptr, nullptr, false }, - { "show-filterbar", nullptr, N_("_Filterbar"), nullptr, nullptr, false }, - { "show-statusbar", nullptr, N_("_Statusbar"), nullptr, nullptr, false }, - { "show-toolbar", nullptr, N_("_Toolbar"), nullptr, nullptr, false }, +std::array const pref_toggle_entries = { + "alt-speed-enabled"sv, // + "compact-view"sv, // + "sort-reversed"sv, // + "show-filterbar"sv, // + "show-statusbar"sv, // + "show-toolbar"sv, // }; -struct : ActionEntryBase -{ - bool is_actionable; -} entries[] = { - { "file-menu", nullptr, N_("_File"), nullptr, nullptr, false }, - { "torrent-menu", nullptr, N_("_Torrent"), nullptr, nullptr, false }, - { "view-menu", nullptr, N_("_View"), nullptr, nullptr, false }, - { "sort-menu", nullptr, N_("_Sort Torrents By"), nullptr, nullptr, false }, - { "queue-menu", nullptr, N_("_Queue"), nullptr, nullptr, false }, - { "edit-menu", nullptr, N_("_Edit"), nullptr, nullptr, false }, - { "help-menu", nullptr, N_("_Help"), nullptr, nullptr, false }, - { "copy-magnet-link-to-clipboard", "edit-copy", N_("Copy _Magnet Link to Clipboard"), "", nullptr, true }, - { "open-torrent-from-url", "document-open", N_("Open _URL…"), "U", N_("Open URL…"), true }, - { "open-torrent-toolbar", "document-open", N_("_Open"), nullptr, N_("Open a torrent"), true }, - { "open-torrent-menu", "document-open", N_("_Open"), nullptr, N_("Open a torrent"), true }, - { "torrent-start", "media-playback-start", N_("_Start"), "S", N_("Start torrent"), true }, - { "torrent-start-now", "media-playback-start", N_("Start _Now"), "S", N_("Start torrent now"), true }, - { "show-stats", nullptr, N_("_Statistics"), nullptr, nullptr, true }, - { "donate", nullptr, N_("_Donate"), nullptr, nullptr, true }, - { "torrent-verify", nullptr, N_("_Verify Local Data"), "V", nullptr, true }, - { "torrent-stop", "media-playback-pause", N_("_Pause"), "P", N_("Pause torrent"), true }, - { "pause-all-torrents", "media-playback-pause", N_("_Pause All"), nullptr, N_("Pause all torrents"), true }, - { "start-all-torrents", "media-playback-start", N_("_Start All"), nullptr, N_("Start all torrents"), true }, - { "relocate-torrent", nullptr, N_("Set _Location…"), nullptr, nullptr, true }, - { "remove-torrent", "list-remove", N_("Remove torrent"), "Delete", nullptr, true }, - { "delete-torrent", "edit-delete", N_("_Delete Files and Remove"), "Delete", nullptr, true }, - { "new-torrent", "document-new", N_("_New…"), nullptr, N_("Create a torrent"), true }, - { "quit", "application-exit", N_("_Quit"), nullptr, nullptr, true }, - { "select-all", "edit-select-all", N_("Select _All"), "A", nullptr, true }, - { "deselect-all", nullptr, N_("Dese_lect All"), "A", nullptr, true }, - { "edit-preferences", "preferences-system", N_("_Preferences"), nullptr, nullptr, true }, - { "show-torrent-properties", "document-properties", N_("_Properties"), "Return", N_("Torrent properties"), true }, - { "open-torrent-folder", "document-open", N_("Open Fold_er"), "E", nullptr, true }, - { "show-about-dialog", "help-about", N_("_About"), nullptr, nullptr, true }, - { "help", "help-browser", N_("_Contents"), "F1", nullptr, true }, - { "torrent-reannounce", "network-workgroup", N_("Ask Tracker for _More Peers"), nullptr, nullptr, true }, - { "queue-move-top", "go-top", N_("Move to _Top"), nullptr, nullptr, true }, - { "queue-move-up", "go-up", N_("Move _Up"), "Up", nullptr, true }, - { "queue-move-down", "go-down", N_("Move _Down"), "Down", nullptr, true }, - { "queue-move-bottom", "go-bottom", N_("Move to _Bottom"), nullptr, nullptr, true }, - { "present-main-window", nullptr, N_("Present Main Window"), nullptr, nullptr, true }, -}; - -struct BuiltinIconInfo -{ - char const* filename; - char const* name; -}; - -BuiltinIconInfo const my_fallback_icons[] = { - { "logo-48", WINDOW_ICON }, // - { "logo-24", TRAY_ICON }, // - { "logo-48", NOTIFICATION_ICON }, // - { "lock", "transmission-lock" }, // - { "utilities", "utilities" }, // - { "turtle-blue", "alt-speed-on" }, // - { "turtle-grey", "alt-speed-off" }, // - { "ratio", "ratio" }, // +std::array const entries = { + "copy-magnet-link-to-clipboard"sv, + "open-torrent-from-url"sv, + "open-torrent"sv, + "torrent-start"sv, + "torrent-start-now"sv, + "show-stats"sv, + "donate"sv, + "torrent-verify"sv, + "torrent-stop"sv, + "pause-all-torrents"sv, + "start-all-torrents"sv, + "relocate-torrent"sv, + "remove-torrent"sv, + "delete-torrent"sv, + "new-torrent"sv, + "quit"sv, + "select-all"sv, + "deselect-all"sv, + "edit-preferences"sv, + "show-torrent-properties"sv, + "open-torrent-folder"sv, + "show-about-dialog"sv, + "help"sv, + "torrent-reannounce"sv, + "queue-move-top"sv, + "queue-move-up"sv, + "queue-move-down"sv, + "queue-move-bottom"sv, + "present-main-window"sv, }; void register_my_icons() { - auto const theme = Gtk::IconTheme::get_default(); - auto const factory = Gtk::IconFactory::create(); - - factory->add_default(); - - for (auto const& icon : my_fallback_icons) - { - if (!theme->has_icon(icon.name)) - { - auto const p = Gdk::Pixbuf::create_from_resource(gtr_sprintf(TR_RESOURCE_PATH "icons/%s.png", icon.filename)); - - if (p != nullptr) - { - Gtk::IconTheme::add_builtin_icon(icon.name, p->get_width(), p); - factory->add(Gtk::StockID(icon.name), Gtk::IconSet::create(p)); - } - } - } + Gtk::IconTheme::get_default()->add_resource_path(TR_RESOURCE_PATH "icons"); } -Gtk::UIManager* myUIManager = nullptr; +Gtk::Builder* myBuilder = nullptr; + +std::unordered_map> key_to_action; } // namespace @@ -181,80 +113,56 @@ void gtr_actions_set_core(Glib::RefPtr const& core) myCore = gtr_get_ptr(core); } -void gtr_actions_init(Glib::RefPtr const& ui_manager, void* callback_user_data) +Glib::RefPtr gtr_actions_init(Glib::RefPtr const& builder, void* callback_user_data) { - myUIManager = gtr_get_ptr(ui_manager); + myBuilder = gtr_get_ptr(builder); register_my_icons(); - auto const action_group = Gtk::ActionGroup::create("Actions"); + auto const action_group = Gio::SimpleActionGroup::create(); auto const match = gtr_pref_string_get(TR_KEY_sort_mode); - Gtk::RadioAction::Group sort_group; - for (auto const& entry : sort_radio_entries) { - auto const action = Gtk::RadioAction::create(sort_group, entry.name, _(entry.label)); - - if (entry.name == match) - { - action->set_active(true); - } - - action_group->add(action, [action, callback_user_data]() { sort_changed_cb(action, callback_user_data); }); + auto const action_name = Glib::ustring("sort-torrents"); + auto const action = Gio::SimpleAction::create_radio_string(action_name, match); + action->signal_activate().connect([a = gtr_get_ptr(action), callback_user_data](auto const& value) + { sort_changed_cb(*a, value, callback_user_data); }); + action_group->add_action(action); + key_to_action.emplace(action_name, action); } - for (auto const& entry : show_toggle_entries) + for (auto const& action_name_view : show_toggle_entries) { - auto const action = Gtk::ToggleAction::create(entry.name, _(entry.label), {}, entry.is_active); - action_group->add(action, [action, callback_user_data]() { action_cb(action, callback_user_data); }); + auto const action_name = Glib::ustring(std::string(action_name_view)); + auto const action = Gio::SimpleAction::create_bool(action_name); + action->signal_activate().connect([a = gtr_get_ptr(action), callback_user_data](auto const& /*value*/) + { action_cb(*a, callback_user_data); }); + action_group->add_action(action); + key_to_action.emplace(action_name, action); } - for (auto& entry : pref_toggle_entries) + for (auto const& action_name_view : pref_toggle_entries) { - entry.is_active = gtr_pref_flag_get(tr_quark_new(entry.name)); + auto const action_name = Glib::ustring(std::string(action_name_view)); + auto const action = Gio::SimpleAction::create_bool(action_name, gtr_pref_flag_get(tr_quark_new(action_name_view))); + action->signal_activate().connect([a = gtr_get_ptr(action), callback_user_data](auto const& /*value*/) + { toggle_pref_cb(*a, callback_user_data); }); + action_group->add_action(action); + key_to_action.emplace(action_name, action); } - for (auto const& entry : pref_toggle_entries) + for (auto const& action_name_view : entries) { - auto const action = Gtk::ToggleAction::create(entry.name, _(entry.label), {}, entry.is_active); - action->signal_activate().connect([action, callback_user_data]() { toggle_pref_cb(action, callback_user_data); }); - if (entry.accelerator != nullptr) - { - action_group->add(action, Gtk::AccelKey(entry.accelerator)); - } - else - { - action_group->add(action); - } + auto const action_name = Glib::ustring(std::string(action_name_view)); + auto const action = Gio::SimpleAction::create(action_name); + action->signal_activate().connect([a = gtr_get_ptr(action), callback_user_data](auto const& /*value*/) + { action_cb(*a, callback_user_data); }); + action_group->add_action(action); + key_to_action.emplace(action_name, action); } - for (auto const& entry : entries) - { - auto const action = Gtk::Action::create( - entry.name, - entry.stock_id != nullptr ? Gtk::StockID(entry.stock_id) : Gtk::StockID(), - _(entry.label), - entry.tooltip != nullptr ? _(entry.tooltip) : Glib::ustring()); - if (entry.stock_id != nullptr && Gtk::IconTheme::get_default()->has_icon(entry.stock_id)) - { - action->set_icon_name(entry.stock_id); - } - if (entry.is_actionable) - { - action->signal_activate().connect([action, callback_user_data]() { action_cb(action, callback_user_data); }); - } - if (entry.accelerator != nullptr) - { - action_group->add(action, Gtk::AccelKey(entry.accelerator)); - } - else - { - action_group->add(action); - } - } - - ui_manager->insert_action_group(action_group, 0); + return action_group; } /**** @@ -264,27 +172,8 @@ void gtr_actions_init(Glib::RefPtr const& ui_manager, void* call namespace { -std::unordered_map> key_to_action; - -void ensure_action_map_loaded(Gtk::UIManager& uim) +Glib::RefPtr get_action(Glib::ustring const& name) { - if (!key_to_action.empty()) - { - return; - } - - for (auto const& action_group : uim.get_action_groups()) - { - for (auto const& action : action_group->get_actions()) - { - key_to_action.emplace(action->get_name(), action); - } - } -} - -Glib::RefPtr get_action(Glib::ustring const& name) -{ - ensure_action_map_loaded(*myUIManager); return key_to_action.at(name); } @@ -297,20 +186,22 @@ void gtr_action_activate(Glib::ustring const& name) void gtr_action_set_sensitive(Glib::ustring const& name, bool b) { - get_action(name)->set_sensitive(b); -} - -void gtr_action_set_important(Glib::ustring const& name, bool b) -{ - get_action(name)->set_is_important(b); + get_action(name)->set_enabled(b); } void gtr_action_set_toggled(Glib::ustring const& name, bool b) { - dynamic_cast(gtr_get_ptr(get_action(name)))->set_active(b); + get_action(name)->set_state(Glib::Variant::create(b)); } -Gtk::Widget* gtr_action_get_widget(Glib::ustring const& path) +Gtk::Widget* gtr_action_get_widget(Glib::ustring const& name) { - return myUIManager->get_widget(path); + Gtk::Widget* widget; + myBuilder->get_widget(name, widget); + return widget; +} + +Glib::RefPtr gtr_action_get_object(Glib::ustring const& name) +{ + return myBuilder->get_object(name); } diff --git a/gtk/Actions.h b/gtk/Actions.h index b347df1ce..cc99b3a0a 100644 --- a/gtk/Actions.h +++ b/gtk/Actions.h @@ -10,24 +10,32 @@ #include +#include "Utils.h" + class Session; #define WINDOW_ICON "transmission-main-window-icon" #define TRAY_ICON "transmission-tray-icon" #define NOTIFICATION_ICON "transmission-notification-icon" -void gtr_actions_init(Glib::RefPtr const& ui_manager, void* callback_user_data); +Glib::RefPtr gtr_actions_init(Glib::RefPtr const& builder, void* callback_user_data); void gtr_actions_set_core(Glib::RefPtr const& core); void gtr_actions_handler(Glib::ustring const& action_name, void* user_data); void gtr_action_activate(Glib::ustring const& action_name); void gtr_action_set_sensitive(Glib::ustring const& action_name, bool is_sensitive); void gtr_action_set_toggled(Glib::ustring const& action_name, bool is_toggled); -void gtr_action_set_important(Glib::ustring const& action_name, bool is_important); -Gtk::Widget* gtr_action_get_widget(Glib::ustring const& path); +Gtk::Widget* gtr_action_get_widget(Glib::ustring const& name); +Glib::RefPtr gtr_action_get_object(Glib::ustring const& name); template -inline T* gtr_action_get_widget(Glib::ustring const& path) +inline T* gtr_action_get_widget(Glib::ustring const& name) { - return static_cast(gtr_action_get_widget(path)); + return static_cast(gtr_action_get_widget(name)); +} + +template +inline Glib::RefPtr gtr_action_get_object(Glib::ustring const& name) +{ + return gtr_ptr_static_cast(gtr_action_get_object(name)); } diff --git a/gtk/Application.cc b/gtk/Application.cc index 1ac590df7..60f6b42f0 100644 --- a/gtk/Application.cc +++ b/gtk/Application.cc @@ -28,6 +28,7 @@ #include #include /* exit() */ #include +#include #include #include #include @@ -171,7 +172,7 @@ private: bool is_iconified_ = false; bool is_closing_ = false; - Glib::RefPtr ui_manager_; + Glib::RefPtr ui_builder_; unsigned int activation_count_ = 0; sigc::connection timer_; @@ -328,7 +329,7 @@ void Application::Impl::refresh_actions_soon() { if (!is_closing_ && !refresh_actions_tag_.connected()) { - refresh_actions_tag_ = Glib::signal_idle().connect(sigc::mem_fun(this, &Impl::refresh_actions)); + refresh_actions_tag_ = Glib::signal_idle().connect(sigc::mem_fun(*this, &Impl::refresh_actions)); } } @@ -560,14 +561,14 @@ void Application::Impl::on_startup() core_ = Session::create(session); /* init the ui manager */ - ui_manager_ = Gtk::UIManager::create(); - gtr_actions_init(ui_manager_, this); - ui_manager_->add_ui_from_resource(TR_RESOURCE_PATH "transmission-ui.xml"); - ui_manager_->ensure_update(); + ui_builder_ = Gtk::Builder::create_from_resource(TR_RESOURCE_PATH "transmission-ui.xml"); + auto const actions = gtr_actions_init(ui_builder_, this); + + app_.set_menubar(gtr_action_get_object("main-window-menu")); /* create main window now to be a parent to any error dialogs */ - wind_ = MainWindow::create(app_, ui_manager_, core_); - wind_->signal_size_allocate().connect(sigc::mem_fun(this, &Impl::on_main_window_size_allocated)); + wind_ = MainWindow::create(app_, actions, core_); + wind_->signal_size_allocate().connect(sigc::mem_fun(*this, &Impl::on_main_window_size_allocated)); app_.hold(); app_setup(); tr_sessionSetRPCCallback(session, &Impl::on_rpc_changed, this); @@ -674,10 +675,10 @@ void Application::Impl::app_setup() gtr_actions_set_core(core_); /* set up core handlers */ - core_->signal_busy().connect(sigc::mem_fun(this, &Impl::on_core_busy)); - core_->signal_add_error().connect(sigc::mem_fun(this, &Impl::on_core_error)); - core_->signal_add_prompt().connect(sigc::mem_fun(this, &Impl::on_add_torrent)); - core_->signal_prefs_changed().connect(sigc::mem_fun(this, &Impl::on_prefs_changed)); + core_->signal_busy().connect(sigc::mem_fun(*this, &Impl::on_core_busy)); + core_->signal_add_error().connect(sigc::mem_fun(*this, &Impl::on_core_error)); + core_->signal_add_prompt().connect(sigc::mem_fun(*this, &Impl::on_add_torrent)); + core_->signal_prefs_changed().connect(sigc::mem_fun(*this, &Impl::on_prefs_changed)); /* add torrents from command-line and saved state */ core_->load(start_paused_); @@ -691,7 +692,7 @@ void Application::Impl::app_setup() /* start model update timer */ timer_ = Glib::signal_timeout().connect_seconds( - sigc::mem_fun(this, &Impl::update_model_loop), + sigc::mem_fun(*this, &Impl::update_model_loop), MAIN_WINDOW_REFRESH_INTERVAL_SECONDS); update_model_once(); @@ -699,6 +700,7 @@ void Application::Impl::app_setup() if (!is_iconified_) { wind_->show(); + gtr_action_set_toggled("toggle-main-window", true); } else { @@ -742,6 +744,8 @@ void Application::Impl::placeWindowFromPrefs() void Application::Impl::presentMainWindow() { + gtr_action_set_toggled("toggle-main-window", true); + if (is_iconified_) { is_iconified_ = false; @@ -761,6 +765,8 @@ void Application::Impl::presentMainWindow() void Application::Impl::hideMainWindow() { + gtr_action_set_toggled("toggle-main-window", false); + wind_->set_skip_taskbar_hint(true); gtr_widget_set_visible(*wind_, false); is_iconified_ = true; @@ -825,17 +831,17 @@ void Application::Impl::main_window_setup() // cbdata->wind = wind; sel_ = wind_->get_selection(); - sel_->signal_changed().connect(sigc::mem_fun(this, &Impl::refresh_actions_soon)); + sel_->signal_changed().connect(sigc::mem_fun(*this, &Impl::refresh_actions_soon)); refresh_actions_soon(); auto const model = core_->get_model(); - model->signal_row_changed().connect(sigc::mem_fun(this, &Impl::rowChangedCB)); - wind_->signal_delete_event().connect(sigc::mem_fun(this, &Impl::winclose)); + model->signal_row_changed().connect(sigc::mem_fun(*this, &Impl::rowChangedCB)); + wind_->signal_delete_event().connect(sigc::mem_fun(*this, &Impl::winclose)); refresh_actions(); /* register to handle URIs that get dragged onto our main window */ wind_->drag_dest_set(Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_COPY); wind_->drag_dest_add_uri_targets(); - wind_->signal_drag_data_received().connect(sigc::mem_fun(this, &Impl::on_drag_data_received)); + wind_->signal_drag_data_received().connect(sigc::mem_fun(*this, &Impl::on_drag_data_received)); } bool Application::Impl::on_session_closed() @@ -916,12 +922,13 @@ void Application::Impl::on_app_exit() /* since tr_sessionClose () is a blocking function, * delegate its call to another thread here... when it's done, * punt the GUI teardown back to the GTK+ thread */ - Glib::Thread::create( + std::thread( [this, session = core_->close()]() { tr_sessionClose(session); - Glib::signal_idle().connect(sigc::mem_fun(this, &Impl::on_session_closed)); - }); + Glib::signal_idle().connect(sigc::mem_fun(*this, &Impl::on_session_closed)); + }) + .detach(); } void Application::Impl::show_torrent_errors(Glib::ustring const& primary, std::vector& files) @@ -996,7 +1003,7 @@ void Application::Impl::on_add_torrent(tr_ctor* ctor) OptionsDialog::create(*wind_, core_, std::unique_ptr(ctor, &tr_ctorFree))); w->signal_hide().connect([w]() mutable { w.reset(); }); - w->signal_focus_in_event().connect(sigc::mem_fun(this, &Impl::on_main_window_focus_in)); + w->signal_focus_in_event().connect(sigc::mem_fun(*this, &Impl::on_main_window_focus_in)); if (wind_ != nullptr) { @@ -1042,7 +1049,7 @@ void Application::Impl::on_prefs_changed(tr_quark const key) if (show && icon_ == nullptr) { - icon_ = std::make_unique(core_); + icon_ = std::make_unique(*wind_, core_); } else if (!show && icon_ != nullptr) { @@ -1237,7 +1244,7 @@ void Application::Impl::update_model_soon() { if (!update_model_soon_tag_.connected()) { - update_model_soon_tag_ = Glib::signal_idle().connect(sigc::mem_fun(this, &Impl::update_model_once)); + update_model_soon_tag_ = Glib::signal_idle().connect(sigc::mem_fun(*this, &Impl::update_model_once)); } } @@ -1405,7 +1412,7 @@ void Application::Impl::actions_handler(Glib::ustring const& action_name) w->signal_hide().connect([w]() mutable { w.reset(); }); w->show(); } - else if (action_name == "open-torrent-menu" || action_name == "open-torrent-toolbar") + else if (action_name == "open-torrent") { auto w = std::shared_ptr(TorrentFileChooserDialog::create(*wind_, core_)); w->signal_hide().connect([w]() mutable { w.reset(); }); @@ -1505,8 +1512,9 @@ void Application::Impl::actions_handler(Glib::ustring const& action_name) { if (msgwin_ == nullptr) { + gtr_action_set_toggled("toggle-message-log", true); msgwin_ = MessageLogWindow::create(*wind_, core_); - msgwin_->signal_hide().connect(sigc::mem_fun(this, &Impl::on_message_window_closed)); + msgwin_->signal_hide().connect(sigc::mem_fun(*this, &Impl::on_message_window_closed)); } else { diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt index 38aa9543d..34203e596 100644 --- a/gtk/CMakeLists.txt +++ b/gtk/CMakeLists.txt @@ -144,12 +144,17 @@ add_definitions( -DG_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED - # FIXME: migrate from GtkUIManager to GtkBuilder in 2.90 - # -DGTK_DISABLE_DEPRECATED + -DGTK_DISABLE_DEPRECATED -DPANGO_DISABLE_DEPRECATED # FIXME: these break libnotify's headers # -DG_DISABLE_SINGLE_INCLUDES # -DGTK_DISABLE_SINGLE_INCLUDES + -DGDKMM_DISABLE_DEPRECATED + -DGIOMM_DISABLE_DEPRECATED + -DGLIBMM_DISABLE_DEPRECATED + -DGTKMM_DISABLE_DEPRECATED + -DPANGOMM_DISABLE_DEPRECATED + -DSIGCXX_DISABLE_DEPRECATED ${GTK_CFLAGS_OTHER} ) diff --git a/gtk/DetailsDialog.cc b/gtk/DetailsDialog.cc index 086f01c37..478fdf599 100644 --- a/gtk/DetailsDialog.cc +++ b/gtk/DetailsDialog.cc @@ -1238,7 +1238,7 @@ void initPeerRow(Gtk::TreeIter const& iter, std::string const& key, std::string (*iter)[peer_cols.address] = peer->addr; (*iter)[peer_cols.address_collated] = collated_name; (*iter)[peer_cols.client] = client; - (*iter)[peer_cols.encryption_stock_id] = peer->isEncrypted ? "transmission-lock" : ""; + (*iter)[peer_cols.encryption_stock_id] = peer->isEncrypted ? "lock" : ""; (*iter)[peer_cols.key] = key; (*iter)[peer_cols.torrent_name] = torrentName; } @@ -1653,7 +1653,7 @@ void setPeerViewColumns(Gtk::TreeView* peer_view) r->property_xalign() = 0.0F; r->property_yalign() = 0.5F; c = Gtk::make_managed(Glib::ustring(), *r); - c->add_attribute(r->property_stock_id(), *col); + c->add_attribute(r->property_icon_name(), *col); c->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED); c->set_fixed_width(20); } @@ -1794,10 +1794,9 @@ Gtk::Widget* DetailsDialog::Impl::peer_page_new() auto m = Gtk::TreeModelSort::create(peer_store_); m->set_sort_column(peer_cols.progress, Gtk::SORT_DESCENDING); peer_view_ = Gtk::make_managed(m); - peer_view_->set_rules_hint(true); peer_view_->set_has_tooltip(true); - peer_view_->signal_query_tooltip().connect(sigc::mem_fun(this, &Impl::onPeerViewQueryTooltip)); + peer_view_->signal_query_tooltip().connect(sigc::mem_fun(*this, &Impl::onPeerViewQueryTooltip)); peer_view_->signal_button_release_event().connect([this](GdkEventButton* event) { return on_tree_view_button_released(peer_view_, event); }); @@ -1818,7 +1817,7 @@ Gtk::Widget* DetailsDialog::Impl::peer_page_new() more_peer_details_check_ = Gtk::make_managed(_("Show _more details"), true); more_peer_details_check_->set_active(gtr_pref_flag_get(TR_KEY_show_extra_peer_details)); - more_peer_details_check_->signal_toggled().connect(sigc::mem_fun(this, &Impl::onMorePeerInfoToggled)); + more_peer_details_check_->signal_toggled().connect(sigc::mem_fun(*this, &Impl::onMorePeerInfoToggled)); vbox->pack_start(*more_peer_details_check_, false, false); return vbox; @@ -2461,7 +2460,7 @@ Gtk::Widget* DetailsDialog::Impl::tracker_page_new() tracker_store_ = Gtk::ListStore::create(tracker_cols); trackers_filtered_ = Gtk::TreeModelFilter::create(tracker_store_); - trackers_filtered_->set_visible_func(sigc::mem_fun(this, &Impl::trackerVisibleFunc)); + trackers_filtered_->set_visible_func(sigc::mem_fun(*this, &Impl::trackerVisibleFunc)); auto* hbox = Gtk::make_managed(Gtk::ORIENTATION_HORIZONTAL, GUI_PAD_BIG); @@ -2473,7 +2472,7 @@ Gtk::Widget* DetailsDialog::Impl::tracker_page_new() { return on_tree_view_button_released(tracker_view_, event); }); auto sel = tracker_view_->get_selection(); - sel->signal_changed().connect(sigc::mem_fun(this, &Impl::on_tracker_list_selection_changed)); + sel->signal_changed().connect(sigc::mem_fun(*this, &Impl::on_tracker_list_selection_changed)); auto* c = Gtk::make_managed(); c->set_title(_("Trackers")); @@ -2510,15 +2509,15 @@ Gtk::Widget* DetailsDialog::Impl::tracker_page_new() auto* v = Gtk::make_managed(Gtk::ORIENTATION_VERTICAL, GUI_PAD); add_tracker_button_ = Gtk::make_managed(_("_Add"), true); - add_tracker_button_->signal_clicked().connect(sigc::mem_fun(this, &Impl::on_tracker_list_add_button_clicked)); + add_tracker_button_->signal_clicked().connect(sigc::mem_fun(*this, &Impl::on_tracker_list_add_button_clicked)); v->pack_start(*add_tracker_button_, false, false); edit_trackers_button_ = Gtk::make_managed(_("_Edit"), true); - edit_trackers_button_->signal_clicked().connect(sigc::mem_fun(this, &Impl::on_edit_trackers)); + edit_trackers_button_->signal_clicked().connect(sigc::mem_fun(*this, &Impl::on_edit_trackers)); v->pack_start(*edit_trackers_button_, false, false); remove_tracker_button_ = Gtk::make_managed(_("_Remove"), true); - remove_tracker_button_->signal_clicked().connect(sigc::mem_fun(this, &Impl::on_tracker_list_remove_button_clicked)); + remove_tracker_button_->signal_clicked().connect(sigc::mem_fun(*this, &Impl::on_tracker_list_remove_button_clicked)); v->pack_start(*remove_tracker_button_, false, false); hbox->pack_start(*v, false, false); @@ -2527,12 +2526,12 @@ Gtk::Widget* DetailsDialog::Impl::tracker_page_new() scrape_check_ = Gtk::make_managed(_("Show _more details"), true); scrape_check_->set_active(gtr_pref_flag_get(TR_KEY_show_tracker_scrapes)); - scrape_check_->signal_toggled().connect(sigc::mem_fun(this, &Impl::onScrapeToggled)); + scrape_check_->signal_toggled().connect(sigc::mem_fun(*this, &Impl::onScrapeToggled)); vbox->pack_start(*scrape_check_, false, false); all_check_ = Gtk::make_managed(_("Show _backup trackers"), true); all_check_->set_active(gtr_pref_flag_get(TR_KEY_show_backup_trackers)); - all_check_->signal_toggled().connect(sigc::mem_fun(this, &Impl::onBackupToggled)); + all_check_->signal_toggled().connect(sigc::mem_fun(*this, &Impl::onBackupToggled)); vbox->pack_start(*all_check_, false, false); return vbox; @@ -2594,7 +2593,7 @@ DetailsDialog::Impl::Impl(DetailsDialog& dialog, Glib::RefPtr const& co /* return saved window size */ dialog_.resize((int)gtr_pref_int_get(TR_KEY_details_window_width), (int)gtr_pref_int_get(TR_KEY_details_window_height)); - dialog_.signal_size_allocate().connect(sigc::mem_fun(this, &Impl::on_details_window_size_allocated)); + dialog_.signal_size_allocate().connect(sigc::mem_fun(*this, &Impl::on_details_window_size_allocated)); dialog_.signal_response().connect(sigc::hide<0>(sigc::mem_fun(dialog_, &DetailsDialog::hide))); dialog_.set_border_width(GUI_PAD); diff --git a/gtk/FileList.cc b/gtk/FileList.cc index 2acd6ac00..a861b155e 100644 --- a/gtk/FileList.cc +++ b/gtk/FileList.cc @@ -828,8 +828,8 @@ FileList::Impl::Impl(FileList& widget, Glib::RefPtr const& core, int to /* create the view */ view_ = Gtk::make_managed(); view_->set_border_width(GUI_PAD_BIG); - view_->signal_button_press_event().connect(sigc::mem_fun(this, &Impl::onViewButtonPressed), false); - view_->signal_row_activated().connect(sigc::mem_fun(this, &Impl::onRowActivated)); + view_->signal_button_press_event().connect(sigc::mem_fun(*this, &Impl::onViewButtonPressed), false); + view_->signal_row_activated().connect(sigc::mem_fun(*this, &Impl::onRowActivated)); view_->signal_button_release_event().connect([this](GdkEventButton* event) { return on_tree_view_button_released(view_, event); }); @@ -856,7 +856,7 @@ FileList::Impl::Impl(FileList& widget, Glib::RefPtr const& core, int to text_rend->property_editable() = true; text_rend->property_ellipsize() = Pango::ELLIPSIZE_END; text_rend->property_font_desc() = pango_font_description; - text_rend->signal_edited().connect(sigc::mem_fun(this, &Impl::cell_edited_callback)); + text_rend->signal_edited().connect(sigc::mem_fun(*this, &Impl::cell_edited_callback)); col->pack_start(*text_rend, true); col->add_attribute(text_rend->property_text(), file_cols.label); col->set_sort_column(file_cols.label); diff --git a/gtk/FilterBar.cc b/gtk/FilterBar.cc index 4f3e82c4a..f9d785c0a 100644 --- a/gtk/FilterBar.cc +++ b/gtk/FilterBar.cc @@ -737,7 +737,7 @@ void FilterBar::Impl::update_count_label_idle() if (!pending) { show_lb_->set_data(DIRTY_KEY, GINT_TO_POINTER(1)); - Glib::signal_idle().connect(sigc::mem_fun(this, &Impl::update_count_label)); + Glib::signal_idle().connect(sigc::mem_fun(*this, &Impl::update_count_label)); } } @@ -765,10 +765,10 @@ FilterBar::Impl::Impl(FilterBar& widget, tr_session* session, Glib::RefPtrproperty_width_request() = 170; static_cast(gtr_get_ptr(tracker_->get_model()))->set_data(SESSION_KEY, session); - filter_model_->set_visible_func(sigc::mem_fun(this, &Impl::is_row_visible)); + filter_model_->set_visible_func(sigc::mem_fun(*this, &Impl::is_row_visible)); - tracker_->signal_changed().connect(sigc::mem_fun(this, &Impl::selection_changed_cb)); - activity_->signal_changed().connect(sigc::mem_fun(this, &Impl::selection_changed_cb)); + tracker_->signal_changed().connect(sigc::mem_fun(*this, &Impl::selection_changed_cb)); + activity_->signal_changed().connect(sigc::mem_fun(*this, &Impl::selection_changed_cb)); /* add the activity combobox */ show_lb_->set_mnemonic_widget(*activity_); @@ -786,7 +786,7 @@ FilterBar::Impl::Impl(FilterBar& widget, tr_session* session, Glib::RefPtrsignal_icon_release().connect([this](auto /*icon_position*/, auto const* /*event*/) { entry_->set_text({}); }); widget_.pack_start(*entry_, true, true, 0); - entry_->signal_changed().connect(sigc::mem_fun(this, &Impl::filter_entry_changed)); + entry_->signal_changed().connect(sigc::mem_fun(*this, &Impl::filter_entry_changed)); selection_changed_cb(); update_count_label(); diff --git a/gtk/FreeSpaceLabel.cc b/gtk/FreeSpaceLabel.cc index a5261958d..a131e8d71 100644 --- a/gtk/FreeSpaceLabel.cc +++ b/gtk/FreeSpaceLabel.cc @@ -64,7 +64,7 @@ FreeSpaceLabel::Impl::Impl(FreeSpaceLabel& label, Glib::RefPtr const& c , core_(core) , dir_(dir) { - timer_id_ = Glib::signal_timeout().connect_seconds(sigc::mem_fun(this, &Impl::on_freespace_timer), 3); + timer_id_ = Glib::signal_timeout().connect_seconds(sigc::mem_fun(*this, &Impl::on_freespace_timer), 3); on_freespace_timer(); } diff --git a/gtk/IconCache.cc b/gtk/IconCache.cc index f2725462e..affa4bec1 100644 --- a/gtk/IconCache.cc +++ b/gtk/IconCache.cc @@ -80,7 +80,7 @@ Glib::RefPtr get_themed_icon_pixbuf(Gio::ThemedIcon& icon, int size auto icon_info = icon_theme.choose_icon(icon_names, size); - if (icon_info == nullptr) + if (!bool{ icon_info }) { icon_info = icon_theme.lookup_icon("text-x-generic", size, Gtk::ICON_LOOKUP_USE_BUILTIN); } diff --git a/gtk/MainWindow.cc b/gtk/MainWindow.cc index f5af86061..7665a2a06 100644 --- a/gtk/MainWindow.cc +++ b/gtk/MainWindow.cc @@ -40,7 +40,7 @@ class MainWindow::Impl { public: - Impl(MainWindow& window, Glib::RefPtr const& ui_mgr, Glib::RefPtr const& core); + Impl(MainWindow& window, Glib::RefPtr const& actions, Glib::RefPtr const& core); ~Impl(); Glib::RefPtr get_selection() const; @@ -56,6 +56,8 @@ private: Gtk::Menu* createSpeedMenu(tr_direction dir); Gtk::Menu* createRatioMenu(); + void on_popup_menu(GdkEventButton* event); + void onSpeedToggled(Gtk::CheckMenuItem* check, tr_direction dir, bool enabled); void onSpeedSet(tr_direction dir, int KBps); @@ -67,7 +69,6 @@ private: void syncAltSpeedButton(); - bool onAskTrackerQueryTooltip(int x, int y, bool keyboard_tip, Glib::RefPtr tooltip); void status_menu_toggled_cb(Gtk::CheckMenuItem* menu_item, std::string const& val); void onOptionsClicked(Gtk::Button* button); void onYinYangClicked(Gtk::Button* button); @@ -75,6 +76,8 @@ private: void onAltSpeedToggledIdle(); private: + MainWindow& window_; + Gtk::RadioMenuItem* speedlimit_on_item_[2] = { nullptr, nullptr }; Gtk::RadioMenuItem* speedlimit_off_item_[2] = { nullptr, nullptr }; Gtk::RadioMenuItem* ratio_on_item_ = nullptr; @@ -96,21 +99,27 @@ private: Gtk::TreeViewColumn* column_ = nullptr; Glib::RefPtr const core_; sigc::connection pref_handler_id_; + Gtk::Menu* popup_menu_; }; /*** **** ***/ +void MainWindow::Impl::on_popup_menu(GdkEventButton* event) +{ + if (popup_menu_ == nullptr) + { + popup_menu_ = Gtk::make_managed(gtr_action_get_object("main-window-popup")); + popup_menu_->attach_to_widget(window_); + } + + popup_menu_->popup_at_pointer(reinterpret_cast(event)); +} + namespace { -void on_popup_menu(GdkEventButton* event) -{ - auto* menu = gtr_action_get_widget("/main-window-popup"); - menu->popup_at_pointer(reinterpret_cast(event)); -} - bool tree_view_search_equal_func( Glib::RefPtr const& /*model*/, int /*column*/, @@ -150,9 +159,10 @@ Gtk::TreeView* MainWindow::Impl::makeview(Glib::RefPtr const& mo selection_->set_mode(Gtk::SELECTION_MULTIPLE); - view->signal_popup_menu().connect_notify([]() { on_popup_menu(nullptr); }); + view->signal_popup_menu().connect_notify([this]() { on_popup_menu(nullptr); }); view->signal_button_press_event().connect( - [view](GdkEventButton* event) { return on_tree_view_button_pressed(view, event, &on_popup_menu); }, + [this, view](GdkEventButton* event) + { return on_tree_view_button_pressed(view, event, sigc::mem_fun(*this, &Impl::on_popup_menu)); }, false); view->signal_button_release_event().connect([view](GdkEventButton* event) { return on_tree_view_button_released(view, event); }); @@ -235,7 +245,7 @@ void MainWindow::Impl::syncAltSpeedButton() gtr_sprintf(_("Click to enable Alternative Speed Limits\n (%1$s down, %2$s up)"), d, u); alt_speed_button_->set_active(b); - alt_speed_image_->set(Gtk::StockID(stock), Gtk::IconSize(-1)); + alt_speed_image_->set_from_icon_name(stock, Gtk::BuiltinIconSize::ICON_SIZE_MENU); alt_speed_button_->set_halign(Gtk::ALIGN_CENTER); alt_speed_button_->set_valign(Gtk::ALIGN_CENTER); alt_speed_button_->set_tooltip_text(str); @@ -250,35 +260,6 @@ void MainWindow::Impl::alt_speed_toggled_cb() **** FILTER ***/ -bool MainWindow::Impl::onAskTrackerQueryTooltip(int /*x*/, int /*y*/, bool /*keyboard_tip*/, Glib::RefPtr tooltip) -{ - bool handled; - time_t maxTime = 0; - time_t const now = time(nullptr); - - selection_->selected_foreach( - [&maxTime](auto const& /*path*/, auto const& iter) - { - auto* tor = static_cast(iter->get_value(torrent_cols.torrent)); - auto const* torStat = tr_torrentStatCached(tor); - maxTime = std::max(maxTime, torStat->manualAnnounceTime); - }); - - if (maxTime <= now) - { - handled = false; - } - else - { - time_t const seconds = maxTime - now; - - tooltip->set_text(gtr_sprintf(_("Tracker will allow requests in %s"), tr_strltime(seconds))); - handled = true; - } - - return handled; -} - void MainWindow::Impl::onAltSpeedToggledIdle() { core_->set_pref(TR_KEY_alt_speed_enabled, tr_sessionUsesAltSpeed(core_->get_session())); @@ -435,23 +416,24 @@ void MainWindow::Impl::onOptionsClicked(Gtk::Button* button) std::unique_ptr MainWindow::create( Gtk::Application& app, - Glib::RefPtr const& uim, + Glib::RefPtr const& actions, Glib::RefPtr const& core) { - return std::unique_ptr(new MainWindow(app, uim, core)); + return std::unique_ptr(new MainWindow(app, actions, core)); } -MainWindow::MainWindow(Gtk::Application& app, Glib::RefPtr const& ui_mgr, Glib::RefPtr const& core) +MainWindow::MainWindow(Gtk::Application& app, Glib::RefPtr const& actions, Glib::RefPtr const& core) : Gtk::ApplicationWindow() - , impl_(std::make_unique(*this, ui_mgr, core)) + , impl_(std::make_unique(*this, actions, core)) { app.add_window(*this); } MainWindow::~MainWindow() = default; -MainWindow::Impl::Impl(MainWindow& window, Glib::RefPtr const& ui_mgr, Glib::RefPtr const& core) - : core_(core) +MainWindow::Impl::Impl(MainWindow& window, Glib::RefPtr const& actions, Glib::RefPtr const& core) + : window_(window) + , core_(core) { static struct { @@ -475,7 +457,7 @@ MainWindow::Impl::Impl(MainWindow& window, Glib::RefPtr const& u window.maximize(); } - window.add_accel_group(ui_mgr->get_accel_group()); + window.insert_action_group("win", actions); /* Add style provider to the window. */ /* Please move it to separate .css file if you’re adding more styles here. */ auto const* style = ".tr-workarea.frame {border-left-width: 0; border-right-width: 0; border-radius: 0;}"; @@ -490,17 +472,9 @@ MainWindow::Impl::Impl(MainWindow& window, Glib::RefPtr const& u auto* vbox = Gtk::make_managed(Gtk::ORIENTATION_VERTICAL, 0); window.add(*vbox); - /* main menu */ - auto* mainmenu = gtr_action_get_widget("/main-window-menu"); - gtr_action_get_widget("/main-window-menu/torrent-menu/torrent-reannounce") - ->signal_query_tooltip() - .connect(sigc::mem_fun(this, &Impl::onAskTrackerQueryTooltip)); - /* toolbar */ - toolbar_ = gtr_action_get_widget("/main-window-toolbar"); + toolbar_ = gtr_action_get_widget("main-window-toolbar"); toolbar_->get_style_context()->add_class(GTK_STYLE_CLASS_PRIMARY_TOOLBAR); - gtr_action_set_important("open-torrent-toolbar", true); - gtr_action_set_important("show-torrent-properties", true); /* filter */ filter_ = Gtk::make_managed(core_->get_session(), core_->get_model()); @@ -542,7 +516,7 @@ MainWindow::Impl::Impl(MainWindow& window, Glib::RefPtr const& u alt_speed_button_ = Gtk::make_managed(); alt_speed_button_->set_image(*alt_speed_image_); alt_speed_button_->set_relief(Gtk::RELIEF_NONE); - alt_speed_button_->signal_toggled().connect(sigc::mem_fun(this, &Impl::alt_speed_toggled_cb)); + alt_speed_button_->signal_toggled().connect(sigc::mem_fun(*this, &Impl::alt_speed_toggled_cb)); status_->add(*alt_speed_button_); /* spacer */ @@ -557,13 +531,13 @@ MainWindow::Impl::Impl(MainWindow& window, Glib::RefPtr const& u /* upload */ ul_lb_ = Gtk::make_managed(); - ul_lb_->set_margin_left(GUI_PAD); + ul_lb_->set_margin_start(GUI_PAD); ul_lb_->set_single_line_mode(true); status_->add(*ul_lb_); /* ratio */ stats_lb_ = Gtk::make_managed(); - stats_lb_->set_margin_left(GUI_PAD_BIG); + stats_lb_->set_margin_start(GUI_PAD_BIG); stats_lb_->set_single_line_mode(true); status_->add(*stats_lb_); @@ -587,7 +561,6 @@ MainWindow::Impl::Impl(MainWindow& window, Glib::RefPtr const& u scroll_->add(*view_); /* lay out the widgets */ - vbox->pack_start(*mainmenu, false, false); vbox->pack_start(*toolbar_, false, false); vbox->pack_start(*filter_, false, false); vbox->pack_start(*scroll_, true, true); @@ -617,7 +590,7 @@ MainWindow::Impl::Impl(MainWindow& window, Glib::RefPtr const& u prefsChanged(TR_KEY_statusbar_stats); prefsChanged(TR_KEY_show_toolbar); prefsChanged(TR_KEY_alt_speed_enabled); - pref_handler_id_ = core_->signal_prefs_changed().connect(sigc::mem_fun(this, &Impl::prefsChanged)); + pref_handler_id_ = core_->signal_prefs_changed().connect(sigc::mem_fun(*this, &Impl::prefsChanged)); tr_sessionSetAltSpeedFunc( core_->get_session(), diff --git a/gtk/MainWindow.h b/gtk/MainWindow.h index 26ef9fd70..9bda6b676 100644 --- a/gtk/MainWindow.h +++ b/gtk/MainWindow.h @@ -36,7 +36,7 @@ public: static std::unique_ptr create( Gtk::Application& app, - Glib::RefPtr const& uim, + Glib::RefPtr const& actions, Glib::RefPtr const& core); Glib::RefPtr get_selection() const; @@ -45,7 +45,7 @@ public: void refresh(); protected: - MainWindow(Gtk::Application& app, Glib::RefPtr const& uim, Glib::RefPtr const& core); + MainWindow(Gtk::Application& app, Glib::RefPtr const& actions, Glib::RefPtr const& core); private: class Impl; diff --git a/gtk/MakeDialog.cc b/gtk/MakeDialog.cc index 991efb6ed..4b6c18f70 100644 --- a/gtk/MakeDialog.cc +++ b/gtk/MakeDialog.cc @@ -204,7 +204,7 @@ MakeProgressDialog::MakeProgressDialog( add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); add_button(_("_Close"), Gtk::RESPONSE_CLOSE); add_button(_("_Add"), Gtk::RESPONSE_ACCEPT); - signal_response().connect(sigc::mem_fun(this, &MakeProgressDialog::onProgressDialogResponse)); + signal_response().connect(sigc::mem_fun(*this, &MakeProgressDialog::onProgressDialogResponse)); auto* fr = Gtk::make_managed(); fr->set_border_width(GUI_PAD_BIG); @@ -222,7 +222,7 @@ MakeProgressDialog::MakeProgressDialog( v->pack_start(*progress_bar_, false, false, 0); progress_tag_ = Glib::signal_timeout().connect_seconds( - sigc::mem_fun(this, &MakeProgressDialog::onProgressDialogRefresh), + sigc::mem_fun(*this, &MakeProgressDialog::onProgressDialogRefresh), SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS); onProgressDialogRefresh(); @@ -436,7 +436,7 @@ MakeDialog::Impl::Impl(MakeDialog& dialog, Glib::RefPtr const& core) dialog_.add_button(_("_Close"), Gtk::RESPONSE_CLOSE); dialog_.add_button(_("_New"), Gtk::RESPONSE_ACCEPT); - dialog_.signal_response().connect(sigc::mem_fun(this, &Impl::onResponse)); + dialog_.signal_response().connect(sigc::mem_fun(*this, &Impl::onResponse)); auto* t = Gtk::make_managed(); @@ -513,5 +513,5 @@ MakeDialog::Impl::Impl(MakeDialog& dialog, Glib::RefPtr const& core) dialog_.drag_dest_set(Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_COPY); dialog_.drag_dest_add_uri_targets(); - dialog_.signal_drag_data_received().connect(sigc::mem_fun(this, &Impl::on_drag_data_received)); + dialog_.signal_drag_data_received().connect(sigc::mem_fun(*this, &Impl::on_drag_data_received)); } diff --git a/gtk/MessageLogWindow.cc b/gtk/MessageLogWindow.cc index a5824108b..1ec95d135 100644 --- a/gtk/MessageLogWindow.cc +++ b/gtk/MessageLogWindow.cc @@ -461,27 +461,33 @@ MessageLogWindow::Impl::Impl(MessageLogWindow& window, Glib::RefPtr con toolbar->get_style_context()->add_class(GTK_STYLE_CLASS_PRIMARY_TOOLBAR); { - auto* item = Gtk::make_managed(Gtk::StockID("document-save-as")); + auto* icon = Gtk::make_managed(); + icon->set_from_icon_name("document-save-as", Gtk::BuiltinIconSize::ICON_SIZE_SMALL_TOOLBAR); + auto* item = Gtk::make_managed(*icon); item->set_is_important(true); item->set_label(_("Save _As")); item->set_use_underline(true); - item->signal_clicked().connect(sigc::mem_fun(this, &Impl::onSaveRequest)); + item->signal_clicked().connect(sigc::mem_fun(*this, &Impl::onSaveRequest)); toolbar->insert(*item, -1); } { - auto* item = Gtk::make_managed(Gtk::StockID("edit-clear")); + auto* icon = Gtk::make_managed(); + icon->set_from_icon_name("edit-clear", Gtk::BuiltinIconSize::ICON_SIZE_SMALL_TOOLBAR); + auto* item = Gtk::make_managed(*icon); item->set_is_important(true); item->set_label(_("Clear")); item->set_use_underline(true); - item->signal_clicked().connect(sigc::mem_fun(this, &Impl::onClearRequest)); + item->signal_clicked().connect(sigc::mem_fun(*this, &Impl::onClearRequest)); toolbar->insert(*item, -1); } toolbar->insert(*Gtk::make_managed(), -1); { - auto* item = Gtk::make_managed(Gtk::StockID("media-playback-pause")); + auto* icon = Gtk::make_managed(); + icon->set_from_icon_name("media-playback-pause", Gtk::BuiltinIconSize::ICON_SIZE_SMALL_TOOLBAR); + auto* item = Gtk::make_managed(*icon); item->set_is_important(true); item->set_label(_("P_ause")); item->set_use_underline(true); @@ -522,7 +528,7 @@ MessageLogWindow::Impl::Impl(MessageLogWindow& window, Glib::RefPtr con sort_ = Gtk::TreeModelSort::create(filter_); sort_->set_sort_column(message_log_cols.sequence, Gtk::SORT_ASCENDING); maxLevel_ = static_cast(gtr_pref_int_get(TR_KEY_message_level)); - filter_->set_visible_func(sigc::mem_fun(this, &Impl::isRowVisible)); + filter_->set_visible_func(sigc::mem_fun(*this, &Impl::isRowVisible)); view_ = Gtk::make_managed(sort_); view_->signal_button_release_event().connect([this](GdkEventButton* event) @@ -538,7 +544,7 @@ MessageLogWindow::Impl::Impl(MessageLogWindow& window, Glib::RefPtr con window_.add(*vbox); refresh_tag_ = Glib::signal_timeout().connect_seconds( - sigc::mem_fun(this, &Impl::onRefresh), + sigc::mem_fun(*this, &Impl::onRefresh), SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS); scroll_to_bottom(); diff --git a/gtk/OptionsDialog.cc b/gtk/OptionsDialog.cc index 12a2e06dd..c0ab3f279 100644 --- a/gtk/OptionsDialog.cc +++ b/gtk/OptionsDialog.cc @@ -303,7 +303,7 @@ OptionsDialog::Impl::Impl( priority_combo_ = gtr_priority_combo_new(); gtr_priority_combo_set_value(*priority_combo_, TR_PRI_NORMAL); - dialog.signal_response().connect(sigc::mem_fun(this, &Impl::addResponseCB)); + dialog.signal_response().connect(sigc::mem_fun(*this, &Impl::addResponseCB)); auto* grid = Gtk::make_managed(); grid->set_border_width(GUI_PAD_BIG); diff --git a/gtk/PrefsDialog.cc b/gtk/PrefsDialog.cc index c0fc0c78b..f2e24dca3 100644 --- a/gtk/PrefsDialog.cc +++ b/gtk/PrefsDialog.cc @@ -1094,7 +1094,7 @@ PrefsDialog::Impl::Impl(PrefsDialog& dialog, Glib::RefPtr const& core) { static tr_quark const prefs_quarks[] = { TR_KEY_peer_port, TR_KEY_download_dir }; - core_prefs_tag_ = core_->signal_prefs_changed().connect(sigc::mem_fun(this, &Impl::on_core_prefs_changed)); + core_prefs_tag_ = core_->signal_prefs_changed().connect(sigc::mem_fun(*this, &Impl::on_core_prefs_changed)); dialog_.add_button(_("_Help"), Gtk::RESPONSE_HELP); dialog_.add_button(_("_Close"), Gtk::RESPONSE_CLOSE); @@ -1118,6 +1118,6 @@ PrefsDialog::Impl::Impl(PrefsDialog& dialog, Glib::RefPtr const& core) on_core_prefs_changed(key); } - dialog_.signal_response().connect(sigc::mem_fun(this, &Impl::response_cb)); + dialog_.signal_response().connect(sigc::mem_fun(*this, &Impl::response_cb)); gtr_dialog_set_content(dialog_, *n); } diff --git a/gtk/RelocateDialog.cc b/gtk/RelocateDialog.cc index ddd3fb401..853eb3ebd 100644 --- a/gtk/RelocateDialog.cc +++ b/gtk/RelocateDialog.cc @@ -124,7 +124,7 @@ void RelocateDialog::Impl::onResponse(int response) /* start the move and periodically check its status */ done_ = TR_LOC_DONE; - timer_ = Glib::signal_timeout().connect_seconds(sigc::mem_fun(this, &Impl::onTimer), 1); + timer_ = Glib::signal_timeout().connect_seconds(sigc::mem_fun(*this, &Impl::onTimer), 1); onTimer(); } else @@ -159,7 +159,7 @@ RelocateDialog::Impl::Impl(RelocateDialog& dialog, Glib::RefPtr const& dialog_.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); dialog_.add_button(_("_Apply"), Gtk::RESPONSE_APPLY); dialog_.set_default_response(Gtk::RESPONSE_CANCEL); - dialog_.signal_response().connect(sigc::mem_fun(this, &Impl::onResponse)); + dialog_.signal_response().connect(sigc::mem_fun(*this, &Impl::onResponse)); row = 0; auto* t = Gtk::make_managed(); diff --git a/gtk/Session.cc b/gtk/Session.cc index d6daa19d4..70f3fd41c 100644 --- a/gtk/Session.cc +++ b/gtk/Session.cc @@ -713,7 +713,7 @@ void Session::Impl::watchdir_monitor_file(Glib::RefPtr const& file) if (!monitor_idle_tag_.connected()) { - monitor_idle_tag_ = Glib::signal_timeout().connect_seconds(sigc::mem_fun(this, &Impl::watchdir_idle), 1); + monitor_idle_tag_ = Glib::signal_timeout().connect_seconds(sigc::mem_fun(*this, &Impl::watchdir_idle), 1); } } } @@ -769,7 +769,7 @@ void Session::Impl::watchdir_update() monitor_ = m; monitor_dir_ = dir; - monitor_tag_ = m->signal_changed().connect(sigc::mem_fun(this, &Impl::on_file_changed_in_watchdir)); + monitor_tag_ = m->signal_changed().connect(sigc::mem_fun(*this, &Impl::on_file_changed_in_watchdir)); } } diff --git a/gtk/StatsDialog.cc b/gtk/StatsDialog.cc index b4528b73c..b7b4cebe6 100644 --- a/gtk/StatsDialog.cc +++ b/gtk/StatsDialog.cc @@ -181,8 +181,8 @@ StatsDialog::Impl::Impl(StatsDialog& dialog, Glib::RefPtr const& core) gtr_dialog_set_content(dialog_, *t); updateStats(); - dialog_.signal_response().connect(sigc::mem_fun(this, &Impl::dialogResponse)); + dialog_.signal_response().connect(sigc::mem_fun(*this, &Impl::dialogResponse)); update_stats_tag_ = Glib::signal_timeout().connect_seconds( - sigc::mem_fun(this, &Impl::updateStats), + sigc::mem_fun(*this, &Impl::updateStats), SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS); } diff --git a/gtk/SystemTrayIcon.cc b/gtk/SystemTrayIcon.cc index 5b0fadb39..2c8595200 100644 --- a/gtk/SystemTrayIcon.cc +++ b/gtk/SystemTrayIcon.cc @@ -1,14 +1,18 @@ /* - * This file Copyright (C) 2007-2014 Mnemosyne LLC + * This file Copyright (C) 2007-2021 Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. * */ +// _AppIndicatorClass::{fallback,unfallback} use deprecated GtkStatusIcon +#undef GTK_DISABLE_DEPRECATED +// We're using deprecated Gtk::StatusItem ourselves as well +#undef GTKMM_DISABLE_DEPRECATED + #include #include -#include #ifdef HAVE_LIBAPPINDICATOR #include @@ -27,7 +31,7 @@ class SystemTrayIcon::Impl { public: - Impl(Glib::RefPtr const& core); + Impl(Gtk::Window& main_window, Glib::RefPtr const& core); ~Impl(); void refresh(); @@ -163,8 +167,8 @@ std::string getIconName() } // namespace -SystemTrayIcon::SystemTrayIcon(Glib::RefPtr const& core) - : impl_(std::make_unique(core)) +SystemTrayIcon::SystemTrayIcon(Gtk::Window& main_window, Glib::RefPtr const& core) + : impl_(std::make_unique(main_window, core)) { } @@ -175,11 +179,12 @@ void SystemTrayIcon::refresh() impl_->refresh(); } -SystemTrayIcon::Impl::Impl(Glib::RefPtr const& core) +SystemTrayIcon::Impl::Impl(Gtk::Window& main_window, Glib::RefPtr const& core) : core_(core) { auto const icon_name = getIconName(); - menu_ = gtr_action_get_widget("/icon-popup"); + menu_ = Gtk::make_managed(gtr_action_get_object("icon-popup")); + menu_->attach_to_widget(main_window); #ifdef HAVE_LIBAPPINDICATOR @@ -191,8 +196,8 @@ SystemTrayIcon::Impl::Impl(Glib::RefPtr const& core) #else 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)); + icon_->signal_activate().connect(sigc::mem_fun(*this, &Impl::activated)); + icon_->signal_popup_menu().connect(sigc::mem_fun(*this, &Impl::popup)); #endif } diff --git a/gtk/SystemTrayIcon.h b/gtk/SystemTrayIcon.h index c3081cf52..83c1ba8dc 100644 --- a/gtk/SystemTrayIcon.h +++ b/gtk/SystemTrayIcon.h @@ -1,5 +1,5 @@ /* - * This file Copyright (C) 2007-2014 Mnemosyne LLC + * This file Copyright (C) 2007-2021 Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. @@ -10,12 +10,14 @@ #include +#include + class Session; class SystemTrayIcon { public: - SystemTrayIcon(Glib::RefPtr const& core); + SystemTrayIcon(Gtk::Window& main_window, Glib::RefPtr const& core); ~SystemTrayIcon(); void refresh(); diff --git a/gtk/Utils.h b/gtk/Utils.h index 5ac7ce86b..6584823d9 100644 --- a/gtk/Utils.h +++ b/gtk/Utils.h @@ -198,6 +198,16 @@ inline T* gtr_get_ptr(Glib::RefPtr const& ptr) #endif } +template +inline Glib::RefPtr gtr_ptr_static_cast(Glib::RefPtr const& ptr) +{ +#if G_ENCODE_VERSION(GLIBMM_MAJOR_VERSION, GLIBMM_MINOR_VERSION) < G_ENCODE_VERSION(2, 68) + return Glib::RefPtr::cast_static(ptr); +#else + return std::static_pointer_cast(ptr); +#endif +} + template<> struct std::hash { diff --git a/gtk/transmission-ui.xml b/gtk/transmission-ui.xml index 86a2e74a8..8fa582260 100644 --- a/gtk/transmission-ui.xml +++ b/gtk/transmission-ui.xml @@ -1,130 +1,585 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - + + + _File +
+ + win.open-torrent + document-open + _Open + Open a torrent + + + win.open-torrent-from-url + document-open + Open _URL… + <control>U + Open URL… + + + win.new-torrent + document-new + _New… + +
+
+ + win.start-all-torrents + media-playback-start + _Start All + Start all torrents + + + win.pause-all-torrents + media-playback-pause + _Pause All + Pause all torrents + +
+
+ + win.quit + application-exit + _Quit + +
+
+ + _Edit +
+ + win.select-all + edit-select-all + Select _All + <control>A + + + win.deselect-all + Dese_lect All + <shift><control>A + +
+
+ + win.edit-preferences + preferences-system + _Preferences + +
+
+ + _Torrent +
+ + win.show-torrent-properties + document-properties + _Properties + <alt>Return + Torrent properties + + + win.open-torrent-folder + document-open + Open Fold_er + <control>E + +
+
+ + win.torrent-start + media-playback-start + _Start + <control>S + Start torrent + + + win.torrent-start-now + media-playback-start + Start _Now + <shift><control>S + Start torrent now + + + win.torrent-reannounce + network-workgroup + Ask Tracker for _More Peers + + + _Queue +
+ + win.queue-move-top + go-top + Move to _Top + + + win.queue-move-up + go-up + Move _Up + + + win.queue-move-down + go-down + Move _Down + + + win.queue-move-bottom + go-bottom + Move to _Bottom + +
+
+ + win.torrent-stop + media-playback-pause + _Pause + <control>P + Pause torrent + +
+
+ + win.relocate-torrent + Set _Location… + + + win.torrent-verify + _Verify Local Data + <control>V + + + win.copy-magnet-link-to-clipboard + edit-copy + Copy _Magnet Link to Clipboard + +
+
+ + win.remove-torrent + list-remove + Remove torrent + Delete + + + win.delete-torrent + edit-delete + _Delete Files and Remove + <shift>Delete + +
+
+ + _View +
+ + win.compact-view + _Compact View + <alt>C + +
+
+ + win.show-toolbar + _Toolbar + + + win.show-filterbar + _Filterbar + + + win.show-statusbar + _Statusbar + +
+
+ + win.sort-torrents + Sort by _Activity + sort-by-activity + + + win.sort-torrents + Sort by A_ge + sort-by-age + + + win.sort-torrents + Sort by _Name + sort-by-name + + + win.sort-torrents + Sort by _Progress + sort-by-progress + + + win.sort-torrents + Sort by _Queue + sort-by-queue + + + win.sort-torrents + Sort by Rati_o + sort-by-ratio + + + win.sort-torrents + Sort by Si_ze + sort-by-size + + + win.sort-torrents + Sort by Stat_e + sort-by-state + + + win.sort-torrents + Sort by Time _Left + sort-by-time-left + +
+
+ + win.sort-reversed + Re_verse Sort Order + +
+
+ + _Help +
+ + win.toggle-message-log + Message _Log + + + win.show-stats + _Statistics + +
+
+ + win.donate + _Donate + +
+
+ + win.help + help-browser + _Contents + F1 + + + win.show-about-dialog + help-about + _About + +
+
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + True + False + + + True + False + Open a torrent + True + win.open-torrent + _Open + True + document-open + + + False + False + + + + + True + False + Start torrent + win.torrent-start + _Start + True + media-playback-start + + + False + False + + + + + True + False + Pause torrent + win.torrent-stop + _Pause + True + media-playback-pause + + + False + False + + + + + True + False + win.remove-torrent + Remove torrent + True + list-remove + + + False + False + + + + + True + False + + + False + True + + + + + True + False + Torrent properties + True + win.show-torrent-properties + _Properties + True + document-properties + + + False + False + + + - - - - - - - - - - - - - -
+ +
+ + win.show-torrent-properties + document-properties + _Properties + <alt>Return + Torrent properties + + + win.open-torrent-folder + document-open + Open Fold_er + <control>E + +
+
+ + _Sort Torrents By +
+ + win.sort-torrents + Sort by _Activity + sort-by-activity + + + win.sort-torrents + Sort by A_ge + sort-by-age + + + win.sort-torrents + Sort by _Name + sort-by-name + + + win.sort-torrents + Sort by _Progress + sort-by-progress + + + win.sort-torrents + Sort by _Queue + sort-by-queue + + + win.sort-torrents + Sort by Rati_o + sort-by-ratio + + + win.sort-torrents + Sort by Si_ze + sort-by-size + + + win.sort-torrents + Sort by Stat_e + sort-by-state + + + win.sort-torrents + Sort by Time _Left + sort-by-time-left + +
+
+ + win.sort-reversed + Re_verse Sort Order + +
+
+
+
+ + win.torrent-start + media-playback-start + _Start + <control>S + Start torrent + + + win.torrent-start-now + media-playback-start + Start _Now + <shift><control>S + Start torrent now + + + win.torrent-reannounce + network-workgroup + Ask Tracker for _More Peers + + + _Queue +
+ + win.queue-move-top + go-top + Move to _Top + + + win.queue-move-up + go-up + Move _Up + + + win.queue-move-down + go-down + Move _Down + + + win.queue-move-bottom + go-bottom + Move to _Bottom + +
+
+ + win.torrent-stop + media-playback-pause + _Pause + <control>P + Pause torrent + +
+
+ + win.relocate-torrent + Set _Location… + + + win.torrent-verify + _Verify Local Data + <control>V + + + win.copy-magnet-link-to-clipboard + edit-copy + Copy _Magnet Link to Clipboard + +
+
+ + win.remove-torrent + list-remove + Remove torrent + Delete + + + win.delete-torrent + edit-delete + _Delete Files and Remove + <shift>Delete + +
+
+ + +
+ + win.toggle-main-window + _Show Transmission + +
+
+ + win.open-torrent + document-open + _Open + Open a torrent + + + win.open-torrent-from-url + document-open + Open _URL… + + Open URL… + +
+
+ + win.pause-all-torrents + media-playback-pause + _Pause All + Pause all torrents + + + win.start-all-torrents + media-playback-start + _Start All + Start all torrents + +
+
+ + win.alt-speed-enabled + Enable Alternative Speed _Limits + +
+
+ + win.quit + application-exit + _Quit + +
+
+ diff --git a/gtk/transmission.gresource.xml b/gtk/transmission.gresource.xml index 55a3eef02..84d6bcd98 100644 --- a/gtk/transmission.gresource.xml +++ b/gtk/transmission.gresource.xml @@ -1,13 +1,14 @@ - - - - icons/hicolor_apps_scalable_transmission.svg - icons/hicolor_apps_scalable_transmission.svg - icons/lock.png - icons/ratio.png - icons/turtle-blue.png - icons/turtle-grey.png - icons/utilities.png - transmission-ui.xml - - + + + + icons/hicolor_apps_scalable_transmission.svg + icons/hicolor_apps_scalable_transmission.svg + icons/hicolor_apps_scalable_transmission.svg + icons/lock.png + icons/ratio.png + icons/turtle-blue.png + icons/turtle-grey.png + icons/utilities.png + transmission-ui.xml + +