diff --git a/src/slic3r/GUI/CAD/McpControl.cpp b/src/slic3r/GUI/CAD/McpControl.cpp index 9004ab934c..81f22ecfef 100644 --- a/src/slic3r/GUI/CAD/McpControl.cpp +++ b/src/slic3r/GUI/CAD/McpControl.cpp @@ -1990,9 +1990,12 @@ json action_set_feature_expr(DesignPanel* panel, const json& params) std::string handle_on_main(const std::string& method, const json& params, const json& id) { MainFrame* mf = wxGetApp().mainframe; - if (!mf || !mf->m_design_panel) + // The panel is built on first use, and in a headless session nobody clicks the tab that + // would build it -- so build it here rather than refusing. Safe: this runs on the main + // thread (see the CallAfter that dispatches us). + DesignPanel* panel = mf ? mf->ensure_design_panel() : nullptr; + if (!panel) return rpc_error(id, -32001, "Design panel not ready"); - DesignPanel* panel = mf->m_design_panel; // Stale-id guard, checked here rather than in each handler. // diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 4490cbe2bb..101715dea7 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1245,6 +1245,19 @@ void MainFrame::show_option(bool show) } } +#ifdef SLIC3R_CAD +DesignPanel* MainFrame::ensure_design_panel() +{ + if (m_design_panel == nullptr && m_design_page != nullptr) { + wxBusyCursor busy; + m_design_panel = new DesignPanel(m_design_page); + m_design_page->GetSizer()->Add(m_design_panel, 1, wxEXPAND); + m_design_page->Layout(); + } + return m_design_panel; +} +#endif + void MainFrame::init_tabpanel() { // wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on // Windows 10 with multiple high resolution displays connected. @@ -1290,12 +1303,7 @@ void MainFrame::init_tabpanel() { // Built on first activation, never at startup: the panel creates several hundred // controls and its own GL canvas, which a user who does not open the tab should // not pay for. - if (m_design_panel == nullptr) { - wxBusyCursor busy; - m_design_panel = new DesignPanel(m_design_page); - m_design_page->GetSizer()->Add(m_design_panel, 1, wxEXPAND); - m_design_page->Layout(); - } + ensure_design_panel(); // Re-sync the Design bed to the active printer: the panel is built before the // printer profile is fully applied, so its bed must refresh on activation or the // grid (true bed) spills past the stale default bed quad. diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 8578ed87b5..b647acfadd 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -391,6 +391,11 @@ public: // selected, so everything the Design panel builds stays off the startup path. wxPanel* m_design_page { nullptr }; DesignPanel* m_design_panel { nullptr }; + // Builds the Design panel if it does not exist yet and returns it (null only before the + // placeholder page itself exists). Main thread only -- it creates wx controls. Both the + // tab activation and the MCP socket go through this: the socket is driven headlessly, + // with nobody to click the tab, and without this every verb would answer "not ready". + DesignPanel* ensure_design_panel(); #endif //BBS: GUI refactor MonitorPanel* m_monitor{ nullptr };