From aa0134c341abe60d31a7acfae8672b0e0447d13c Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 5 Oct 2025 23:23:37 +0100 Subject: [PATCH] chore: improve webview code style --- .../Web/Edge/CustomProtocolHandlerEdge.cpp | 207 ++++++++++-------- .../Web/Edge/CustomProtocolHandlerEdge.h | 4 +- .../Web/Gtk/CustomProtocolHandlerGtk.cpp | 48 +--- src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.h | 4 +- src/ModMan/Web/UiAssets.cpp | 16 ++ src/ModMan/Web/UiAssets.h | 1 + src/ModMan/main.cpp | 10 +- 7 files changed, 142 insertions(+), 148 deletions(-) diff --git a/src/ModMan/Web/Edge/CustomProtocolHandlerEdge.cpp b/src/ModMan/Web/Edge/CustomProtocolHandlerEdge.cpp index 5116b549..bbf4a923 100644 --- a/src/ModMan/Web/Edge/CustomProtocolHandlerEdge.cpp +++ b/src/ModMan/Web/Edge/CustomProtocolHandlerEdge.cpp @@ -7,7 +7,7 @@ #if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE) -#include "ui/modmanui.h" +#include "Web/UiAssets.h" #include #include @@ -18,25 +18,33 @@ namespace { - constexpr auto MOD_MAN_URL_PREFIX = "modman://localhost/"; - std::unordered_map assetLookup; - std::string wide_string_to_string(const std::wstring& wide_string) + std::string WideStringToString(const std::wstring& wideString) { - if (wide_string.empty()) - { + if (wideString.empty()) return ""; - } - const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, wide_string.data(), (int)wide_string.size(), nullptr, 0, nullptr, nullptr); - if (size_needed <= 0) - { - throw std::runtime_error("WideCharToMultiByte() failed: " + std::to_string(size_needed)); - } + const auto sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, wideString.data(), static_cast(wideString.size()), nullptr, 0, nullptr, nullptr); + if (sizeNeeded <= 0) + throw std::runtime_error(std::format("WideCharToMultiByte() failed: {}", sizeNeeded)); - std::string result(size_needed, 0); - WideCharToMultiByte(CP_UTF8, 0, wide_string.data(), (int)wide_string.size(), result.data(), size_needed, nullptr, nullptr); + std::string result(sizeNeeded, 0); + WideCharToMultiByte(CP_UTF8, 0, wideString.data(), static_cast(wideString.size()), result.data(), sizeNeeded, nullptr, nullptr); + return result; + } + + std::wstring StringToWideString(const std::string& string) + { + if (string.empty()) + return L""; + + const auto sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, string.data(), static_cast(string.size()), nullptr, 0); + if (sizeNeeded <= 0) + throw std::runtime_error(std::format("MultiByteToWideChar() failed: {}", sizeNeeded)); + + std::wstring result(sizeNeeded, 0); + MultiByteToWideChar(CP_UTF8, 0, string.data(), static_cast(string.size()), result.data(), sizeNeeded); return result; } @@ -45,22 +53,89 @@ namespace std::wstringstream wss; wss << std::format(L"Content-Length: {}\n", contentLength); - - if (assetName.ends_with(".html")) - { - wss << L"Content-Type: text/html\n"; - } - else if (assetName.ends_with(".js")) - { - wss << L"Content-Type: text/javascript\n"; - } - else if (assetName.ends_with(".css")) - { - wss << L"Content-Type: text/css\n"; - } + wss << L"Content-Type: " << StringToWideString(GetMimeTypeForFileName(assetName)); return wss.str(); } + + HRESULT HandleResourceRequested(ICoreWebView2_22* core22, IUnknown* args) + { + Microsoft::WRL::ComPtr webResourceRequestArgs; + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&webResourceRequestArgs)))) + { + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS requestSourceKind = COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL; + if (!SUCCEEDED(webResourceRequestArgs->get_RequestedSourceKind(&requestSourceKind))) + { + std::cerr << "Failed to get requested source kind\n"; + return S_FALSE; + } + + Microsoft::WRL::ComPtr request; + if (!SUCCEEDED(webResourceRequestArgs->get_Request(&request))) + { + std::cerr << "Failed to get request\n"; + return S_FALSE; + } + + LPWSTR wUri; + if (!SUCCEEDED(request->get_Uri(&wUri))) + { + std::cerr << "Failed to get uri\n"; + return S_FALSE; + } + + Microsoft::WRL::ComPtr environment; + if (!SUCCEEDED(core22->get_Environment(&environment))) + { + std::cerr << "Failed to get environment\n"; + return S_FALSE; + } + + Microsoft::WRL::ComPtr response; + + const auto uri = WideStringToString(wUri); + bool fileFound = false; + if (uri.starts_with(edge::URL_PREFIX)) + { + const auto asset = uri.substr(std::char_traits::length(edge::URL_PREFIX) - 1); + + const auto foundUiFile = assetLookup.find(asset); + if (foundUiFile != assetLookup.end()) + { + const Microsoft::WRL::ComPtr responseStream = + SHCreateMemStream(static_cast(foundUiFile->second.data), foundUiFile->second.dataSize); + + const auto headers = HeadersForAssetName(asset, foundUiFile->second.dataSize); + if (!SUCCEEDED(environment->CreateWebResourceResponse(responseStream.Get(), 200, L"OK", headers.data(), &response))) + { + std::cerr << "Failed to create web resource\n"; + return S_FALSE; + } + + fileFound = true; + } + } + + if (!fileFound) + { + if (!SUCCEEDED(environment->CreateWebResourceResponse(nullptr, 404, L"Not found", L"", &response))) + { + std::cerr << "Failed to create web resource\n"; + return S_FALSE; + } + } + + if (!SUCCEEDED(webResourceRequestArgs->put_Response(response.Get()))) + { + std::cerr << "Failed to put response\n"; + return S_FALSE; + } + + return S_OK; + } + + return S_FALSE; + } } // namespace namespace edge @@ -92,74 +167,16 @@ namespace edge } EventRegistrationToken token; - core->add_WebResourceRequested(Microsoft::WRL::Callback( - [core22](ICoreWebView2* sender, IUnknown* args) -> HRESULT - { - Microsoft::WRL::ComPtr webResourceRequestArgs; - if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&webResourceRequestArgs)))) - { - COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS requestSourceKind = - COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL; - if (!SUCCEEDED(webResourceRequestArgs->get_RequestedSourceKind(&requestSourceKind))) - { - std::cerr << "Failed to get requested source kind\n"; - return S_FALSE; - } - - Microsoft::WRL::ComPtr request; - if (!SUCCEEDED(webResourceRequestArgs->get_Request(&request))) - { - std::cerr << "Failed to get request\n"; - return S_FALSE; - } - - LPWSTR wUri; - if (!SUCCEEDED(request->get_Uri(&wUri))) - { - std::cerr << "Failed to get uri\n"; - return S_FALSE; - } - - Microsoft::WRL::ComPtr environment; - if (!SUCCEEDED(core22->get_Environment(&environment))) - { - std::cerr << "Failed to get environment\n"; - return S_FALSE; - } - - Microsoft::WRL::ComPtr response; - - const auto uri = wide_string_to_string(wUri); - bool fileFound = false; - if (uri.starts_with(MOD_MAN_URL_PREFIX)) - { - const auto asset = uri.substr(std::char_traits::length(MOD_MAN_URL_PREFIX)); - - const auto foundUiFile = assetLookup.find(asset); - if (foundUiFile != assetLookup.end()) - { - Microsoft::WRL::ComPtr response_stream = SHCreateMemStream( - static_cast(foundUiFile->second.data), foundUiFile->second.dataSize); - - const auto headers = HeadersForAssetName(asset, foundUiFile->second.dataSize); - environment->CreateWebResourceResponse(response_stream.Get(), 200, L"OK", headers.data(), &response); - fileFound = true; - } - } - - if (!fileFound) - { - environment->CreateWebResourceResponse(nullptr, 404, L"Not found", L"", &response); - } - - webResourceRequestArgs->put_Response(response.Get()); - return S_OK; - } - - return S_FALSE; - }) - .Get(), - &token); + if (!SUCCEEDED(core->add_WebResourceRequested(Microsoft::WRL::Callback( + [core22](ICoreWebView2* sender, IUnknown* args) -> HRESULT + { + return HandleResourceRequested(core22.Get(), args); + }) + .Get(), + &token))) + { + std::cerr << "Failed to add resource requested filter\n"; + } } } // namespace edge diff --git a/src/ModMan/Web/Edge/CustomProtocolHandlerEdge.h b/src/ModMan/Web/Edge/CustomProtocolHandlerEdge.h index 3c6efe2f..8d7f3ad4 100644 --- a/src/ModMan/Web/Edge/CustomProtocolHandlerEdge.h +++ b/src/ModMan/Web/Edge/CustomProtocolHandlerEdge.h @@ -12,7 +12,9 @@ namespace edge { + constexpr auto URL_PREFIX = "http://modman.local/"; + void InstallCustomProtocolHandler(webview::webview& wv); -} +} // namespace edge #endif diff --git a/src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.cpp b/src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.cpp index 8036e279..570d8a72 100644 --- a/src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.cpp +++ b/src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.cpp @@ -20,43 +20,17 @@ namespace { std::unordered_map assetLookup; - const char* ContentTypeForAssetName(const std::string& assetName) - { - const char* mimeType; - - if (assetName.ends_with(".html")) - { - mimeType = "text/html"; - } - else if (assetName.ends_with(".js")) - { - mimeType = "text/javascript"; - } - else if (assetName.ends_with(".css")) - { - mimeType = "text/css"; - } - else - { - mimeType = "application/octet-stream"; - } - - return mimeType; - } - void ModManUriSchemeRequestCb(WebKitURISchemeRequest* request, gpointer user_data) { const gchar* asset = webkit_uri_scheme_request_get_path(request); - std::cout << std::format("Modman request: {}\n", asset); - const auto foundUiFile = assetLookup.find(asset); if (foundUiFile != assetLookup.end()) { gsize stream_length = foundUiFile->second.dataSize; GInputStream* stream = g_memory_input_stream_new_from_data(foundUiFile->second.data, foundUiFile->second.dataSize, nullptr); - webkit_uri_scheme_request_finish(request, stream, stream_length, ContentTypeForAssetName(foundUiFile->second.filename)); + webkit_uri_scheme_request_finish(request, stream, stream_length, GetMimeTypeForFileName(foundUiFile->second.filename)); g_object_unref(stream); } else @@ -67,24 +41,6 @@ namespace return; } } - - void OnResourceLoadStarted(WebKitWebView* self, WebKitWebResource* resource, WebKitURIRequest* request, gpointer user_data) - { - std::cout << webkit_uri_request_get_http_method(request) << " " << webkit_uri_request_get_uri(request) << "\n"; - - std::string uri(webkit_uri_request_get_uri(request)); - if (uri.starts_with("http://")) - { - uri = std::format("modman://{}", uri.substr(7)); - } - else if (uri.starts_with("https://")) - { - uri = std::format("modman://{}", uri.substr(8)); - } - - std::cout << std::format("Setting uri: {}\n", uri); - webkit_uri_request_set_uri(request, uri.c_str()); - } } // namespace namespace gtk @@ -97,8 +53,6 @@ namespace gtk assetLookup = BuildUiFileLookup(); - g_signal_connect(webView, "resource-load-started", G_CALLBACK(OnResourceLoadStarted), NULL); - webkit_web_context_register_uri_scheme(context, "modman", ModManUriSchemeRequestCb, NULL, nullptr); } } // namespace gtk diff --git a/src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.h b/src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.h index 85e2231a..c104e10f 100644 --- a/src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.h +++ b/src/ModMan/Web/Gtk/CustomProtocolHandlerGtk.h @@ -12,7 +12,9 @@ namespace gtk { + constexpr auto URL_PREFIX = "modman://localhost/"; + void InstallCustomProtocolHandler(webview::webview& wv); -} +} // namespace gtk #endif diff --git a/src/ModMan/Web/UiAssets.cpp b/src/ModMan/Web/UiAssets.cpp index 3ddadbf4..cd34c030 100644 --- a/src/ModMan/Web/UiAssets.cpp +++ b/src/ModMan/Web/UiAssets.cpp @@ -13,3 +13,19 @@ std::unordered_map BuildUiFileLookup() return result; } + +const char* GetMimeTypeForFileName(const std::string& fileName) +{ + const char* mimeType; + + if (fileName.ends_with(".html")) + mimeType = "text/html"; + else if (fileName.ends_with(".js")) + mimeType = "text/javascript"; + else if (fileName.ends_with(".css")) + mimeType = "text/css"; + else + mimeType = "application/octet-stream"; + + return mimeType; +} diff --git a/src/ModMan/Web/UiAssets.h b/src/ModMan/Web/UiAssets.h index 50231baa..2bc9542b 100644 --- a/src/ModMan/Web/UiAssets.h +++ b/src/ModMan/Web/UiAssets.h @@ -6,3 +6,4 @@ #include std::unordered_map BuildUiFileLookup(); +const char* GetMimeTypeForFileName(const std::string& fileName); diff --git a/src/ModMan/main.cpp b/src/ModMan/main.cpp index 64661cd0..033739db 100644 --- a/src/ModMan/main.cpp +++ b/src/ModMan/main.cpp @@ -7,9 +7,12 @@ #include #include +#include #include #include +using namespace std::string_literals; + #ifdef _WIN32 int WINAPI WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/) { @@ -55,13 +58,12 @@ int main() #if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE) edge::InstallCustomProtocolHandler(w); -#endif - -#if defined(WEBVIEW_PLATFORM_LINUX) && defined(WEBVIEW_GTK) + w.navigate(edge::URL_PREFIX + "index.html"s); +#elif defined(WEBVIEW_PLATFORM_LINUX) && defined(WEBVIEW_GTK) gtk::InstallCustomProtocolHandler(w); + w.navigate(gtk::URL_PREFIX + "index.html"s); #endif - w.navigate("modman://localhost/index.html"); w.run(); } catch (const webview::exception& e)