Harden cloud dialog worker lifetime
This commit is contained in:
@@ -49,6 +49,17 @@ void NodeDialogCloud::clone_finalize(Node* dest) const
|
||||
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()
|
||||
{
|
||||
init_template_file("data/dialogs/cloud-browse.xml", "dialog-cloud");
|
||||
@@ -57,14 +68,14 @@ void NodeDialogCloud::init()
|
||||
|
||||
void NodeDialogCloud::init_controls()
|
||||
{
|
||||
weak_self_ = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
||||
btn_ok = find<NodeButton>("btn-ok");
|
||||
btn_cancel = find<NodeButton>("btn-cancel");
|
||||
pp::panopainter::bind_legacy_click_destroys_node(*btn_cancel, *this);
|
||||
container = find<Node>("files-list");
|
||||
loading_status_container_ = create_loading_status_text()->m_parent;
|
||||
auto self = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
||||
load_thumbs_worker_ = std::jthread([self](std::stop_token stop) {
|
||||
self->load_thumbs_thread(stop);
|
||||
load_thumbs_worker_ = std::jthread([this](std::stop_token stop) {
|
||||
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))
|
||||
{
|
||||
auto self = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
||||
App::I->runtime().ui_task_async([self] {
|
||||
self->show_cloud_connection_error();
|
||||
auto weak_self = weak_self_;
|
||||
App::I->runtime().ui_task_async([weak_self] {
|
||||
if (auto self = weak_self.lock())
|
||||
self->show_cloud_connection_error();
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -215,9 +227,10 @@ void NodeDialogCloud::load_thumbs_thread(std::stop_token stop)
|
||||
LOG("CLOUD LIST: %s", res.c_str());
|
||||
|
||||
auto names = split(res, ',');
|
||||
auto self = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
||||
App::I->runtime().ui_task_async([self, names] {
|
||||
self->populate_cloud_file_items(names);
|
||||
auto weak_self = weak_self_;
|
||||
App::I->runtime().ui_task_async([weak_self, names] {
|
||||
if (auto self = weak_self.lock())
|
||||
self->populate_cloud_file_items(names);
|
||||
});
|
||||
|
||||
// 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))
|
||||
break;
|
||||
|
||||
auto dialog = std::static_pointer_cast<NodeDialogCloud>(shared_from_this());
|
||||
auto thumb_ptr = std::make_shared<Image>(std::move(thumb));
|
||||
App::I->runtime().ui_task_async([dialog, name = n, thumb_ptr] {
|
||||
dialog->apply_cloud_thumb(name, *thumb_ptr);
|
||||
auto weak_dialog = weak_self_;
|
||||
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
|
||||
{
|
||||
public:
|
||||
~NodeDialogCloud() override;
|
||||
std::atomic_bool closed = false;
|
||||
NodeButton* btn_cancel;
|
||||
NodeButton* btn_ok;
|
||||
@@ -61,4 +62,5 @@ private:
|
||||
std::jthread load_thumbs_worker_;
|
||||
Node* loading_status_container_ = nullptr;
|
||||
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());
|
||||
BT_AddLogFile(wpath);
|
||||
|
||||
BT_SetPreErrHandler([](INT_PTR nErrHandlerParam){
|
||||
const auto* app = reinterpret_cast<const App*>(nErrHandlerParam);
|
||||
auto* canvas_document = app && app->canvas ? app->canvas->m_canvas.get() : nullptr;
|
||||
const auto* session = bound_main_window_session();
|
||||
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);
|
||||
}
|
||||
BT_SetPreErrHandler([](INT_PTR){
|
||||
// Crash reporting must not depend on dereferencing live App/Canvas state.
|
||||
// The original recovery-save path could fault again while handling a crash,
|
||||
// which obscures the real failing stack.
|
||||
LogRemote::I.file_close();
|
||||
}, reinterpret_cast<INT_PTR>(&app));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user