Skip to content

Commit

Permalink
Switch to list view for torrents list (GTK 4) (transmission#5858)
Browse files Browse the repository at this point in the history
* Add compat operator* for RefPtr

* Rename `*_tree_view_*` button handling helpers to `*_item_view_*`

* Move torrent item colors to CSS

* Switch to list view for torrents list (GTK 4)

* Bump Fedora image to 39 (current rawhide) for GTK 4.11

Enable deprecations as there're lots of them in 4.11 and I'm not keen on
fixing them all right now. Disable warnings as errors due to
-Warray-bounds issue somewhere in libfmt.
  • Loading branch information
mikedld committed Aug 6, 2023
1 parent badeed3 commit 586cff9
Show file tree
Hide file tree
Showing 24 changed files with 904 additions and 207 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -644,14 +644,14 @@ jobs:
name: binaries-${{ github.job }}
path: pfx/**/*

fedora-36-from-tarball:
fedora-39-from-tarball:
needs: [ make-source-tarball, what-to-make ]
if: ${{ needs.what-to-make.outputs.make-cli == 'true' || needs.what-to-make.outputs.make-daemon == 'true' || needs.what-to-make.outputs.make-gtk == 'true' || needs.what-to-make.outputs.make-qt == 'true' || needs.what-to-make.outputs.make-tests == 'true' || needs.what-to-make.outputs.make-utils == 'true' }}
runs-on: ubuntu-22.04
env:
NODE_PATH: /usr/lib/nodejs:/usr/share/nodejs
container:
image: fedora:36
image: fedora:39
steps:
- name: Show Configuration
run: |
Expand Down Expand Up @@ -706,7 +706,8 @@ jobs:
-DENABLE_TESTS=${{ (needs.what-to-make.outputs.make-tests == 'true') && 'ON' || 'OFF' }} \
-DENABLE_UTILS=${{ (needs.what-to-make.outputs.make-utils == 'true') && 'ON' || 'OFF' }} \
-DREBUILD_WEB=${{ (needs.what-to-make.outputs.make-web == 'true') && 'ON' || 'OFF' }} \
-DENABLE_WERROR=ON \
-DENABLE_DEPRECATED=ON \
-DENABLE_WERROR=OFF \
-DRUN_CLANG_TIDY=OFF
- name: Build
run: cmake --build obj --config RelWithDebInfo
Expand Down
7 changes: 4 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ set(DEFLATE_MINIMUM 1.7)
set(EVENT2_MINIMUM 2.1.0)
set(GIOMM_MINIMUM 2.26.0)
set(GLIBMM_MINIMUM 2.60.0)
set(GTKMM_MINIMUM 3.24.0)
set(GTKMM3_MINIMUM 3.24.0)
set(GTKMM4_MINIMUM 4.11.1)
set(OPENSSL_MINIMUM 0.9.7)
set(MBEDTLS_MINIMUM 1.3)
set(NPM_MINIMUM 8.1.307) # Node.js 14
Expand Down Expand Up @@ -297,7 +298,7 @@ if(ENABLE_GTK)

if(USE_GTK_VERSION STREQUAL "AUTO" OR USE_GTK_VERSION EQUAL 4)
pkg_check_modules(GTK4
gtkmm-4.0>=${GTKMM_MINIMUM}
gtkmm-4.0>=${GTKMM4_MINIMUM}
glibmm-2.68>=${GLIBMM_MINIMUM}
giomm-2.68>=${GIOMM_MINIMUM})
set(GTK_VERSION 4)
Expand All @@ -306,7 +307,7 @@ if(ENABLE_GTK)

if(NOT GTK_FOUND AND (USE_GTK_VERSION STREQUAL "AUTO" OR USE_GTK_VERSION EQUAL 3))
pkg_check_modules(GTK3
gtkmm-3.0>=${GTKMM_MINIMUM}
gtkmm-3.0>=${GTKMM3_MINIMUM}
glibmm-2.4>=${GLIBMM_MINIMUM}
giomm-2.4>=${GIOMM_MINIMUM})
set(GTK_VERSION 3)
Expand Down
7 changes: 7 additions & 0 deletions gtk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ target_sources(${TR_NAME}-gtk
DetailsDialog.h
Dialogs.cc
Dialogs.h
DynamicPropertyStore.h
FaviconCache.cc
FileList.cc
FileList.h
Expand Down Expand Up @@ -72,6 +73,10 @@ target_sources(${TR_NAME}-gtk
Utils.cc
Utils.h)

tr_allow_compile_if(
[=[[GTK_VERSION EQUAL 3]]=]
TorrentCellRenderer.cc)

target_sources(${TR_NAME}-gtk
PRIVATE
ui/gtk3/AddTrackerDialog.ui
Expand Down Expand Up @@ -105,6 +110,8 @@ target_sources(${TR_NAME}-gtk
ui/gtk4/PrefsDialog.ui
ui/gtk4/RelocateDialog.ui
ui/gtk4/StatsDialog.ui
ui/gtk4/TorrentListItemCompact.ui
ui/gtk4/TorrentListItemFull.ui
ui/gtk4/TorrentUrlChooserDialog.ui)

source_group(Ui/GTK4
Expand Down
14 changes: 7 additions & 7 deletions gtk/DetailsDialog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1743,10 +1743,10 @@ void DetailsDialog::Impl::peer_page_init(Glib::RefPtr<Gtk::Builder> const& build
webseed_store_ = Gtk::ListStore::create(webseed_cols);
auto* v = gtr_get_widget<Gtk::TreeView>(builder, "webseeds_view");
v->set_model(webseed_store_);
setup_tree_view_button_event_handling(
setup_item_view_button_event_handling(
*v,
{},
[v](double view_x, double view_y) { return on_tree_view_button_released(*v, view_x, view_y); });
[v](double view_x, double view_y) { return on_item_view_button_released(*v, view_x, view_y); });

{
auto* r = Gtk::make_managed<Gtk::CellRendererText>();
Expand Down Expand Up @@ -1775,10 +1775,10 @@ void DetailsDialog::Impl::peer_page_init(Glib::RefPtr<Gtk::Builder> const& build
peer_view_->set_model(m);
peer_view_->set_has_tooltip(true);
peer_view_->signal_query_tooltip().connect(sigc::mem_fun(*this, &Impl::onPeerViewQueryTooltip), false);
setup_tree_view_button_event_handling(
setup_item_view_button_event_handling(
*peer_view_,
{},
[this](double view_x, double view_y) { return on_tree_view_button_released(*peer_view_, view_x, view_y); });
[this](double view_x, double view_y) { return on_item_view_button_released(*peer_view_, view_x, view_y); });

setPeerViewColumns(peer_view_);

Expand Down Expand Up @@ -2449,11 +2449,11 @@ void DetailsDialog::Impl::tracker_page_init(Glib::RefPtr<Gtk::Builder> const& /*
trackers_filtered_->set_visible_func(sigc::mem_fun(*this, &Impl::trackerVisibleFunc));

tracker_view_->set_model(trackers_filtered_);
setup_tree_view_button_event_handling(
setup_item_view_button_event_handling(
*tracker_view_,
[this](guint /*button*/, TrGdkModifierType /*state*/, double view_x, double view_y, bool context_menu_requested)
{ return on_tree_view_button_pressed(*tracker_view_, view_x, view_y, context_menu_requested); },
[this](double view_x, double view_y) { return on_tree_view_button_released(*tracker_view_, view_x, view_y); });
{ return on_item_view_button_pressed(*tracker_view_, view_x, view_y, context_menu_requested); },
[this](double view_x, double view_y) { return on_item_view_button_released(*tracker_view_, view_x, view_y); });

auto sel = tracker_view_->get_selection();
sel->signal_changed().connect(sigc::mem_fun(*this, &Impl::on_tracker_list_selection_changed));
Expand Down
107 changes: 107 additions & 0 deletions gtk/DynamicPropertyStore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// This file Copyright © 2023 Mnemosyne LLC.
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.

#pragma once

#include "Utils.h"

#include <glibmm/object.h>
#include <glibmm/value.h>
#include <glibmm/wrap.h>

#include <array>
#include <functional>
#include <type_traits>

template<typename ObjectT, typename PropertyT>
class DynamicPropertyStore
{
public:
using ObjectType = ObjectT;
using PropertyType = PropertyT;

using PropertyIdType = guint;
static_assert(std::is_same_v<std::underlying_type_t<PropertyType>, PropertyIdType>);

struct PropertyInfo
{
template<typename MethodT>
using ValueType = std::invoke_result_t<MethodT, ObjectType>;

PropertyIdType id = 0;
GParamSpec* spec = nullptr;
std::function<void(ObjectType const&, Glib::ValueBase&)> getter;

PropertyInfo() = default;

template<typename MethodT>
PropertyInfo(PropertyType index, char const* name, char const* nick, char const* blurb, MethodT getter_method)
: id(static_cast<PropertyIdType>(index))
, spec(gtr_get_param_spec<ValueType<MethodT>>(name, nick, blurb))
, getter([getter_method](ObjectType const& object, Glib::ValueBase& value)
{ static_cast<Glib::Value<ValueType<MethodT>>&>(value).set((object.*getter_method)()); })
{
}
};

static inline auto const PropertyCount = static_cast<PropertyIdType>(PropertyType::N_PROPS);

public:
static DynamicPropertyStore& get() noexcept
{
static auto instance = DynamicPropertyStore();
return instance;
}

void install(GObjectClass* cls, std::initializer_list<PropertyInfo> properties)
{
cls->get_property = &DynamicPropertyStore::get_property_vfunc;

g_assert(properties_.size() == properties.size() + 1);
std::move(properties.begin(), properties.end(), properties_.begin() + 1);

for (auto id = PropertyIdType{ 1 }; id < PropertyCount; ++id)
{
g_assert(id == properties_[id].id);
g_object_class_install_property(cls, id, properties_[id].spec);
}
}

void get_value(ObjectType const& object, PropertyType index, Glib::ValueBase& value) const
{
get_property(index).getter(object, value);
}

void notify_changed(ObjectType& object, PropertyType index) const
{
g_object_notify_by_pspec(object.gobj(), get_property(index).spec);
}

private:
PropertyInfo const& get_property(PropertyType index) const noexcept
{
auto const id = static_cast<PropertyIdType>(index);
g_assert(id > 0);
g_assert(id < PropertyCount);
return properties_[id];
}

static void get_property_vfunc(GObject* object, PropertyIdType id, GValue* value, GParamSpec* /*param_spec*/)
{
if (id <= 0 || id >= PropertyCount)
{
return;
}

if (auto const* const typed_object = dynamic_cast<ObjectType const*>(Glib::wrap_auto(object)); typed_object != nullptr)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
get().get_value(*typed_object, PropertyType{ id }, *reinterpret_cast<Glib::ValueBase*>(value));
}
}

private:
std::array<PropertyInfo, PropertyCount> properties_ = {};
};
4 changes: 2 additions & 2 deletions gtk/FileList.cc
Original file line number Diff line number Diff line change
Expand Up @@ -924,11 +924,11 @@ FileList::Impl::Impl(
{
/* create the view */
view_->signal_row_activated().connect(sigc::mem_fun(*this, &Impl::onRowActivated));
setup_tree_view_button_event_handling(
setup_item_view_button_event_handling(
*view_,
[this](guint button, TrGdkModifierType state, double view_x, double view_y, bool /*context_menu_requested*/)
{ return onViewButtonPressed(button, state, view_x, view_y); },
[this](double view_x, double view_y) { return on_tree_view_button_released(*view_, view_x, view_y); });
[this](double view_x, double view_y) { return on_item_view_button_released(*view_, view_x, view_y); });

auto pango_font_description = view_->create_pango_context()->get_font_description();
if (auto const new_size = pango_font_description.get_size() * 0.8; pango_font_description.get_size_is_absolute())
Expand Down
2 changes: 1 addition & 1 deletion gtk/FilterBar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ bool FilterBar::Impl::activity_filter_model_update()
for (auto i = 0U, count = torrents_model->get_n_items(); i < count; ++i)
{
auto const torrent = gtr_ptr_dynamic_cast<Torrent>(torrents_model->get_object(i));
if (torrent != nullptr && TorrentFilter::match_activity(*torrent.get(), static_cast<ActivityType>(type)))
if (torrent != nullptr && TorrentFilter::match_activity(*torrent, static_cast<ActivityType>(type)))
{
++hits;
}
Expand Down
6 changes: 6 additions & 0 deletions gtk/GtkCompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ inline bool operator!=(RefPtr<T> const& lhs, std::nullptr_t /*rhs*/)
return !(lhs == nullptr);
}

template<typename T>
inline T& operator*(RefPtr<T> const& ptr)
{
return *ptr.get();
}

template<typename T>
inline RefPtr<T> make_refptr_for_instance(T* object)
{
Expand Down
Loading

0 comments on commit 586cff9

Please sign in to comment.