Let the download list own its downloads through a shared pointer.

A multicall could then dispatch commands on an erased download.
This commit is contained in:
xirvik
2026-08-16 19:17:00 +00:00
committed by Jari Sundell
parent 58e627f2be
commit 385e149ccc
14 changed files with 116 additions and 56 deletions
+23 -5
View File
@@ -51,7 +51,7 @@ apply_on_ratio(const torrent::Object& rawArgs) {
!(max_ratio > 0 && total_upload * 100 > total_done * max_ratio)) !(max_ratio > 0 && total_upload * 100 > total_done * max_ratio))
continue; continue;
downloads.push_back(*itr); downloads.push_back(itr->get());
} }
auto ratio_command = "group." + group_name + ".ratio.command"; auto ratio_command = "group." + group_name + ".ratio.command";
@@ -173,7 +173,7 @@ apply_close_low_diskspace(int64_t arg, uint32_t skip_priority) {
torrent::FileList::cache_list cache; torrent::FileList::cache_list cache;
for (auto download : *control->core()->download_list()) { for (const auto& download : *control->core()->download_list()) {
if (!download->is_downloading()) if (!download->is_downloading())
continue; continue;
if (download->priority() >= skip_priority) if (download->priority() >= skip_priority)
@@ -240,15 +240,25 @@ d_multicall(const torrent::Object::list_type& args) {
// Add some pre-parsing of the commands, so we don't spend time // Add some pre-parsing of the commands, so we don't spend time
// parsing and searching command map for every single call. // parsing and searching command map for every single call.
std::vector<core::Download*> dlist((*view_itr)->begin_visible(), (*view_itr)->end_visible()); // Hold a reference to each download so a command that erases one does not
// leave the rest of the loop dispatching on freed memory.
core::View::base_type dlist((*view_itr)->begin_visible(), (*view_itr)->end_visible());
torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list(); torrent::Object::list_type& result = resultRaw.as_list();
for (auto download : dlist) { for (const auto& download : dlist) {
if (download.use_count() == 1)
continue;
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) { for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
// A command may erase this download, which destroys the torrent object it
// wraps; the list dropping its reference is what tells us.
if (download.use_count() == 1)
break;
auto& cmd = cItr->as_string(); auto& cmd = cItr->as_string();
row.push_back(rpc::parse_command(rpc::make_target(download), cmd.c_str(), cmd.c_str() + cmd.size()).first); row.push_back(rpc::parse_command(rpc::make_target(download), cmd.c_str(), cmd.c_str() + cmd.size()).first);
} }
@@ -271,10 +281,12 @@ d_multicall_filtered(const torrent::Object::list_type& args) {
if (view_itr == viewManager->end()) if (view_itr == viewManager->end())
throw torrent::input_error("Could not find view '" + arg->as_string() + "'."); throw torrent::input_error("Could not find view '" + arg->as_string() + "'.");
// Make a filtered copy of the current item list // Make a filtered copy of the current item list, holding a reference to each
// download so a command that erases one cannot free it under us.
core::View::base_type dlist; core::View::base_type dlist;
(*view_itr)->filter_by(*++arg, dlist); (*view_itr)->filter_by(*++arg, dlist);
// Generate result by iterating over all items // Generate result by iterating over all items
auto resultRaw = torrent::Object::create_list(); auto resultRaw = torrent::Object::create_list();
auto& result = resultRaw.as_list(); auto& result = resultRaw.as_list();
@@ -282,11 +294,17 @@ d_multicall_filtered(const torrent::Object::list_type& args) {
++arg; // skip to first command ++arg; // skip to first command
for (const auto& item : dlist) { for (const auto& item : dlist) {
if (item.use_count() == 1)
continue;
// Add empty row to result // Add empty row to result
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
// Call the provided commands and assemble their results // Call the provided commands and assemble their results
for (torrent::Object::list_const_iterator command = arg; command != args.end(); command++) { for (torrent::Object::list_const_iterator command = arg; command != args.end(); command++) {
if (item.use_count() == 1)
break;
auto& cmdstr = command->as_string(); auto& cmdstr = command->as_string();
row.push_back(rpc::parse_command(rpc::make_target(item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first); row.push_back(rpc::parse_command(rpc::make_target(item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first);
} }
+2 -2
View File
@@ -68,11 +68,11 @@ apply_dht_add_node(const std::string& arg) {
torrent::Object torrent::Object
apply_enable_trackers(int64_t arg) { apply_enable_trackers(int64_t arg) {
if (arg == 0) { if (arg == 0) {
for (auto download : *control->core()->download_list()) for (const auto& download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.disable(); }); download->tracker_controller().for_each([](auto& tracker) { tracker.disable(); });
} else { } else {
for (auto download : *control->core()->download_list()) for (const auto& download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.enable(); }); download->tracker_controller().for_each([](auto& tracker) { tracker.enable(); });
} }
+1
View File
@@ -1,6 +1,7 @@
#ifndef RTORRENT_CORE_DOWNLOAD_H #ifndef RTORRENT_CORE_DOWNLOAD_H
#define RTORRENT_CORE_DOWNLOAD_H #define RTORRENT_CORE_DOWNLOAD_H
#include <memory>
#include <torrent/common.h> #include <torrent/common.h>
#include <torrent/download.h> #include <torrent/download.h>
#include <torrent/download_info.h> #include <torrent/download_info.h>
+10 -12
View File
@@ -37,7 +37,7 @@ namespace core {
inline void inline void
DownloadList::check_contains([[maybe_unused]] Download* d) { DownloadList::check_contains([[maybe_unused]] Download* d) {
#ifdef USE_EXTRA_DEBUG #ifdef USE_EXTRA_DEBUG
if (std::find(begin(), end(), d) == end()) if (std::find_if(begin(), end(), [d](const auto& entry) { return entry.get() == d; }) == end())
throw torrent::internal_error("DownloadList::check_contains(...) failed."); throw torrent::internal_error("DownloadList::check_contains(...) failed.");
#endif #endif
} }
@@ -54,7 +54,6 @@ DownloadList::clear() {
base_type::pop_back(); base_type::pop_back();
torrent::download_remove(*download->download()); torrent::download_remove(*download->download());
delete download;
} catch (torrent::internal_error& e) { } catch (torrent::internal_error& e) {
lt_log_print(torrent::LOG_ERROR, "DownloadList::clear() failed to close or remove download: %s", e.what()); lt_log_print(torrent::LOG_ERROR, "DownloadList::clear() failed to close or remove download: %s", e.what());
@@ -70,7 +69,7 @@ DownloadList::clear() {
void void
DownloadList::session_save() { DownloadList::session_save() {
for (auto& download : *this) for (auto& download : *this)
session_thread::manager()->save_resume_download(download); session_thread::manager()->save_resume_download(download.get());
control->dht_manager()->save_dht_cache(); control->dht_manager()->save_dht_cache();
control->ui()->save_input_history(); control->ui()->save_input_history();
@@ -78,7 +77,7 @@ DownloadList::session_save() {
DownloadList::iterator DownloadList::iterator
DownloadList::find(const torrent::HashString& hash) { DownloadList::find(const torrent::HashString& hash) {
return std::find_if(begin(), end(), [hash](Download* d) { return hash == d->info()->hash(); }); return std::find_if(begin(), end(), [hash](const auto& d) { return hash == d->info()->hash(); });
} }
DownloadList::iterator DownloadList::iterator
@@ -91,14 +90,14 @@ DownloadList::find_hex(const char* hash) {
if (torrent::utils::transform_from_hex(hash, hash + 40, key) != key.end()) if (torrent::utils::transform_from_hex(hash, hash + 40, key) != key.end())
return end(); return end();
return std::find_if(begin(), end(), [key](Download* d) { return key == d->info()->hash(); }); return std::find_if(begin(), end(), [key](const auto& d) { return key == d->info()->hash(); });
} }
Download* Download*
DownloadList::find_hex_ptr(const char* hash) { DownloadList::find_hex_ptr(const char* hash) {
iterator itr = find_hex(hash); iterator itr = find_hex(hash);
return itr != end() ? *itr : NULL; return itr != end() ? itr->get() : NULL;
} }
Download* Download*
@@ -159,7 +158,7 @@ DownloadList::create(std::istream* str, uint32_t tracker_key, bool printLog) {
DownloadList::iterator DownloadList::iterator
DownloadList::insert(Download* download) { DownloadList::insert(Download* download) {
iterator itr = base_type::insert(end(), download); iterator itr = base_type::insert(end(), std::shared_ptr<Download>(download));
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Inserting download."); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Inserting download.");
@@ -170,7 +169,7 @@ DownloadList::insert(Download* download) {
// This needs to be separated into two different calls to ensure // This needs to be separated into two different calls to ensure
// the download remains in the view. // the download remains in the view.
for (auto v : *control->view_manager()) for (auto v : *control->view_manager())
v->insert(download); v->insert(*itr);
for (auto v : *control->view_manager()) for (auto v : *control->view_manager())
v->filter_download(download); v->filter_download(download);
@@ -187,7 +186,7 @@ DownloadList::insert(Download* download) {
void void
DownloadList::erase_ptr(Download* download) { DownloadList::erase_ptr(Download* download) {
erase(std::find(begin(), end(), download)); erase(std::find_if(begin(), end(), [download](const auto& entry) { return entry.get() == download; }));
} }
DownloadList::iterator DownloadList::iterator
@@ -201,15 +200,14 @@ DownloadList::erase(iterator itr) {
(*itr)->set_hash_failed(true); (*itr)->set_hash_failed(true);
close(*itr); close(*itr);
session_thread::manager()->remove_download(*itr); session_thread::manager()->remove_download(itr->get());
DL_TRIGGER_EVENT(*itr, "event.download.erased"); DL_TRIGGER_EVENT(*itr, "event.download.erased");
for (auto v : *control->view_manager()) for (auto v : *control->view_manager())
v->erase(*itr); v->erase(itr->get());
torrent::download_remove(*(*itr)->download()); torrent::download_remove(*(*itr)->download());
delete *itr;
return base_type::erase(itr); return base_type::erase(itr);
} }
+11 -2
View File
@@ -3,6 +3,7 @@
#include <iosfwd> #include <iosfwd>
#include <list> #include <list>
#include <memory>
#include <string> #include <string>
namespace torrent { namespace torrent {
@@ -20,9 +21,9 @@ class Download;
// //
// Fix apply_on_ratio if the base_type is changed. // Fix apply_on_ratio if the base_type is changed.
class DownloadList : private std::list<Download*> { class DownloadList : private std::list<std::shared_ptr<Download>> {
public: public:
typedef std::list<Download*> base_type; typedef std::list<std::shared_ptr<Download>> base_type;
using base_type::iterator; using base_type::iterator;
using base_type::const_iterator; using base_type::const_iterator;
@@ -64,6 +65,14 @@ public:
bool open(Download* d); bool open(Download* d);
void open_throw(Download* d); void open_throw(Download* d);
// Overloads for the list's own entries, so callers iterating it do not need
// to unwrap.
bool open(const value_type& d) { return open(d.get()); }
void close(const value_type& d) { close(d.get()); }
void close_quick(const value_type& d) { close_quick(d.get()); }
void pause(const value_type& d) { pause(d.get()); }
void resume(const value_type& d) { resume(d.get()); }
void close(Download* d); void close(Download* d);
void close_directly(Download* d); void close_directly(Download* d);
void close_quick(Download* d); void close_quick(Download* d);
+4 -4
View File
@@ -154,10 +154,10 @@ Manager::cleanup() {
void void
Manager::shutdown(bool force) { Manager::shutdown(bool force) {
if (!force) { if (!force) {
for (auto d : *m_download_list) for (const auto& d : *m_download_list)
m_download_list->pause_default(d); m_download_list->pause_default(d.get());
} else { } else {
for (auto d : *m_download_list) for (const auto& d : *m_download_list)
m_download_list->close_quick(d); m_download_list->close_quick(d);
} }
} }
@@ -405,7 +405,7 @@ Manager::receive_hashing_changed() {
continue; continue;
try { try {
m_download_list->open_throw(*itr); m_download_list->open_throw(itr->get());
// Since the bitfield is allocated on loading of resume load or // Since the bitfield is allocated on loading of resume load or
// hash start, and unallocated on close, we know that if it it // hash start, and unallocated on close, we know that if it it
+40 -16
View File
@@ -16,10 +16,20 @@
namespace core { namespace core {
// Also add focus thingie here? // Also add focus thingie here?
// Matches the list entry that owns a given download.
inline auto
entry_is(Download* download) {
return [download](const std::shared_ptr<Download>& entry) { return entry.get() == download; };
}
struct view_downloads_compare { struct view_downloads_compare {
view_downloads_compare(const torrent::Object& cmd) : view_downloads_compare(const torrent::Object& cmd) :
m_command(cmd) {} m_command(cmd) {}
bool operator()(const std::shared_ptr<Download>& d1, const std::shared_ptr<Download>& d2) const {
return (*this)(d1.get(), d2.get());
}
bool operator()(Download* d1, Download* d2) const { bool operator()(Download* d1, Download* d2) const {
try { try {
if (m_command.is_empty()) if (m_command.is_empty())
@@ -54,6 +64,10 @@ struct view_downloads_filter {
view_downloads_filter(const torrent::Object& cmd, const torrent::Object& cmd2) : view_downloads_filter(const torrent::Object& cmd, const torrent::Object& cmd2) :
m_command(cmd), m_command2(cmd2) {} m_command(cmd), m_command2(cmd2) {}
bool operator()(const std::shared_ptr<Download>& d1) const {
return (*this)(d1.get());
}
bool operator()(Download* d1) const { bool operator()(Download* d1) const {
return this->evalCmd(m_command, d1) && this->evalCmd(m_command2, d1); return this->evalCmd(m_command, d1) && this->evalCmd(m_command2, d1);
} }
@@ -152,7 +166,7 @@ View::initialize(const std::string& name) {
void void
View::erase(Download* download) { View::erase(Download* download) {
iterator itr = std::find(base_type::begin(), base_type::end(), download); iterator itr = std::find_if(base_type::begin(), base_type::end(), entry_is(download));
if (itr >= end_visible()) { if (itr >= end_visible()) {
erase_internal(itr); erase_internal(itr);
@@ -165,22 +179,24 @@ View::erase(Download* download) {
void void
View::set_visible(Download* download) { View::set_visible(Download* download) {
iterator itr = std::find(begin_filtered(), end_filtered(), download); iterator itr = std::find_if(begin_filtered(), end_filtered(), entry_is(download));
if (itr == end_filtered()) if (itr == end_filtered())
return; return;
// Don't optimize erase since we want to keep the order of the // Don't optimize erase since we want to keep the order of the
// non-visible elements. // non-visible elements.
auto entry = *itr;
base_type::erase(itr); base_type::erase(itr);
insert_visible(download); insert_visible(entry);
rpc::call_object_nothrow(m_event_added, rpc::make_target(download)); rpc::call_object_nothrow(m_event_added, rpc::make_target(download));
} }
void void
View::set_not_visible(Download* download) { View::set_not_visible(Download* download) {
iterator itr = std::find(begin_visible(), end_visible(), download); iterator itr = std::find_if(begin_visible(), end_visible(), entry_is(download));
if (itr == end_visible()) if (itr == end_visible())
return; return;
@@ -190,8 +206,10 @@ View::set_not_visible(Download* download) {
// Don't optimize erase since we want to keep the order of the // Don't optimize erase since we want to keep the order of the
// non-visible elements. // non-visible elements.
auto entry = *itr;
base_type::erase(itr); base_type::erase(itr);
base_type::push_back(download); base_type::push_back(entry);
rpc::call_object_nothrow(m_event_removed, rpc::make_target(download)); rpc::call_object_nothrow(m_event_removed, rpc::make_target(download));
} }
@@ -241,12 +259,12 @@ View::prev_focus(unsigned int i) {
void void
View::sort() { View::sort() {
Download* curFocus = focus() != end_visible() ? *focus() : NULL; Download* curFocus = focus() != end_visible() ? focus()->get() : NULL;
// Don't go randomly switching around equivalent elements. // Don't go randomly switching around equivalent elements.
std::stable_sort(begin(), end_visible(), view_downloads_compare(m_sortCurrent)); std::stable_sort(begin(), end_visible(), view_downloads_compare(m_sortCurrent));
m_focus = position(std::find(begin(), end_visible(), curFocus)); m_focus = position(std::find_if(begin(), end_visible(), entry_is(curFocus)));
emit_changed(); emit_changed();
} }
@@ -280,10 +298,10 @@ View::filter() {
// set the elements to NULL as we trigger commands on them. Or // set the elements to NULL as we trigger commands on them. Or
// perhaps always clear them, thus not throwing anything. // perhaps always clear them, thus not throwing anything.
if (!m_event_removed.is_empty()) if (!m_event_removed.is_empty())
std::for_each(changed.begin(), splitChanged, std::bind(&rpc::call_object_d_nothrow, m_event_removed, std::placeholders::_1)); std::for_each(changed.begin(), splitChanged, [this](const auto& d) { rpc::call_object_d_nothrow(m_event_removed, d.get()); });
if (!m_event_added.is_empty()) if (!m_event_added.is_empty())
std::for_each(changed.begin(), splitChanged, std::bind(&rpc::call_object_d_nothrow, m_event_added, std::placeholders::_1)); std::for_each(changed.begin(), splitChanged, [this](const auto& d) { rpc::call_object_d_nothrow(m_event_added, d.get()); });
emit_changed(); emit_changed();
} }
@@ -294,21 +312,23 @@ View::filter_by(const torrent::Object& condition, View::base_type& result) {
view_downloads_filter matches = view_downloads_filter(condition, m_temp_filter); view_downloads_filter matches = view_downloads_filter(condition, m_temp_filter);
for (iterator itr = begin_visible(); itr != end_visible(); ++itr) for (iterator itr = begin_visible(); itr != end_visible(); ++itr)
if (matches(*itr)) if (matches(itr->get()))
result.push_back(*itr); result.push_back(*itr);
} }
void void
View::filter_download(core::Download* download) { View::filter_download(core::Download* download) {
iterator itr = std::find(base_type::begin(), base_type::end(), download); iterator itr = std::find_if(base_type::begin(), base_type::end(), entry_is(download));
if (itr == base_type::end()) if (itr == base_type::end())
throw torrent::internal_error("View::filter_download(...) could not find download."); throw torrent::internal_error("View::filter_download(...) could not find download.");
if (view_downloads_filter(m_filter, m_temp_filter)(download)) { if (view_downloads_filter(m_filter, m_temp_filter)(download)) {
if (itr >= end_visible()) { if (itr >= end_visible()) {
auto entry = *itr;
erase_internal(itr); erase_internal(itr);
insert_visible(download); insert_visible(entry);
rpc::call_object_nothrow(m_event_added, rpc::make_target(download)); rpc::call_object_nothrow(m_event_added, rpc::make_target(download));
@@ -317,16 +337,20 @@ View::filter_download(core::Download* download) {
// already visible. // already visible.
// //
// Consider removing this. // Consider removing this.
auto entry = *itr;
erase_internal(itr); erase_internal(itr);
insert_visible(download); insert_visible(entry);
} }
} else { } else {
if (itr >= end_visible()) if (itr >= end_visible())
return; return;
auto entry = *itr;
erase_internal(itr); erase_internal(itr);
base_type::push_back(download); base_type::push_back(entry);
rpc::call_object_nothrow(m_event_removed, rpc::make_target(download)); rpc::call_object_nothrow(m_event_removed, rpc::make_target(download));
} }
@@ -345,8 +369,8 @@ View::clear_filter_on() {
} }
inline void inline void
View::insert_visible(Download* d) { View::insert_visible(const std::shared_ptr<Download>& d) {
auto itr = std::find_if(begin_visible(), end_visible(), [this, d](auto d2) { return view_downloads_compare(m_sortNew)(d, d2); }); auto itr = std::find_if(begin_visible(), end_visible(), [this, &d](const auto& d2) { return view_downloads_compare(m_sortNew)(d.get(), d2.get()); });
m_size++; m_size++;
m_focus += (m_focus >= position(itr)); m_focus += (m_focus >= position(itr));
+6 -5
View File
@@ -15,6 +15,7 @@
#include <functional> #include <functional>
#include <list> #include <list>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <torrent/object.h> #include <torrent/object.h>
@@ -26,9 +27,9 @@ namespace core {
class Download; class Download;
class View : private std::vector<Download*> { class View : private std::vector<std::shared_ptr<Download>> {
public: public:
typedef std::vector<Download*> base_type; typedef std::vector<std::shared_ptr<Download>> base_type;
typedef std::function<void()> slot_void; typedef std::function<void()> slot_void;
typedef std::list<slot_void> signal_void; typedef std::list<slot_void> signal_void;
@@ -72,7 +73,7 @@ public:
emit_changed(); emit_changed();
} }
void insert(Download* download) { base_type::push_back(download); } void insert(const std::shared_ptr<Download>& download) { base_type::push_back(download); }
void erase(Download* download); void erase(Download* download);
void set_visible(Download* download); void set_visible(Download* download);
@@ -124,9 +125,9 @@ private:
View(const View&); View(const View&);
void operator=(const View&); void operator=(const View&);
void push_back(Download* d) { base_type::push_back(d); } void push_back(const std::shared_ptr<Download>& d) { base_type::push_back(d); }
inline void insert_visible(Download* d); inline void insert_visible(const std::shared_ptr<Download>& d);
inline void erase_internal(iterator itr); inline void erase_internal(iterator itr);
void emit_changed(); void emit_changed();
+5 -5
View File
@@ -37,7 +37,7 @@ WindowDownloadList::set_view(core::View* l) {
// Return a pair of ints, representing a) the ncurses attributes and b) the ncurses color pair ID to use // Return a pair of ints, representing a) the ncurses attributes and b) the ncurses color pair ID to use
std::pair<int, int> std::pair<int, int>
WindowDownloadList::get_attr_color(core::View::iterator selected) { WindowDownloadList::get_attr_color(core::View::iterator selected) {
core::Download* item = *selected; core::Download* item = selected->get();
unsigned long focus_attr = selected == m_view->focus() ? m_canvas->attr_map().at(RCOLOR_FOCUS) : 0; unsigned long focus_attr = selected == m_view->focus() ? m_canvas->attr_map().at(RCOLOR_FOCUS) : 0;
int offset = (((selected - m_view->begin_visible()) & 1) + 1) * RCOLOR_MAX; // Determine the even/odd offset for the color pair int offset = (((selected - m_view->begin_visible()) & 1) + 1) * RCOLOR_MAX; // Determine the even/odd offset for the color pair
bool active = item->is_open() && item->is_active(); bool active = item->is_open() && item->is_active();
@@ -132,15 +132,15 @@ WindowDownloadList::redraw() {
ColorKind focus_color = is_focused ? RCOLOR_FOCUS : RCOLOR_LABEL; ColorKind focus_color = is_focused ? RCOLOR_FOCUS : RCOLOR_LABEL;
auto attr_color = get_attr_color(range.first); auto attr_color = get_attr_color(range.first);
print_download_title(buffer.data(), last, *range.first); print_download_title(buffer.data(), last, range.first->get());
m_canvas->print(0, pos, "%c %s", focus_char, buffer.data()); m_canvas->print(0, pos, "%c %s", focus_char, buffer.data());
m_canvas->set_attr(2, pos++, -1, attr_color.first, attr_color.second); m_canvas->set_attr(2, pos++, -1, attr_color.first, attr_color.second);
print_download_info_full(buffer.data(), last, *range.first); print_download_info_full(buffer.data(), last, range.first->get());
m_canvas->print(0, pos, "%c %s", focus_char, buffer.data()); m_canvas->print(0, pos, "%c %s", focus_char, buffer.data());
m_canvas->set_attr(2, pos++, -1, focus_color); m_canvas->set_attr(2, pos++, -1, focus_color);
print_download_status(buffer.data(), last, *range.first); print_download_status(buffer.data(), last, range.first->get());
m_canvas->print(0, pos, "%c %s", focus_char, buffer.data()); m_canvas->print(0, pos, "%c %s", focus_char, buffer.data());
m_canvas->set_attr(2, pos++, -1, focus_color); m_canvas->set_attr(2, pos++, -1, focus_color);
@@ -152,7 +152,7 @@ WindowDownloadList::redraw() {
char focus_char = range.first == m_view->focus() ? '*' : ' '; char focus_char = range.first == m_view->focus() ? '*' : ' ';
auto attr_color = get_attr_color(range.first); auto attr_color = get_attr_color(range.first);
print_download_info_compact(buffer.data(), last, *range.first); print_download_info_compact(buffer.data(), last, range.first->get());
m_canvas->print(0, pos, "%c %s", focus_char, buffer.data()); m_canvas->print(0, pos, "%c %s", focus_char, buffer.data());
m_canvas->set_attr(2, pos++, -1, attr_color.first, attr_color.second); m_canvas->set_attr(2, pos++, -1, attr_color.first, attr_color.second);
+5
View File
@@ -1,6 +1,7 @@
#ifndef RTORRENT_RPC_COMMAND_MAP_H #ifndef RTORRENT_RPC_COMMAND_MAP_H
#define RTORRENT_RPC_COMMAND_MAP_H #define RTORRENT_RPC_COMMAND_MAP_H
#include <memory>
#include <map> #include <map>
#include <string> #include <string>
#include <cstring> #include <cstring>
@@ -104,6 +105,10 @@ inline target_type make_target(T target) {
return target_type((int)target_type_id<T>::value, target); return target_type((int)target_type_id<T>::value, target);
} }
inline target_type make_target(const std::shared_ptr<core::Download>& target) {
return make_target(target.get());
}
template <typename T> template <typename T>
inline target_type make_target_pair(T target1, T target2) { inline target_type make_target_pair(T target1, T target2) {
return target_type((int)target_type_id<T, T>::value, target1, target2); return target_type((int)target_type_id<T, T>::value, target1, target2);
+5 -2
View File
@@ -1,3 +1,4 @@
#include <memory>
#include "config.h" #include "config.h"
#include <cassert> #include <cassert>
@@ -30,8 +31,10 @@
namespace ui { namespace ui {
Download::Download(core::Download* d) Download::Download(const std::shared_ptr<core::Download>& download)
: m_download(d) { : m_download(download.get()) {
auto* d = download.get();
m_windowDownloadStatus = std::make_unique<WDownloadStatus>(d); m_windowDownloadStatus = std::make_unique<WDownloadStatus>(d);
m_windowDownloadStatus->set_bottom(true); m_windowDownloadStatus->set_bottom(true);
+2 -1
View File
@@ -2,6 +2,7 @@
#define RTORRENT_UI_DOWNLOAD_H #define RTORRENT_UI_DOWNLOAD_H
#include <list> #include <list>
#include <memory>
#include <torrent/peer/peer.h> #include <torrent/peer/peer.h>
#include "display/manager.h" #include "display/manager.h"
@@ -36,7 +37,7 @@ public:
DISPLAY_MAX_SIZE DISPLAY_MAX_SIZE
} Display; } Display;
Download(core::Download* d); Download(const std::shared_ptr<core::Download>& d);
~Download(); ~Download();
void activate(display::Frame* frame, bool focus = true); void activate(display::Frame* frame, bool focus = true);
+1 -1
View File
@@ -89,7 +89,7 @@ DownloadList::unfocus_download(core::Download* d) {
if (m_state == DISPLAY_DOWNLOAD && d == static_cast<Download*>(m_uiArray[DISPLAY_DOWNLOAD])->download()) if (m_state == DISPLAY_DOWNLOAD && d == static_cast<Download*>(m_uiArray[DISPLAY_DOWNLOAD])->download())
activate_display(DISPLAY_DOWNLOAD_LIST); activate_display(DISPLAY_DOWNLOAD_LIST);
if (current_view()->focus() < current_view()->end_visible() && *current_view()->focus() == d) if (current_view()->focus() < current_view()->end_visible() && current_view()->focus()->get() == d)
current_view()->next_focus(); current_view()->next_focus();
} }
+1 -1
View File
@@ -196,7 +196,7 @@ ElementDownloadList::receive_cycle_throttle() {
if (m_view->focus() == m_view->end_visible()) if (m_view->focus() == m_view->end_visible())
return; return;
core::Download* download = *m_view->focus(); core::Download* download = m_view->focus()->get();
if (download->is_active()) { if (download->is_active()) {
lt_log_print(torrent::LOG_TORRENT_WARN, "Cannot change throttle on active download."); lt_log_print(torrent::LOG_TORRENT_WARN, "Cannot change throttle on active download.");
return; return;