Files
OrcaSlicer-KX/src/slic3r/GUI/Widgets/WebView.cpp
Ocraftyone dab6fa4db2 Fix Compile Warnings (#5963)
* Fix calls to depreciated wxPen constructor

* Fix use of wxTimerEvent

* Fix unrecognized character escape sequence

* Fix signed/unsigned mismatch

At least as much as possible without significantly altering parts of the application

* Clean unreferenced variables

* fix mistyped namespace selector

* Update deprecated calls

* Fix preprocessor statement

* Remove empty switch statements

* Change int vector used as bool to bool vector

* Remove empty control statements and related unused code

* Change multi character constant to string constant

* Fix discarded return value

json::parse was being called on the object, rather than statically like it should be. Also, the value was not being captured.

* Rename ICON_SIZE def used by MultiMachine

By having the definition in the header, it causes issues when other files define ICON_SIZE. By renaming it to MM_ICON_SIZE, this lessens the issue. It would probably be ideal to have the definitions in the respective .cpp that use them, but it would make it less convenient to update the values if needed in the future.

* Remove unused includes

* Fix linux/macOS compilation

* Hide unused-function errors on non-Windows systems

* Disable signed/unsigned comparison mismatch error

* Remove/Disable more unused variables

Still TODO: check double for loop in Print.cpp

* Remove unused variable that was missed

* Remove unused variables in libraries in the src folder

* Apply temporary fix for subobject linkage error

* Remove/Disable last set of unused variables reported by GCC

* remove redundant for loop

* fix misspelled ifdef check

* Update message on dialog

* Fix hard-coded platform specific modifier keys

* Remove duplicate for loop

* Disable -Wmisleading-indentation warning

* disable -Wswitch warning

* Remove unused local typedefs

* Fix -Wunused-value

* Fix pragma error on Windows from subobject linkage fix

* Fix -Waddress

* Fix null conversions (-Wconversion-null)

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
2024-07-29 21:00:26 +08:00

390 lines
16 KiB
C++

#include "WebView.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/Utils/MacDarkMode.hpp"
#include <boost/log/trivial.hpp>
#include <wx/webviewarchivehandler.h>
#include <wx/webviewfshandler.h>
#if wxUSE_WEBVIEW_EDGE
#include <wx/msw/webview_edge.h>
#elif defined(__WXMAC__)
#include <wx/osx/webview_webkit.h>
#endif
#include <wx/uri.h>
#if defined(__WIN32__) || defined(__WXMAC__)
#include "wx/private/jsscriptwrapper.h"
#endif
#ifdef __WIN32__
#include <WebView2.h>
#include <Shellapi.h>
#include <slic3r/Utils/Http.hpp>
#elif defined __linux__
#include <gtk/gtk.h>
#define WEBKIT_API
struct WebKitWebView;
struct WebKitJavascriptResult;
extern "C" {
WEBKIT_API void
webkit_web_view_run_javascript (WebKitWebView *web_view,
const gchar *script,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
WEBKIT_API WebKitJavascriptResult *
webkit_web_view_run_javascript_finish (WebKitWebView *web_view,
GAsyncResult *result,
GError **error);
WEBKIT_API void
webkit_javascript_result_unref (WebKitJavascriptResult *js_result);
}
#endif
#ifdef __WIN32__
// Run Download and Install in another thread so we don't block the UI thread
DWORD DownloadAndInstallWV2RT() {
int returnCode = 2; // Download failed
// Use fwlink to download WebView2 Bootstrapper at runtime and invoke installation
// Broken/Invalid Https Certificate will fail to download
// Use of the download link below is governed by the below terms. You may acquire the link
// for your use at https://developer.microsoft.com/microsoft-edge/webview2/. Microsoft owns
// all legal right, title, and interest in and to the WebView2 Runtime Bootstrapper
// ("Software") and related documentation, including any intellectual property in the
// Software. You must acquire all code, including any code obtained from a Microsoft URL,
// under a separate license directly from Microsoft, including a Microsoft download site
// (e.g., https://developer.microsoft.com/microsoft-edge/webview2/).
// HRESULT hr = URLDownloadToFileW(NULL, L"https://go.microsoft.com/fwlink/p/?LinkId=2124703",
// L".\\plugin\\MicrosoftEdgeWebview2Setup.exe", 0, 0);
fs::path target_file_path = (fs::temp_directory_path() / "MicrosoftEdgeWebview2Setup.exe");
bool downloaded = false;
Slic3r::Http::get("https://go.microsoft.com/fwlink/p/?LinkId=2124703")
.on_error([](std::string body, std::string error, unsigned http_status) {
})
.on_complete([&downloaded, target_file_path](std::string body, unsigned http_status) {
fs::fstream file(target_file_path, std::ios::out | std::ios::binary | std::ios::trunc);
file.write(body.c_str(), body.size());
file.flush();
file.close();
downloaded = true;
})
.perform_sync();
// Sleep for 1 second to wait for the buffer writen into disk
std::this_thread::sleep_for(1000ms);
if (downloaded) {
// Either Package the WebView2 Bootstrapper with your app or download it using fwlink
// Then invoke install at Runtime.
SHELLEXECUTEINFOW shExInfo = {0};
shExInfo.cbSize = sizeof(shExInfo);
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExInfo.hwnd = 0;
shExInfo.lpVerb = L"runas";
shExInfo.lpFile = target_file_path.generic_wstring().c_str();
shExInfo.lpParameters = L" /install";
shExInfo.lpDirectory = 0;
shExInfo.nShow = 0;
shExInfo.hInstApp = 0;
if (ShellExecuteExW(&shExInfo)) {
WaitForSingleObject(shExInfo.hProcess, INFINITE);
returnCode = 0; // Install successfull
} else {
returnCode = 1; // Install failed
}
}
return returnCode;
}
class WebViewEdge : public wxWebViewEdge
{
public:
bool SetUserAgent(const wxString &userAgent)
{
bool dark = userAgent.Contains("dark");
SetColorScheme(dark ? COREWEBVIEW2_PREFERRED_COLOR_SCHEME_DARK : COREWEBVIEW2_PREFERRED_COLOR_SCHEME_LIGHT);
ICoreWebView2 *webView2 = (ICoreWebView2 *) GetNativeBackend();
if (webView2) {
ICoreWebView2Settings *settings;
HRESULT hr = webView2->get_Settings(&settings);
if (hr == S_OK) {
ICoreWebView2Settings2 *settings2;
hr = settings->QueryInterface(&settings2);
if (hr == S_OK) {
settings2->put_UserAgent(userAgent.wc_str());
settings2->Release();
return true;
}
}
settings->Release();
return false;
}
pendingUserAgent = userAgent;
return true;
}
bool SetColorScheme(COREWEBVIEW2_PREFERRED_COLOR_SCHEME colorScheme)
{
ICoreWebView2 *webView2 = (ICoreWebView2 *) GetNativeBackend();
if (webView2) {
ICoreWebView2_13 * webView2_13;
HRESULT hr = webView2->QueryInterface(&webView2_13);
if (hr == S_OK) {
ICoreWebView2Profile *profile;
hr = webView2_13->get_Profile(&profile);
if (hr == S_OK) {
profile->put_PreferredColorScheme(colorScheme);
profile->Release();
return true;
}
webView2_13->Release();
}
return false;
}
pendingColorScheme = colorScheme;
return true;
}
void DoGetClientSize(int *x, int *y) const override
{
if (!pendingUserAgent.empty()) {
auto thiz = const_cast<WebViewEdge *>(this);
auto userAgent = std::move(thiz->pendingUserAgent);
thiz->pendingUserAgent.clear();
thiz->SetUserAgent(userAgent);
}
if (pendingColorScheme) {
auto thiz = const_cast<WebViewEdge *>(this);
auto colorScheme = pendingColorScheme;
thiz->pendingColorScheme = COREWEBVIEW2_PREFERRED_COLOR_SCHEME_AUTO;
thiz->SetColorScheme(colorScheme);
}
wxWebViewEdge::DoGetClientSize(x, y);
};
private:
wxString pendingUserAgent;
COREWEBVIEW2_PREFERRED_COLOR_SCHEME pendingColorScheme = COREWEBVIEW2_PREFERRED_COLOR_SCHEME_AUTO;
};
#elif defined __WXOSX__
class WebViewWebKit : public wxWebViewWebKit
{
~WebViewWebKit() override
{
RemoveScriptMessageHandler("wx");
}
};
#endif
class FakeWebView : public wxWebView
{
virtual bool Create(wxWindow* parent, wxWindowID id, const wxString& url, const wxPoint& pos, const wxSize& size, long style, const wxString& name) override { return false; }
virtual wxString GetCurrentTitle() const override { return wxString(); }
virtual wxString GetCurrentURL() const override { return wxString(); }
virtual bool IsBusy() const override { return false; }
virtual bool IsEditable() const override { return false; }
virtual void LoadURL(const wxString& url) override { }
virtual void Print() override { }
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) override { }
virtual void Reload(wxWebViewReloadFlags flags = wxWEBVIEW_RELOAD_DEFAULT) override { }
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const override { return false; }
virtual void SetEditable(bool enable = true) override { }
virtual void Stop() override { }
virtual bool CanGoBack() const override { return false; }
virtual bool CanGoForward() const override { return false; }
virtual void GoBack() override { }
virtual void GoForward() override { }
virtual void ClearHistory() override { }
virtual void EnableHistory(bool enable = true) override { }
virtual wxVector<wxSharedPtr<wxWebViewHistoryItem>> GetBackwardHistory() override { return {}; }
virtual wxVector<wxSharedPtr<wxWebViewHistoryItem>> GetForwardHistory() override { return {}; }
virtual void LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item) override { }
virtual bool CanSetZoomType(wxWebViewZoomType type) const override { return false; }
virtual float GetZoomFactor() const override { return 0.0f; }
virtual wxWebViewZoomType GetZoomType() const override { return wxWebViewZoomType(); }
virtual void SetZoomFactor(float zoom) override { }
virtual void SetZoomType(wxWebViewZoomType zoomType) override { }
virtual bool CanUndo() const override { return false; }
virtual bool CanRedo() const override { return false; }
virtual void Undo() override { }
virtual void Redo() override { }
virtual void* GetNativeBackend() const override { return nullptr; }
virtual void DoSetPage(const wxString& html, const wxString& baseUrl) override { }
};
wxDEFINE_EVENT(EVT_WEBVIEW_RECREATED, wxCommandEvent);
static std::vector<wxWebView*> g_webviews;
static std::vector<wxWebView*> g_delay_webviews;
class WebViewRef : public wxObjectRefData
{
public:
WebViewRef(wxWebView *webView) : m_webView(webView) {}
~WebViewRef() {
auto iter = std::find(g_webviews.begin(), g_webviews.end(), m_webView);
assert(iter != g_webviews.end());
if (iter != g_webviews.end())
g_webviews.erase(iter);
}
wxWebView *m_webView;
};
wxWebView* WebView::CreateWebView(wxWindow * parent, wxString const & url)
{
#if wxUSE_WEBVIEW_EDGE
// Check if a fixed version of edge is present in
// $executable_path/edge_fixed and use it
wxFileName edgeFixedDir(wxStandardPaths::Get().GetExecutablePath());
edgeFixedDir.SetFullName("");
edgeFixedDir.AppendDir("edge_fixed");
if (edgeFixedDir.DirExists()) {
wxWebViewEdge::MSWSetBrowserExecutableDir(edgeFixedDir.GetFullPath());
wxLogMessage("Using fixed edge version");
}
#endif
auto url2 = url;
#ifdef __WIN32__
url2.Replace("\\", "/");
#endif
if (!url2.empty()) { url2 = wxURI(url2).BuildURI(); }
BOOST_LOG_TRIVIAL(trace) << __FUNCTION__ << ": " << url2.ToUTF8();
#ifdef __WIN32__
wxWebView* webView = new WebViewEdge;
#elif defined(__WXOSX__)
wxWebView *webView = new WebViewWebKit;
#else
auto webView = wxWebView::New();
#endif
if (webView) {
webView->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
#ifdef __WIN32__
webView->SetUserAgent(wxString::Format("BBL-Slicer/v%s (%s) Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.52", SLIC3R_VERSION,
Slic3r::GUI::wxGetApp().dark_mode() ? "dark" : "light"));
webView->Create(parent, wxID_ANY, url2, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
// We register the wxfs:// protocol for testing purposes
webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("bbl")));
// And the memory: file system
webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
#else
// With WKWebView handlers need to be registered before creation
webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewArchiveHandler("wxfs")));
// And the memory: file system
webView->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new wxWebViewFSHandler("memory")));
webView->Create(parent, wxID_ANY, url2, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
webView->SetUserAgent(wxString::Format("BBL-Slicer/v%s (%s) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)", SLIC3R_VERSION,
Slic3r::GUI::wxGetApp().dark_mode() ? "dark" : "light"));
#endif
#ifdef __WXMAC__
WKWebView * wkWebView = (WKWebView *) webView->GetNativeBackend();
Slic3r::GUI::WKWebView_setTransparentBackground(wkWebView);
#endif
auto addScriptMessageHandler = [] (wxWebView *webView) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": begin to add script message handler for wx.";
Slic3r::GUI::wxGetApp().set_adding_script_handler(true);
if (!webView->AddScriptMessageHandler("wx"))
wxLogError("Could not add script message handler");
Slic3r::GUI::wxGetApp().set_adding_script_handler(false);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": finished add script message handler for wx.";
};
#ifndef __WIN32__
webView->CallAfter([webView, addScriptMessageHandler] {
#endif
if (Slic3r::GUI::wxGetApp().is_adding_script_handler()) {
g_delay_webviews.push_back(webView);
} else {
addScriptMessageHandler(webView);
while (!g_delay_webviews.empty()) {
auto views = std::move(g_delay_webviews);
for (auto wv : views)
addScriptMessageHandler(wv);
}
}
#ifndef __WIN32__
});
#endif
webView->EnableContextMenu(true);
} else {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": failed. Use fake web view.";
webView = new FakeWebView;
}
webView->SetRefData(new WebViewRef(webView));
g_webviews.push_back(webView);
return webView;
}
#if wxUSE_WEBVIEW_EDGE
bool WebView::CheckWebViewRuntime()
{
wxWebViewFactoryEdge factory;
auto wxVersion = factory.GetVersionInfo();
return wxVersion.GetMajor() != 0;
}
bool WebView::DownloadAndInstallWebViewRuntime()
{
return DownloadAndInstallWV2RT() == 0;
}
#endif
void WebView::LoadUrl(wxWebView * webView, wxString const &url)
{
auto url2 = url;
#ifdef __WIN32__
url2.Replace("\\", "/");
#endif
if (!url2.empty()) { url2 = wxURI(url2).BuildURI(); }
BOOST_LOG_TRIVIAL(trace) << __FUNCTION__ << url2.ToUTF8();
webView->LoadURL(url2);
}
bool WebView::RunScript(wxWebView *webView, wxString const &javascript)
{
if (Slic3r::GUI::wxGetApp().app_config->get("internal_developer_mode") == "true"
&& javascript.find("studio_userlogin") == wxString::npos)
wxLogMessage("Running JavaScript:\n%s\n", javascript);
try {
#ifdef __WIN32__
ICoreWebView2 * webView2 = (ICoreWebView2 *) webView->GetNativeBackend();
if (webView2 == nullptr)
return false;
return webView2->ExecuteScript(javascript, NULL) == 0;
#elif defined __WXMAC__
WKWebView * wkWebView = (WKWebView *) webView->GetNativeBackend();
Slic3r::GUI::WKWebView_evaluateJavaScript(wkWebView, javascript, nullptr);
return true;
#else
WebKitWebView *wkWebView = (WebKitWebView *) webView->GetNativeBackend();
webkit_web_view_run_javascript(
wkWebView, javascript.utf8_str(), NULL,
[](GObject *wkWebView, GAsyncResult *res, void *) {
GError * error = NULL;
auto result = webkit_web_view_run_javascript_finish((WebKitWebView*)wkWebView, res, &error);
if (!result)
g_error_free (error);
else
webkit_javascript_result_unref (result);
}, NULL);
return true;
#endif
} catch (std::exception&) {
return false;
}
}
void WebView::RecreateAll()
{
auto dark = Slic3r::GUI::wxGetApp().dark_mode();
for (auto webView : g_webviews) {
webView->SetUserAgent(wxString::Format("BBL-Slicer/v%s (%s) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)", SLIC3R_VERSION,
dark ? "dark" : "light"));
webView->Reload();
}
}