Compare commits

...

6 Commits

Author SHA1 Message Date
Noisyfox
0d1dd95303 Merge branch 'main' into fix/device_tab_missing_after_hot_reload_due_to_race_condition 2026-07-13 15:23:25 +08:00
ExPikaPaka
8be0e172c5 Remove redundant fallback leftover 2026-07-06 08:53:39 +02:00
SoftFever
f8bc07b5dd Merge branch 'main' into fix/device_tab_missing_after_hot_reload_due_to_race_condition 2026-07-04 13:31:04 +08:00
ExPikaPaka
6fe99cd2b6 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
2026-07-03 14:04:40 +02:00
ExPikaPaka
359e70d61f Recreate web view from scratch as only URL fix seems not robust enough 2026-07-03 13:29:00 +02:00
ExPikaPaka
fd72249a35 Save device url in all cases and load printer url after hot-reload finishes 2026-07-03 08:17:25 +02:00
6 changed files with 180 additions and 39 deletions

View File

@@ -111,26 +111,14 @@ PrinterWebView::PrinterWebView(wxWindow *parent)
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
// Create the webview
m_browser = WebView::CreateWebView(this, "");
if (m_browser == nullptr) {
wxLogError("Could not init m_browser");
create_browser();
if (m_browser == nullptr)
return;
}
#ifdef __linux__
inject_vue_resize_workaround(m_browser);
auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db");
auto wv = static_cast<WebKitWebView*>(m_browser->GetNativeBackend());
auto wv_ctx = webkit_web_view_get_context(wv);
auto cookieManager = webkit_web_context_get_cookie_manager(wv_ctx);
webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesPath.c_str(), WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
#endif
m_browser->Bind(wxEVT_WEBVIEW_ERROR, &PrinterWebView::OnError, this);
m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrinterWebView::OnLoaded, this);
m_browser->Bind(wxEVT_WEBVIEW_NEWWINDOW, &PrinterWebView::OnNewWindow, this);
m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &PrinterWebView::OnScriptMessage, this);
// A PrinterWebView built during a GUI rebuild (language switch) can come up
// with a wedged WebView2 backend that silently drops every navigation. Flag
// it so we recreate the backend the first time the tab is opened.
m_reset_on_show = wxGetApp().is_recreating_gui();
SetSizer(topsizer);
@@ -169,6 +157,51 @@ PrinterWebView::~PrinterWebView()
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " End";
}
void PrinterWebView::create_browser()
{
m_browser = WebView::CreateWebView(this, "");
if (m_browser == nullptr) {
wxLogError("Could not init m_browser");
return;
}
#ifdef __linux__
inject_vue_resize_workaround(m_browser);
auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db");
auto wv = static_cast<WebKitWebView*>(m_browser->GetNativeBackend());
auto wv_ctx = webkit_web_view_get_context(wv);
auto cookieManager = webkit_web_context_get_cookie_manager(wv_ctx);
webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesPath.c_str(), WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
#endif
m_browser->Bind(wxEVT_WEBVIEW_ERROR, &PrinterWebView::OnError, this);
m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrinterWebView::OnLoaded, this);
m_browser->Bind(wxEVT_WEBVIEW_NEWWINDOW, &PrinterWebView::OnNewWindow, this);
m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &PrinterWebView::OnScriptMessage, this);
}
void PrinterWebView::reset_browser()
{
wxSizer* topsizer = GetSizer();
if (m_browser) {
if (topsizer)
topsizer->Detach(m_browser);
m_browser->Destroy();
m_browser = nullptr;
}
m_apikey_sent = false;
create_browser();
if (m_browser == nullptr)
return;
if (topsizer) {
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
Layout();
}
update_mode();
}
void PrinterWebView::load_url(wxString& url, wxString apikey)
{
// this->Show();
@@ -179,20 +212,26 @@ void PrinterWebView::load_url(wxString& url, wxString apikey)
m_apikey_sent = false;
m_handler = create_printer_webview_handler(*this);
if (this->IsShown()) {
//ORCA: m_url_deferred will be cleared on load success
//m_url_deferred.clear();
// Always remember the requested URL as a fallback. If the immediate load
// below is dropped (e.g. the webview backend is not ready yet right after
// recreate_GUI on a language switch), Show() will retry it. OnLoaded clears
// m_url_deferred once the page actually finishes loading.
m_url_deferred = url;
if (this->IsShown())
m_browser->LoadURL(url);
} else {
m_url_deferred = url;
}
//m_browser->SetFocus();
UpdateState();
}
bool PrinterWebView::Show(bool show)
{
if (show && !m_url_deferred.empty()) {
// Recover from a wedged WebView2 backend created during a GUI rebuild by
// recreating the control the first time the tab is actually opened.
if (show && m_reset_on_show) {
m_reset_on_show = false;
reset_browser();
}
if (show && !m_url_deferred.empty() && m_browser) {
m_browser->LoadURL(m_url_deferred);
//ORCA: m_url_deferred will be cleared on load success
//m_url_deferred.clear();

View File

@@ -55,6 +55,13 @@ private:
friend class PrinterWebViewHandler;
void SendAPIKey();
// Create/configure the underlying wxWebView (m_browser) and bind its events.
void create_browser();
// Tear down and recreate m_browser from scratch. Used to recover from a
// wedged WebView2 backend after a recreate_GUI (language switch), where a
// control created while the previous frame's active webview is still alive
// silently ignores all navigations.
void reset_browser();
wxWebView* m_browser;
long m_zoomFactor;
@@ -62,6 +69,10 @@ private:
bool m_apikey_sent;
wxString m_url_deferred;
std::unique_ptr<PrinterWebViewHandler> m_handler;
// When this view is constructed during a GUI rebuild, its WebView2 backend
// may come up wedged. Recreate it the first time the view is actually shown
// (by then the old frame is gone and creation is clean).
bool m_reset_on_show{false};
// DECLARE_EVENT_TABLE()
};

View File

@@ -51,16 +51,12 @@ 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");
create_browser();
if (m_browser == nullptr)
return;
}
m_reset_on_show = wxGetApp().is_recreating_gui();
//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);
@@ -76,6 +72,36 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos,
ProjectPanel::~ProjectPanel() {}
void ProjectPanel::create_browser()
{
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;
}
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());
}
void ProjectPanel::reset_browser()
{
wxSizer* sizer = GetSizer();
if (m_browser) {
if (sizer)
sizer->Detach(m_browser);
m_browser->Destroy();
m_browser = nullptr;
}
create_browser();
if (m_browser == nullptr)
return;
if (sizer) {
sizer->Insert(0, m_browser, wxSizerFlags().Expand().Proportion(1));
Layout();
}
}
// Helper to convert newlines to <br>
static std::string convert_newlines_to_br(const std::string& text) {
std::string result = text;
@@ -454,10 +480,16 @@ void ProjectPanel::RunScript(std::string content)
WebView::RunScript(m_browser, content);
}
bool ProjectPanel::Show(bool show)
bool ProjectPanel::Show(bool show)
{
// Recover from a wedged WebView2 backend created during a GUI rebuild by
// recreating the control the first time the panel is actually shown.
if (show && m_reset_on_show) {
m_reset_on_show = false;
reset_browser();
}
if (show) update_model_data();
return wxPanel::Show(show);
return wxPanel::Show(show);
}
}} // namespace Slic3r::GUI

View File

@@ -68,8 +68,15 @@ private:
wxString m_project_home_url;
wxString m_root_dir;
static inline int m_sequence_id = 8000;
// Set when this panel is built during a GUI rebuild (language switch), where
// the WebView2 backend can come up wedged. Recreate it on first show.
bool m_reset_on_show = {false};
void show_info_editor(bool show);
// Create/configure m_browser (create + bind events + load the home url).
void create_browser();
// Tear down and recreate m_browser to recover from a wedged backend.
void reset_browser();
public:

View File

@@ -40,6 +40,7 @@ WebViewPanel::WebViewPanel(wxWindow *parent)
wxString strlang = wxGetApp().current_language_code_safe();
if (strlang != "")
url = wxString::Format("file://%s/web/homepage/index.html?lang=%s", from_u8(resources_dir()), strlang);
m_home_url = url;
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
@@ -83,12 +84,10 @@ WebViewPanel::WebViewPanel(wxWindow *parent)
m_info = new wxInfoBar(this);
topsizer->Add(m_info, wxSizerFlags().Expand());
// Create the webview
m_browser = WebView::CreateWebView(this, url);
if (m_browser == nullptr) {
wxLogError("Could not init m_browser");
create_browser();
if (m_browser == nullptr)
return;
}
m_browser->Hide();
m_reset_on_show = wxGetApp().is_recreating_gui();
SetSizer(topsizer);
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
@@ -237,6 +236,47 @@ WebViewPanel::~WebViewPanel()
}
void WebViewPanel::create_browser()
{
m_browser = WebView::CreateWebView(this, m_home_url);
if (m_browser == nullptr) {
wxLogError("Could not init m_browser");
return;
}
m_browser->Hide();
}
void WebViewPanel::reset_browser()
{
wxSizer* topsizer = GetSizer();
if (m_browser) {
if (topsizer)
topsizer->Detach(m_browser);
m_browser->Destroy();
m_browser = nullptr;
}
create_browser();
if (m_browser == nullptr)
return;
if (topsizer) {
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
Layout();
}
}
bool WebViewPanel::Show(bool show)
{
// Recover from a wedged WebView2 backend created during a GUI rebuild by
// recreating the control the first time the Home tab is actually shown.
if (show && m_reset_on_show) {
m_reset_on_show = false;
reset_browser();
if (m_browser != nullptr)
m_browser->LoadURL(m_home_url);
}
return wxPanel::Show(show);
}
void WebViewPanel::load_url(wxString& url)
{
this->Show();

View File

@@ -105,9 +105,21 @@ public:
int get_model_mall_detail_url(std::string *url, std::string id);
void update_mode();
bool Show(bool show = true) override;
private:
// Create/configure m_browser (create the webview, hidden until loaded).
void create_browser();
// Tear down and recreate m_browser to recover from a wedged WebView2 backend
// after a GUI rebuild (language switch), then reload the home page.
void reset_browser();
wxWebView* m_browser;
// Home page url (kept so the browser can be reloaded after a reset).
wxString m_home_url;
// Set when this panel is built during a GUI rebuild; recreate the backend on
// first show to recover from a wedged control.
bool m_reset_on_show{false};
wxBoxSizer *bSizer_toolbar;
wxButton * m_button_back;
wxButton * m_button_forward;