fix: crash on windows

This commit is contained in:
peachismomo
2026-08-06 06:08:02 +08:00
parent acb0be6ed9
commit ef4815b26c
4 changed files with 67 additions and 14 deletions

View File

@@ -1110,6 +1110,8 @@ void MainFrame::update_edge_panels()
void MainFrame::shutdown() void MainFrame::shutdown()
{ {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "MainFrame::shutdown enter"; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "MainFrame::shutdown enter";
if (m_project != nullptr)
m_project->shutdown();
m_plugin_pages.shutdown(); m_plugin_pages.shutdown();
#ifdef __WXGTK__ #ifdef __WXGTK__
// Edge panels are child windows — wxWidgets destroys them automatically. // Edge panels are child windows — wxWidgets destroys them automatically.

View File

@@ -74,7 +74,18 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos,
Fit(); 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 <br> // Helper to convert newlines to <br>
static std::string convert_newlines_to_br(const std::string& text) { 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) 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<boost::thread>([this, cancel_token] {
if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing())
return;
std::string update_type; std::string update_type;
std::string license; std::string license;
std::string model_name; std::string model_name;
@@ -115,6 +136,9 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
std::map<std::string, std::vector<json>> files; std::map<std::string, std::vector<json>> files;
if (wxGetApp().plater() == nullptr)
return;
Model model = wxGetApp().plater()->model(); Model model = wxGetApp().plater()->model();
auto model_info = model.model_info; 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()); std::string file_path = encode_path(wxGetApp().plater()->model().get_auxiliary_file_temp_path().c_str());
if (!file_path.empty()) { if (!file_path.empty()) {
files = Reload(file_path); 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 { } else {
clear_model_info(); clear_model_info();
return; return;
@@ -215,15 +246,18 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
json m_Res = json::object(); json m_Res = json::object();
m_Res["command"] = "show_3mf_info"; 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; m_Res["model"] = j;
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore)); wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore));
if (m_web_init_completed) { if (m_web_init_completed.load(std::memory_order_acquire) &&
wxGetApp().CallAfter([this, strJS] { !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()); RunScript(strJS.ToStdString());
}); });
} }
}); });
} }
@@ -264,7 +298,7 @@ void ProjectPanel::OnScriptMessage(wxWebViewEvent& evt)
} }
} }
else if (strCmd == "request_3mf_info") { 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") { else if (strCmd == "edit_project_info") {
show_info_editor(true); show_info_editor(true);
@@ -307,13 +341,20 @@ void ProjectPanel::update_model_data()
void ProjectPanel::clear_model_info() 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(); json m_Res = json::object();
m_Res["command"] = "clear_3mf_info"; 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)); 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()); RunScript(strJS.ToStdString());
}); });
} }

View File

@@ -26,9 +26,11 @@
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "slic3r/Utils/json_diff.hpp" #include "slic3r/Utils/json_diff.hpp"
#include <atomic>
#include <map> #include <map>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <boost/thread.hpp>
#include "Event.hpp" #include "Event.hpp"
#include "libslic3r/ProjectTask.hpp" #include "libslic3r/ProjectTask.hpp"
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
@@ -60,14 +62,17 @@ struct project_file{
class ProjectPanel : public wxPanel class ProjectPanel : public wxPanel
{ {
private: private:
bool m_web_init_completed = {false}; std::atomic<bool> m_web_init_completed{false};
bool m_reload_already = {false}; bool m_reload_already = {false};
std::shared_ptr<std::atomic<bool>> m_reload_cancel_token{std::make_shared<std::atomic<bool>>(false)};
std::unique_ptr<boost::thread> m_reload_task;
wxWebView* m_browser = {nullptr}; wxWebView* m_browser = {nullptr};
AuxiliaryPanel* m_auxiliary{nullptr}; AuxiliaryPanel* m_auxiliary{nullptr};
wxString m_project_home_url; wxString m_project_home_url;
wxString m_root_dir; wxString m_root_dir;
static inline int m_sequence_id = 8000; static inline std::atomic<int> m_sequence_id{8000};
void show_info_editor(bool show); void show_info_editor(bool show);
@@ -75,6 +80,7 @@ private:
public: public:
ProjectPanel(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxTAB_TRAVERSAL); ProjectPanel(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxTAB_TRAVERSAL);
~ProjectPanel(); ~ProjectPanel();
void shutdown();
void onWebNavigating(wxWebViewEvent& evt); void onWebNavigating(wxWebViewEvent& evt);

View File

@@ -8477,8 +8477,12 @@ void Page::activate(ConfigOptionMode mode, std::function<void()> throw_if_cancel
#ifdef __WXMSW__ #ifdef __WXMSW__
// BBS: fix field control position // BBS: fix field control position
wxTheApp->CallAfter([this]() { wxTheApp->CallAfter([wp = std::weak_ptr<Page>(shared_from_this())]() {
for (auto group : m_optgroups) { auto page = wp.lock();
if (!page)
return;
for (auto group : page->m_optgroups) {
if (group->custom_ctrl) if (group->custom_ctrl)
group->custom_ctrl->fixup_items_positions(); group->custom_ctrl->fixup_items_positions();
} }