Harden cloud dialog worker lifetime
This commit is contained in:
@@ -49,6 +49,17 @@ void NodeDialogCloud::clone_finalize(Node* dest) const
|
|||||||
n->init_controls();
|
n->init_controls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeDialogCloud::~NodeDialogCloud()
|
||||||
|
{
|
||||||
|
closed.store(true, std::memory_order_release);
|
||||||
|
if (load_thumbs_worker_.joinable())
|
||||||
|
{
|
||||||
|
load_thumbs_worker_.request_stop();
|
||||||
|
if (load_thumbs_worker_.get_id() != std::this_thread::get_id())
|
||||||
|
load_thumbs_worker_.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NodeDialogCloud::init()
|
void NodeDialogCloud::init()
|
||||||
{
|
{
|
||||||
init_template_file("data/dialogs/cloud-browse.xml", "dialog-cloud");
|
init_template_file("data/dialogs/cloud-browse.xml", "dialog-cloud");
|
||||||
@@ -57,14 +68,14 @@ void NodeDialogCloud::init()
|
|||||||
|
|
||||||
void NodeDialogCloud::init_controls()
|
void NodeDialogCloud::init_controls()
|
||||||
{
|
{
|
||||||
|
weak_self_ = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
||||||
btn_ok = find<NodeButton>("btn-ok");
|
btn_ok = find<NodeButton>("btn-ok");
|
||||||
btn_cancel = find<NodeButton>("btn-cancel");
|
btn_cancel = find<NodeButton>("btn-cancel");
|
||||||
pp::panopainter::bind_legacy_click_destroys_node(*btn_cancel, *this);
|
pp::panopainter::bind_legacy_click_destroys_node(*btn_cancel, *this);
|
||||||
container = find<Node>("files-list");
|
container = find<Node>("files-list");
|
||||||
loading_status_container_ = create_loading_status_text()->m_parent;
|
loading_status_container_ = create_loading_status_text()->m_parent;
|
||||||
auto self = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
load_thumbs_worker_ = std::jthread([this](std::stop_token stop) {
|
||||||
load_thumbs_worker_ = std::jthread([self](std::stop_token stop) {
|
load_thumbs_thread(stop);
|
||||||
self->load_thumbs_thread(stop);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,9 +213,10 @@ void NodeDialogCloud::load_thumbs_thread(std::stop_token stop)
|
|||||||
|
|
||||||
if (!load_cloud_file_list(curl.get(), res))
|
if (!load_cloud_file_list(curl.get(), res))
|
||||||
{
|
{
|
||||||
auto self = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
auto weak_self = weak_self_;
|
||||||
App::I->runtime().ui_task_async([self] {
|
App::I->runtime().ui_task_async([weak_self] {
|
||||||
self->show_cloud_connection_error();
|
if (auto self = weak_self.lock())
|
||||||
|
self->show_cloud_connection_error();
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -215,9 +227,10 @@ void NodeDialogCloud::load_thumbs_thread(std::stop_token stop)
|
|||||||
LOG("CLOUD LIST: %s", res.c_str());
|
LOG("CLOUD LIST: %s", res.c_str());
|
||||||
|
|
||||||
auto names = split(res, ',');
|
auto names = split(res, ',');
|
||||||
auto self = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
auto weak_self = weak_self_;
|
||||||
App::I->runtime().ui_task_async([self, names] {
|
App::I->runtime().ui_task_async([weak_self, names] {
|
||||||
self->populate_cloud_file_items(names);
|
if (auto self = weak_self.lock())
|
||||||
|
self->populate_cloud_file_items(names);
|
||||||
});
|
});
|
||||||
|
|
||||||
// load the icons
|
// load the icons
|
||||||
@@ -230,10 +243,11 @@ void NodeDialogCloud::load_thumbs_thread(std::stop_token stop)
|
|||||||
if (!load_cloud_thumb(curl.get(), n, res, thumb))
|
if (!load_cloud_thumb(curl.get(), n, res, thumb))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto dialog = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
|
||||||
auto thumb_ptr = std::make_shared<Image>(std::move(thumb));
|
auto thumb_ptr = std::make_shared<Image>(std::move(thumb));
|
||||||
App::I->runtime().ui_task_async([dialog, name = n, thumb_ptr] {
|
auto weak_dialog = weak_self_;
|
||||||
dialog->apply_cloud_thumb(name, *thumb_ptr);
|
App::I->runtime().ui_task_async([weak_dialog, name = n, thumb_ptr] {
|
||||||
|
if (auto dialog = weak_dialog.lock())
|
||||||
|
dialog->apply_cloud_thumb(name, *thumb_ptr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public:
|
|||||||
class NodeDialogCloud : public NodeBorder
|
class NodeDialogCloud : public NodeBorder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
~NodeDialogCloud() override;
|
||||||
std::atomic_bool closed = false;
|
std::atomic_bool closed = false;
|
||||||
NodeButton* btn_cancel;
|
NodeButton* btn_cancel;
|
||||||
NodeButton* btn_ok;
|
NodeButton* btn_ok;
|
||||||
@@ -61,4 +62,5 @@ private:
|
|||||||
std::jthread load_thumbs_worker_;
|
std::jthread load_thumbs_worker_;
|
||||||
Node* loading_status_container_ = nullptr;
|
Node* loading_status_container_ = nullptr;
|
||||||
std::unordered_map<std::string, std::weak_ptr<NodeDialogCloudItem>> items_by_name_;
|
std::unordered_map<std::string, std::weak_ptr<NodeDialogCloudItem>> items_by_name_;
|
||||||
|
std::weak_ptr<NodeDialogCloud> weak_self_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -161,25 +161,10 @@ void setup_exception_handler(const App& app)
|
|||||||
std::mbstowcs(wpath, log_file.c_str(), log_file.size());
|
std::mbstowcs(wpath, log_file.c_str(), log_file.size());
|
||||||
BT_AddLogFile(wpath);
|
BT_AddLogFile(wpath);
|
||||||
|
|
||||||
BT_SetPreErrHandler([](INT_PTR nErrHandlerParam){
|
BT_SetPreErrHandler([](INT_PTR){
|
||||||
const auto* app = reinterpret_cast<const App*>(nErrHandlerParam);
|
// Crash reporting must not depend on dereferencing live App/Canvas state.
|
||||||
auto* canvas_document = app && app->canvas ? app->canvas->m_canvas.get() : nullptr;
|
// The original recovery-save path could fault again while handling a crash,
|
||||||
const auto* session = bound_main_window_session();
|
// which obscures the real failing stack.
|
||||||
if (canvas_document && canvas_document->m_unsaved)
|
|
||||||
{
|
|
||||||
auto t = std::time(nullptr);
|
|
||||||
auto tm = *std::localtime(&t);
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S");
|
|
||||||
|
|
||||||
auto path = app->data_path + "/" + app->doc_name + "-recovery (" + oss.str() + ").ppi";
|
|
||||||
canvas_document->project_save_thread(path, false);
|
|
||||||
static char abspath[MAX_PATH];
|
|
||||||
GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL);
|
|
||||||
static char message[4096];
|
|
||||||
snprintf(message, sizeof(message), "File recovered in: %s", abspath);
|
|
||||||
MessageBoxA(session ? session->handle : nullptr, message, "File Recovery", MB_OK | MB_ICONWARNING);
|
|
||||||
}
|
|
||||||
LogRemote::I.file_close();
|
LogRemote::I.file_close();
|
||||||
}, reinterpret_cast<INT_PTR>(&app));
|
}, reinterpret_cast<INT_PTR>(&app));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user