diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 9566426c53..5dc1f0ccfc 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -1110,6 +1110,8 @@ void MainFrame::update_edge_panels()
void MainFrame::shutdown()
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "MainFrame::shutdown enter";
+ if (m_project != nullptr)
+ m_project->shutdown();
m_plugin_pages.shutdown();
#ifdef __WXGTK__
// Edge panels are child windows — wxWidgets destroys them automatically.
diff --git a/src/slic3r/GUI/Project.cpp b/src/slic3r/GUI/Project.cpp
index 57410b1202..6d1eb0e180 100644
--- a/src/slic3r/GUI/Project.cpp
+++ b/src/slic3r/GUI/Project.cpp
@@ -74,7 +74,18 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos,
Fit();
}
-ProjectPanel::~ProjectPanel() {}
+ProjectPanel::~ProjectPanel()
+{
+ shutdown();
+}
+
+void ProjectPanel::shutdown()
+{
+ m_reload_cancel_token->store(true, std::memory_order_release);
+ if (m_reload_task && m_reload_task->joinable())
+ m_reload_task->join();
+ m_reload_task.reset();
+}
// Helper to convert newlines to
static std::string convert_newlines_to_br(const std::string& text) {
@@ -101,7 +112,17 @@ void ProjectPanel::onWebNavigating(wxWebViewEvent& evt)
void ProjectPanel::on_reload(wxCommandEvent& evt)
{
- boost::thread reload = boost::thread([this] {
+ if (wxTheApp == nullptr || wxGetApp().is_closing() ||
+ m_reload_cancel_token->load(std::memory_order_acquire))
+ return;
+
+ if (m_reload_task && m_reload_task->joinable())
+ m_reload_task->join();
+
+ const auto cancel_token = m_reload_cancel_token;
+ m_reload_task = std::make_unique([this, cancel_token] {
+ if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
std::string update_type;
std::string license;
std::string model_name;
@@ -115,6 +136,9 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
std::map> files;
+ if (wxGetApp().plater() == nullptr)
+ return;
+
Model model = wxGetApp().plater()->model();
auto model_info = model.model_info;
@@ -156,7 +180,14 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
std::string file_path = encode_path(wxGetApp().plater()->model().get_auxiliary_file_temp_path().c_str());
if (!file_path.empty()) {
files = Reload(file_path);
- wxGetApp().CallAfter([this, file_path, files] { m_auxiliary->Reload(file_path, files); });
+ if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
+
+ wxGetApp().CallAfter([this, cancel_token, file_path, files] {
+ if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
+ m_auxiliary->Reload(file_path, files);
+ });
} else {
clear_model_info();
return;
@@ -215,15 +246,18 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
json m_Res = json::object();
m_Res["command"] = "show_3mf_info";
- m_Res["sequence_id"] = std::to_string(ProjectPanel::m_sequence_id++);
+ m_Res["sequence_id"] = std::to_string(ProjectPanel::m_sequence_id.fetch_add(1, std::memory_order_relaxed));
m_Res["model"] = j;
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore));
- if (m_web_init_completed) {
- wxGetApp().CallAfter([this, strJS] {
+ if (m_web_init_completed.load(std::memory_order_acquire) &&
+ !cancel_token->load(std::memory_order_acquire) && wxTheApp != nullptr && !wxGetApp().is_closing()) {
+ wxGetApp().CallAfter([this, cancel_token, strJS] {
+ if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
RunScript(strJS.ToStdString());
- });
+ });
}
});
}
@@ -264,7 +298,7 @@ void ProjectPanel::OnScriptMessage(wxWebViewEvent& evt)
}
}
else if (strCmd == "request_3mf_info") {
- m_web_init_completed = true;
+ m_web_init_completed.store(true, std::memory_order_release);
}
else if (strCmd == "edit_project_info") {
show_info_editor(true);
@@ -307,13 +341,20 @@ void ProjectPanel::update_model_data()
void ProjectPanel::clear_model_info()
{
+ if (wxTheApp == nullptr || wxGetApp().is_closing() ||
+ m_reload_cancel_token->load(std::memory_order_acquire))
+ return;
+
json m_Res = json::object();
m_Res["command"] = "clear_3mf_info";
- m_Res["sequence_id"] = std::to_string(ProjectPanel::m_sequence_id++);
+ m_Res["sequence_id"] = std::to_string(ProjectPanel::m_sequence_id.fetch_add(1, std::memory_order_relaxed));
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore));
- wxGetApp().CallAfter([this, strJS] {
+ const auto cancel_token = m_reload_cancel_token;
+ wxGetApp().CallAfter([this, cancel_token, strJS] {
+ if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
RunScript(strJS.ToStdString());
});
}
diff --git a/src/slic3r/GUI/Project.hpp b/src/slic3r/GUI/Project.hpp
index 0071685e7d..a41f76ba7e 100644
--- a/src/slic3r/GUI/Project.hpp
+++ b/src/slic3r/GUI/Project.hpp
@@ -26,9 +26,11 @@
#include "nlohmann/json.hpp"
#include "slic3r/Utils/json_diff.hpp"
+#include
#include