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 #include #include +#include #include "Event.hpp" #include "libslic3r/ProjectTask.hpp" #include "wxExtensions.hpp" @@ -60,14 +62,17 @@ struct project_file{ class ProjectPanel : public wxPanel { private: - bool m_web_init_completed = {false}; + std::atomic m_web_init_completed{false}; bool m_reload_already = {false}; + std::shared_ptr> m_reload_cancel_token{std::make_shared>(false)}; + std::unique_ptr m_reload_task; + wxWebView* m_browser = {nullptr}; AuxiliaryPanel* m_auxiliary{nullptr}; wxString m_project_home_url; wxString m_root_dir; - static inline int m_sequence_id = 8000; + static inline std::atomic m_sequence_id{8000}; void show_info_editor(bool show); @@ -75,6 +80,7 @@ private: public: ProjectPanel(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxTAB_TRAVERSAL); ~ProjectPanel(); + void shutdown(); void onWebNavigating(wxWebViewEvent& evt); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 05631c8afa..469864af46 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -8477,8 +8477,12 @@ void Page::activate(ConfigOptionMode mode, std::function throw_if_cancel #ifdef __WXMSW__ // BBS: fix field control position - wxTheApp->CallAfter([this]() { - for (auto group : m_optgroups) { + wxTheApp->CallAfter([wp = std::weak_ptr(shared_from_this())]() { + auto page = wp.lock(); + if (!page) + return; + + for (auto group : page->m_optgroups) { if (group->custom_ctrl) group->custom_ctrl->fixup_items_positions(); }