Device tab blank for webui printers after switching language (#14547)

* Save device url in all cases and load printer url after hot-reload finishes

* Recreate web view from scratch as only URL fix seems not robust enough

* Add the same robust browser recreation for WebViewDialog

It should eliminate possible issue with blank Home and other pages
in the same way as Printer page

* Remove redundant fallback leftover

* Fix webview reset state and replay Project info on page reload

The first-show webview reset now runs only on Windows, reloads the last
printer URL and resets the Project page's ready state. The Project tab
replays its 3MF info whenever the page reloads, so it no longer goes
blank after a theme switch or a slow first load. The Device tab no longer
loads an extra time on first open, and the Home tab no longer navigates
twice. NeedsRecreateOnShow() logs is_recreating_gui so one language
switch shows whether the reset ever fires.

* Build plugin pages on first show

A language switch rebuilt every plugin page's browser while the main
window was being recreated, which left plugin tabs blank on Windows.
Plugin pages are now lazy pages, never prebuilt, and are removed left
to right so removing pages never builds one only to destroy it.

A plugin page's script now starts when its tab is first opened;
messages posted before that are dropped.

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
Co-authored-by: SoftFever <103989404+SoftFever@users.noreply.github.com>
This commit is contained in:
ExPikaPaka
2026-10-03 20:06:50 +08:00
committed by GitHub
co-authored by SoftFever Noisyfox SoftFever
parent 8a6377f087
commit a6dbf2502d
13 changed files with 203 additions and 76 deletions
+34 -13
View File
@@ -80,16 +80,10 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos,
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
m_browser = WebView::CreateWebView(this, m_project_home_url);
if (m_browser == nullptr) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("load web view of project page failed");
return;
}
create_browser();
m_reset_on_show = WebView::NeedsRecreateOnShow();
//m_browser->Hide();
main_sizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
m_browser->Bind(wxEVT_WEBVIEW_NAVIGATED, &ProjectPanel::on_navigated, this);
m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ProjectPanel::OnScriptMessage, this, m_browser->GetId());
Bind(wxEVT_WEBVIEW_NAVIGATING, &ProjectPanel::onWebNavigating, this, m_browser->GetId());
Bind(EVT_PROJECT_RELOAD, &ProjectPanel::on_reload, this);
@@ -117,6 +111,23 @@ void ProjectPanel::shutdown()
m_reload_task.reset();
}
void ProjectPanel::create_browser()
{
m_browser = WebView::CreateWebView(this, m_project_home_url);
m_browser->Bind(wxEVT_WEBVIEW_NAVIGATED, &ProjectPanel::on_navigated, this);
m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ProjectPanel::OnScriptMessage, this, m_browser->GetId());
m_browser->Bind(wxEVT_WEBVIEW_NAVIGATING, &ProjectPanel::onWebNavigating, this);
}
void ProjectPanel::reset_browser()
{
m_browser->Destroy(); // also removes it from the sizer
create_browser();
GetSizer()->Insert(0, m_browser, wxSizerFlags().Expand().Proportion(1));
Layout();
m_web_init_completed.store(false, std::memory_order_release);
}
// Helper to convert newlines to <br>
static std::string convert_newlines_to_br(const std::string& text) {
std::string result = text;
@@ -281,12 +292,13 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore));
if (m_web_init_completed.load(std::memory_order_acquire) &&
!cancel_token->load(std::memory_order_acquire) && wxTheApp != nullptr && !wxGetApp().is_closing()) {
if (!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());
m_info_script = strJS.ToStdString();
if (m_web_init_completed.load(std::memory_order_acquire))
RunScript(m_info_script);
});
}
});
@@ -327,6 +339,11 @@ void ProjectPanel::OnScriptMessage(wxWebViewEvent& evt)
}
else if (strCmd == "request_3mf_info") {
m_web_init_completed.store(true, std::memory_order_release);
// Replay the stored info after each page load.
CallAfter([this] {
if (!m_info_script.empty())
RunScript(m_info_script);
});
}
else if (strCmd == "edit_project_info") {
show_info_editor(true);
@@ -383,6 +400,8 @@ void ProjectPanel::clear_model_info()
wxGetApp().CallAfter([this, cancel_token, strJS] {
if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing())
return;
// Runs after any store queued by an earlier reload pass, so stale info is never replayed.
m_info_script.clear();
RunScript(strJS.ToStdString());
});
}
@@ -523,10 +542,12 @@ void ProjectPanel::RunScript(std::string content)
WebView::RunScript(m_browser, content);
}
bool ProjectPanel::Show(bool show)
bool ProjectPanel::Show(bool show)
{
if (show && std::exchange(m_reset_on_show, false))
reset_browser();
if (show) update_model_data();
return wxPanel::Show(show);
return wxPanel::Show(show);
}
}} // namespace Slic3r::GUI