Files
OrcaSlicer/src/slic3r/GUI/PrinterWebView.cpp
T
HanifKoh 4895bc03b4 Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced (#16099)
* Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced

Generated with include-what-you-use and applied conservatively. Only OrcaSlicer's own headers, the ones under src/ and tests/, are removed or forward-declared; standard-library and third-party includes are left alone. An include is removed only when both the Release and the Debug configuration leave it unused, never from inside a conditional block, and never from a file with platform-specific blocks, which only gain includes. Files whose only use of a header sits behind a feature or debug macro (libvgcode's OpenGL ES and marker code, the ARACHNE/TESTS_EXPORT_SVGS debug output) keep their includes.

clonable_ptr.hpp gains #pragma once; it had no include guard and was only safe while Config.hpp was its sole includer.

* Remove Unused Project Includes From Files With Platform-Specific Code

A Linux include-what-you-use run cannot see the code inside _WIN32, __APPLE__ or __linux__ blocks, so its verdict is only taken where nothing the removed header declares, directly or through what it includes, is named inside those blocks. Removals also have to hold in both the Release and Debug configuration and never touch a line inside a conditional block.

* Restore the libslic3r Precompiled Header and Direct Includes Lost in the Platform Pass

The platform-file pass treated pchheader.hpp as an ordinary header and
emptied it, and left GUI_Preview.hpp and 14 other files relying on
headers they no longer reached directly.

* Restore MainFrame.hpp in ParamsDialog.cpp for the Windows-Only Reparent Call

* Include Headers That Files Reached Through Ones the Cleanup Removed

* Drop Includes Duplicated by the Cleanup or by Main's Own Additions

* Leave PreciseSeam.cpp as Main Has It After the Precise Seam Rework
2026-10-05 16:47:17 +08:00

349 lines
11 KiB
C++

#include "PrinterWebView.hpp"
#include "PrinterWebViewHandler.hpp"
#include "slic3r/GUI/PrinterWebView.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "libslic3r_version.h"
#include <boost/filesystem/path.hpp>
#include <utility>
#include <wx/panel.h>
#include <wx/gdicmn.h>
#include <memory>
#include <wx/log.h>
#include "libslic3r/Utils.hpp"
#include <wx/event.h>
#include <boost/log/trivial.hpp>
#include <wx/sizer.h>
#include <wx/string.h>
#include <wx/toolbar.h>
#include <slic3r/GUI/Widgets/WebView.hpp>
#include <wx/utils.h>
#include <wx/webview.h>
class wxWindow;
#ifdef __linux__
#include <webkit2/webkit2.h>
#endif
namespace Slic3r {
namespace GUI {
#ifdef __linux__
// Workaround for #7210: WebKitGTK crashes on vue-resize's hidden <object> probe used by
// older Fluidd/Mainsail pages. Swap that <object> for a <div> shim at appendChild time
// and bridge resize events through a fake contentDocument.defaultView so vue-resize keeps
// working. Workaround proposed by @VittC.
static void inject_vue_resize_workaround(wxWebView *webView)
{
webView->AddUserScript(
"(function() {"
" 'use strict';"
" function isVueResizeObject(el) {"
" return el && el.tagName === 'OBJECT'"
" && el.type === 'text/html'"
" && el.getAttribute('aria-hidden') === 'true'"
" && el.getAttribute('tabindex') === '-1';"
" }"
" function isResizeObserverParent(p) {"
" return p && p.classList && p.classList.contains('resize-observer');"
" }"
" function makeShim(orig, parentForRO) {"
" var shim = document.createElement('div');"
" shim.setAttribute('aria-hidden', 'true');"
" shim.setAttribute('tabindex', '-1');"
" shim.style.display = 'none';"
" var fakeWin = document.createElement('div');"
" var ro = null;"
" var origRemoveEL = fakeWin.removeEventListener.bind(fakeWin);"
" fakeWin.removeEventListener = function(type, fn, opts) {"
" origRemoveEL(type, fn, opts);"
" if (type === 'resize' && ro) { ro.disconnect(); ro = null; }"
" };"
" Object.defineProperty(shim, 'contentDocument', {"
" configurable: true,"
" get: function() { return { defaultView: fakeWin }; }"
" });"
" Object.defineProperty(shim, 'contentWindow', {"
" configurable: true,"
" get: function() { return fakeWin; }"
" });"
" if (typeof orig.onload === 'function') { shim.onload = orig.onload; }"
" queueMicrotask(function() {"
" if (parentForRO && typeof ResizeObserver !== 'undefined') {"
" ro = new ResizeObserver(function() {"
" fakeWin.dispatchEvent(new Event('resize'));"
" });"
" ro.observe(parentForRO);"
" }"
" if (typeof shim.onload === 'function') {"
" try { shim.onload(new Event('load')); } catch (e) {}"
" }"
" shim.dispatchEvent(new Event('load'));"
" });"
" return shim;"
" }"
" var origAppend = Node.prototype.appendChild;"
" Node.prototype.appendChild = function(child) {"
" if (isResizeObserverParent(this) && isVueResizeObject(child)) {"
" return origAppend.call(this, makeShim(child, this));"
" }"
" return origAppend.call(this, child);"
" };"
" var origInsertBefore = Node.prototype.insertBefore;"
" Node.prototype.insertBefore = function(child, ref) {"
" if (isResizeObserverParent(this) && isVueResizeObject(child)) {"
" return origInsertBefore.call(this, makeShim(child, this), ref);"
" }"
" return origInsertBefore.call(this, child, ref);"
" };"
" console.log('[vr-fix] vue-resize WebKitGTK patch active');"
"})();",
wxWEBVIEW_INJECT_AT_DOCUMENT_START
);
}
#endif
PrinterWebView::PrinterWebView(wxWindow *parent)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
, m_browser(nullptr)
, m_zoomFactor(100)
, m_apikey()
, m_apikey_sent(false)
, m_url_deferred()
, m_handler(std::make_unique<PrinterWebViewHandler>(*this))
{
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
// Create the webview
create_browser();
m_reset_on_show = WebView::NeedsRecreateOnShow();
SetSizer(topsizer);
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
// Log backend information
/* m_browser->GetUserAgent() may lead crash
if (wxGetApp().get_mode() == comDevelop) {
wxLogMessage(wxWebView::GetBackendVersionInfo().ToString());
wxLogMessage("Backend: %s Version: %s", m_browser->GetClassInfo()->GetClassName(),
wxWebView::GetBackendVersionInfo().ToString());
wxLogMessage("User Agent: %s", m_browser->GetUserAgent());
}
*/
//Connect the idle events
Bind(wxEVT_CLOSE_WINDOW, &PrinterWebView::OnClose, this);
}
PrinterWebView::~PrinterWebView()
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Start";
SetEvtHandlerEnabled(false);
m_handler.reset();
// Destroy the webview
if(m_browser){
m_browser->Destroy();
m_browser = nullptr;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " End";
}
void PrinterWebView::create_browser()
{
m_browser = WebView::CreateWebView(this, "");
#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);
update_mode();
}
void PrinterWebView::reset_browser()
{
m_browser->Destroy(); // also removes it from the sizer
create_browser();
GetSizer()->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
Layout();
// OnLoaded may have cleared m_url_deferred already, so requeue the last url for Show().
m_apikey_sent = false;
m_url_deferred = m_url;
}
void PrinterWebView::load_url(wxString& url, wxString apikey)
{
// this->Show();
// this->Raise();
m_url = url;
m_apikey = 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();
m_browser->LoadURL(url);
} else {
m_url_deferred = url;
}
//m_browser->SetFocus();
UpdateState();
}
bool PrinterWebView::Show(bool show)
{
if (show && std::exchange(m_reset_on_show, false))
reset_browser();
if (show && !m_url_deferred.empty()) {
m_browser->LoadURL(m_url_deferred);
//ORCA: m_url_deferred will be cleared on load success
//m_url_deferred.clear();
}
return wxPanel::Show(show);
}
void PrinterWebView::reload()
{
m_browser->Reload();
}
void PrinterWebView::update_mode()
{
m_browser->EnableAccessToDevTools(wxGetApp().app_config->get_bool("developer_mode"));
}
/**
* Method that retrieves the current state from the web control and updates the
* GUI the reflect this current state.
*/
void PrinterWebView::UpdateState() {
// SetTitle(m_browser->GetCurrentTitle());
}
void PrinterWebView::OnClose(wxCloseEvent& evt)
{
this->Hide();
}
void PrinterWebView::SendAPIKey()
{
if (m_apikey_sent || m_apikey.IsEmpty())
return;
m_apikey_sent = true;
wxString script = wxString::Format(R"(
// Check if window.fetch exists before overriding
if (window.fetch) {
const originalFetch = window.fetch;
window.fetch = function(input, init = {}) {
init.headers = init.headers || {};
init.headers['X-API-Key'] = '%s';
return originalFetch(input, init);
};
}
)",
m_apikey);
m_browser->RemoveAllUserScripts();
// RemoveAllUserScripts causes WebView to forget about our script message handler,
// so re-add it here.
m_browser->RemoveScriptMessageHandler("wx");
if (m_browser->AddScriptMessageHandler("wx"))
WebView::MarkScriptMessageHandlerAdded(m_browser);
else
wxLogError("Could not add script message handler");
#ifdef __linux__
// Re-inject the vue-resize/WebKitGTK workaround that RemoveAllUserScripts just cleared.
inject_vue_resize_workaround(m_browser);
#endif
m_browser->AddUserScript(script);
m_browser->Reload();
}
void PrinterWebView::OnError(wxWebViewEvent &evt)
{
auto e = "unknown error";
switch (evt.GetInt()) {
case wxWEBVIEW_NAV_ERR_CONNECTION:
e = "wxWEBVIEW_NAV_ERR_CONNECTION";
break;
case wxWEBVIEW_NAV_ERR_CERTIFICATE:
e = "wxWEBVIEW_NAV_ERR_CERTIFICATE";
break;
case wxWEBVIEW_NAV_ERR_AUTH:
e = "wxWEBVIEW_NAV_ERR_AUTH";
break;
case wxWEBVIEW_NAV_ERR_SECURITY:
e = "wxWEBVIEW_NAV_ERR_SECURITY";
break;
case wxWEBVIEW_NAV_ERR_NOT_FOUND:
e = "wxWEBVIEW_NAV_ERR_NOT_FOUND";
break;
case wxWEBVIEW_NAV_ERR_REQUEST:
e = "wxWEBVIEW_NAV_ERR_REQUEST";
break;
case wxWEBVIEW_NAV_ERR_USER_CANCELLED:
e = "wxWEBVIEW_NAV_ERR_USER_CANCELLED";
break;
case wxWEBVIEW_NAV_ERR_OTHER:
e = "wxWEBVIEW_NAV_ERR_OTHER";
break;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": error loading page %1% %2% %3% %4%") %evt.GetURL() %evt.GetTarget() %e %evt.GetString();
}
void PrinterWebView::OnLoaded(wxWebViewEvent& evt)
{
if (evt.GetURL().IsEmpty())
return;
//ORCA: url loaded successfully, safe to clear
m_url_deferred.clear();
SendAPIKey();
if (m_handler != nullptr) {
m_handler->on_loaded(evt);
return;
}
}
void PrinterWebView::OnNewWindow(wxWebViewEvent& evt)
{
const wxString url = evt.GetURL();
if (!url.empty())
wxLaunchDefaultBrowser(url);
evt.Veto();
}
void PrinterWebView::OnScriptMessage(wxWebViewEvent& evt)
{
if (m_handler != nullptr)
m_handler->on_script_message(evt);
}
} // GUI
} // Slic3r