From 8dba13f91391f1a499c0566aaa295c82ec7bed3a Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 16 Jun 2026 09:50:34 +0200 Subject: [PATCH] refactor: use new webwindowed api (#831) * chore: update webview with new api * chore: update modman to use new webview api * chore: use title handler plugin from webview lib * chore: use favicon plugin from webview lib * chore: use vite-plugin-cpp-header from webview repo * chore: use asset handler from webview lib * chore: make webview utility * chore: rename webview to webwindowed * chore: Rename code usages to webwindowed --- .gitmodules | 6 +- package-lock.json | 71 +++--- premake5.lua | 4 +- src/ModMan.lua | 4 +- src/ModMan/Context/ModManContext.h | 6 +- src/ModMan/README.md | 12 +- src/ModMan/Web/Binds/AssetBinds.cpp | 6 +- src/ModMan/Web/Binds/AssetBinds.h | 4 +- src/ModMan/Web/Binds/Binds.cpp | 10 +- src/ModMan/Web/Binds/Binds.h | 4 +- src/ModMan/Web/Binds/DialogBinds.cpp | 58 ++--- src/ModMan/Web/Binds/DialogBinds.h | 4 +- src/ModMan/Web/Binds/UnlinkingBinds.cpp | 20 +- src/ModMan/Web/Binds/UnlinkingBinds.h | 6 +- src/ModMan/Web/Binds/ZoneBinds.cpp | 44 ++-- src/ModMan/Web/Binds/ZoneBinds.h | 4 +- src/ModMan/Web/Platform/AssetHandler.h | 17 -- src/ModMan/Web/Platform/FaviconHandler.h | 10 - .../Web/Platform/Linux/AssetHandlerLinux.cpp | 53 ---- .../Platform/Linux/FaviconHandlerLinux.cpp | 22 -- .../Web/Platform/Linux/TitleHandlerLinux.cpp | 30 --- src/ModMan/Web/Platform/TitleHandler.h | 10 - .../Platform/Windows/AssetHandlerWindows.cpp | 161 ------------- .../Windows/FaviconHandlerWindows.cpp | 150 ------------ .../Platform/Windows/TitleHandlerWindows.cpp | 62 ----- src/ModMan/Web/UiAssets.cpp | 34 --- src/ModMan/Web/UiAssets.h | 12 - src/ModMan/Web/UiCommunication.h | 227 +++++++++--------- .../Web/{WebViewLib.h => WebWindowedLib.h} | 7 +- src/ModMan/main.cpp | 97 ++++---- .../build/HeaderTransformationPlugin.ts | 223 ----------------- src/ModManUi/package.json | 1 + src/ModManUi/src/native/index.ts | 18 +- src/ModManUi/src/stores/AssetStore.ts | 4 +- src/ModManUi/src/stores/UnlinkingStore.ts | 6 +- src/ModManUi/src/stores/ZoneStore.ts | 12 +- .../view/inspect/ZoneInspectorZoneList.vue | 8 +- src/ModManUi/vite.config.ts | 6 +- thirdparty/webview | 1 - thirdparty/webwindowed | 1 + thirdparty/{webview.lua => webwindowed.lua} | 33 +-- 41 files changed, 352 insertions(+), 1116 deletions(-) delete mode 100644 src/ModMan/Web/Platform/AssetHandler.h delete mode 100644 src/ModMan/Web/Platform/FaviconHandler.h delete mode 100644 src/ModMan/Web/Platform/Linux/AssetHandlerLinux.cpp delete mode 100644 src/ModMan/Web/Platform/Linux/FaviconHandlerLinux.cpp delete mode 100644 src/ModMan/Web/Platform/Linux/TitleHandlerLinux.cpp delete mode 100644 src/ModMan/Web/Platform/TitleHandler.h delete mode 100644 src/ModMan/Web/Platform/Windows/AssetHandlerWindows.cpp delete mode 100644 src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.cpp delete mode 100644 src/ModMan/Web/Platform/Windows/TitleHandlerWindows.cpp delete mode 100644 src/ModMan/Web/UiAssets.cpp delete mode 100644 src/ModMan/Web/UiAssets.h rename src/ModMan/Web/{WebViewLib.h => WebWindowedLib.h} (59%) delete mode 100644 src/ModManUi/build/HeaderTransformationPlugin.ts delete mode 160000 thirdparty/webview create mode 160000 thirdparty/webwindowed rename thirdparty/{webview.lua => webwindowed.lua} (80%) diff --git a/.gitmodules b/.gitmodules index ffaaa975..c3a4e5b0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,6 +19,6 @@ [submodule "thirdparty/lz4"] path = thirdparty/lz4 url = https://github.com/lz4/lz4.git -[submodule "thirdparty/webview"] - path = thirdparty/webview - url = https://github.com/Laupetin/webview.git +[submodule "thirdparty/webwindowed"] + path = thirdparty/webwindowed + url = https://github.com/Laupetin/webwindowed.git diff --git a/package-lock.json b/package-lock.json index 4535660f..cbb35b4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -994,6 +994,16 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@laupetin/vite-plugin-cpp-header": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@laupetin/vite-plugin-cpp-header/-/vite-plugin-cpp-header-1.1.0.tgz", + "integrity": "sha512-nUf5yTkL+oy7VxdTOe6jpx3juZksMI7f+zpA9Ns7PSAB+0vcXAa5wtkdFfbn93HaBc2QI3hJZmdfOzsCihD3Ow==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "vite": ">=7.0.0" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", @@ -1847,9 +1857,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "version": "25.9.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.2.tgz", + "integrity": "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -2533,15 +2543,15 @@ } }, "node_modules/@vue/eslint-config-typescript": { - "version": "14.7.0", - "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.7.0.tgz", - "integrity": "sha512-iegbMINVc+seZ/QxtzWiOBozctrHiF2WvGedruu2EbLujg9VuU0FQiNcN2z1ycuaoKKpF4m2qzB5HDEMKbxtIg==", + "version": "14.8.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.8.0.tgz", + "integrity": "sha512-yIquzhXH7ZsrwSSm+rYvoGCRY6wcuF4qBi76e0l7hHLq7YU0f9aC+RcR5fL+XJNfmBZxgX5cVl4sppt4x7ZCBg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^8.56.0", + "@typescript-eslint/utils": "^8.60.0", "fast-glob": "^3.3.3", - "typescript-eslint": "^8.56.0", + "typescript-eslint": "^8.60.0", "vue-eslint-parser": "^10.4.0" }, "engines": { @@ -2559,9 +2569,9 @@ } }, "node_modules/@vue/language-core": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.3.tgz", - "integrity": "sha512-X6p+7nfY7vVT6dQwUJ+v0Jfq/lwIfhL2jMi91dQ3ln4hnlGXlxsDu/FNkeyHYgvYtyQy18ZX76IZy7X4diDbiQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.4.tgz", + "integrity": "sha512-IuHqQ5zGGOE7CXP72VX6A42IVeIzYv4WAhO6arej11TRNqtdZfGyH8Yr2FOCaDX0dSQG+JwULLoFHGY1igYVjQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2638,9 +2648,9 @@ "license": "MIT" }, "node_modules/@vue/test-utils": { - "version": "2.4.10", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.10.tgz", - "integrity": "sha512-SmoZ5EA1kYiAFs9NkYdiFFQF+cSnUwnvlYEbY+DogWQZUiqOm/Y29eSbc5T6yi75SgSF9863SBeXniIEoPajCA==", + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.11.tgz", + "integrity": "sha512-GDqaqZsA6m2E5vNzej0aYiIb6BX8xV9pNSbbbXKOfEYwg7ZNblVX8suyqmUBThq8VIrgAJNxn+z72hVtUeiWHA==", "dev": true, "license": "MIT", "dependencies": { @@ -3428,9 +3438,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.1.tgz", - "integrity": "sha512-cHB0Tf4Duvzwecwd/AqWzZvF/QszE13BhjVUpVXWCy9AeMR5GjkAjP3i85vqgLgOuTmkHR1OJ5oMeqLHtuw8zg==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.2.tgz", + "integrity": "sha512-4g7ZP3pYcuqd7Zp0pzUKcos0W+RkjBz4EGdhJ92FcYk6v03Ti/GK5NwjgsjxHK+98eXDbHeK7VtX1az7/8doZA==", "dev": true, "license": "MIT", "dependencies": { @@ -5144,9 +5154,9 @@ } }, "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", "bin": { @@ -6571,14 +6581,14 @@ } }, "node_modules/vue-tsc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.3.tgz", - "integrity": "sha512-SWUEG7YRUeDJHT7Xsuhf02elYX2gxPzzAII7OxDAh4KNOr4QHQ0Lls0YfnaO5GNd560CwVa2HTfdqmA5MqvRqQ==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.4.tgz", + "integrity": "sha512-XA/JqmQwS2GZmfgpjOEGdrKwaTSEuPwxpHa7/t6f4yiGrJb3gVHTPb9wBfByMNZwQ+xDXs41b8gaS2DKsOozUw==", "dev": true, "license": "MIT", "dependencies": { "@volar/typescript": "2.4.28", - "@vue/language-core": "3.3.3" + "@vue/language-core": "3.3.4" }, "bin": { "vue-tsc": "bin/vue-tsc.js" @@ -6873,27 +6883,28 @@ "vue-router": "5.1.0" }, "devDependencies": { + "@laupetin/vite-plugin-cpp-header": "1.1.0", "@tsconfig/node24": "24.0.4", "@types/jsdom": "28.0.3", - "@types/node": "25.9.1", + "@types/node": "25.9.2", "@vitejs/plugin-vue": "6.0.7", "@vitest/eslint-plugin": "1.6.19", "@vue/eslint-config-prettier": "10.2.0", - "@vue/eslint-config-typescript": "14.7.0", - "@vue/test-utils": "2.4.10", + "@vue/eslint-config-typescript": "14.8.0", + "@vue/test-utils": "2.4.11", "@vue/tsconfig": "0.9.1", "eslint": "10.4.1", - "eslint-plugin-vue": "10.9.1", + "eslint-plugin-vue": "10.9.2", "jiti": "2.7.0", "jsdom": "29.1.1", "npm-run-all2": "9.0.1", - "prettier": "3.8.3", + "prettier": "3.8.4", "sass": "1.100.0", "typescript": "6.0.3", "vite": "8.0.16", "vite-plugin-vue-devtools": "8.1.2", "vitest": "4.1.8", - "vue-tsc": "3.3.3" + "vue-tsc": "3.3.4" } } } diff --git a/premake5.lua b/premake5.lua index ef0a3d56..517387fa 100644 --- a/premake5.lua +++ b/premake5.lua @@ -100,7 +100,7 @@ include "thirdparty/json.lua" include "thirdparty/minilzo.lua" include "thirdparty/minizip.lua" include "thirdparty/salsa20.lua" -include "thirdparty/webview.lua" +include "thirdparty/webwindowed.lua" include "thirdparty/zlib.lua" -- ThirdParty group: All projects that are external dependencies @@ -118,7 +118,7 @@ group "ThirdParty" zlib:project() if _OPTIONS["modman"] then - webview:project() + webwindowed:project() end group "" diff --git a/src/ModMan.lua b/src/ModMan.lua index bfff6fb1..56918233 100644 --- a/src/ModMan.lua +++ b/src/ModMan.lua @@ -57,12 +57,12 @@ function ModMan:project() ObjLoading:include(includes) ObjWriting:include(includes) json:include(includes) - webview:include(includes) + webwindowed:include(includes) links:linkto(Utils) links:linkto(ZoneLoading) links:linkto(ObjLoading) links:linkto(ObjWriting) - links:linkto(webview) + links:linkto(webwindowed) links:linkall() end diff --git a/src/ModMan/Context/ModManContext.h b/src/ModMan/Context/ModManContext.h index ec09e183..6b71b76f 100644 --- a/src/ModMan/Context/ModManContext.h +++ b/src/ModMan/Context/ModManContext.h @@ -2,7 +2,7 @@ #include "FastFileContext.h" #include "Utils/DispatchableThread.h" -#include "Web/WebViewLib.h" +#include "Web/WebWindowedLib.h" #include @@ -14,8 +14,8 @@ public: void Startup(); void Destroy(); - std::unique_ptr m_main_webview; - std::unique_ptr m_dev_tools_webview; + std::shared_ptr m_main_window; + std::shared_ptr m_dev_tools_window; FastFileContext m_fast_file; DispatchableThread m_db_thread; diff --git a/src/ModMan/README.md b/src/ModMan/README.md index e81e5f61..c5fca5e9 100644 --- a/src/ModMan/README.md +++ b/src/ModMan/README.md @@ -31,11 +31,15 @@ npm run dev ## How does it work -ModMan uses [`webview`](https://github.com/Laupetin/webview) for providing a web frontend as a native application. -Unlike frameworks like Electron this does not ship a browser engine alongside it, but instead relies on browser APIs of your OS. -On Windows, this makes use of [WebView2](https://learn.microsoft.com/en-us/microsoft-edge/webview2), on Linux it uses [WebKitGTK](https://webkitgtk.org). +ModMan uses [`webwindowed`](https://github.com/Laupetin/webwindowed) for providing a web frontend as a native +application. +Unlike frameworks like Electron this does not ship a browser engine alongside it, but instead relies on browser APIs of +your OS. +On Windows, this makes use of [WebView2](https://learn.microsoft.com/en-us/microsoft-edge/webview2), on Linux it +uses [WebKitGTK](https://webkitgtk.org). This adds the following dependencies: -- **Windows**: An up-to-date OS with at the very least Windows10. The WebView2 library for development is downloaded by premake. +- **Windows**: An up-to-date OS with at the very least Windows10. The WebView2 library for development is downloaded by + premake. - **Linux**: Developing and using ModMan requires the following dependencies to be installed: `gtk4 webkitgtk-6.0` diff --git a/src/ModMan/Web/Binds/AssetBinds.cpp b/src/ModMan/Web/Binds/AssetBinds.cpp index 47c611f5..0bef17a7 100644 --- a/src/ModMan/Web/Binds/AssetBinds.cpp +++ b/src/ModMan/Web/Binds/AssetBinds.cpp @@ -162,11 +162,11 @@ namespace namespace ui { - void RegisterAssetBinds(webview::webview& wv) + void RegisterAssetBinds(webwindowed::commands_builder& commands) { - Bind>(wv, + Bind>(commands, "getAssetsForZone", - [](const std::string& zoneName) + [](webwindowed::detail::window_base& calling_window, const std::string& zoneName) { return GetZonesForZone(zoneName); }); diff --git a/src/ModMan/Web/Binds/AssetBinds.h b/src/ModMan/Web/Binds/AssetBinds.h index 282e2a5d..68203fdf 100644 --- a/src/ModMan/Web/Binds/AssetBinds.h +++ b/src/ModMan/Web/Binds/AssetBinds.h @@ -1,8 +1,8 @@ #pragma once -#include "Web/WebViewLib.h" +#include "Web/WebWindowedLib.h" namespace ui { - void RegisterAssetBinds(webview::webview& wv); + void RegisterAssetBinds(webwindowed::commands_builder& commands); } // namespace ui diff --git a/src/ModMan/Web/Binds/Binds.cpp b/src/ModMan/Web/Binds/Binds.cpp index e1a13a8c..3b9377c3 100644 --- a/src/ModMan/Web/Binds/Binds.cpp +++ b/src/ModMan/Web/Binds/Binds.cpp @@ -7,11 +7,11 @@ namespace ui { - void RegisterAllBinds(webview::webview& wv) + void RegisterAllBinds(webwindowed::commands_builder& commands) { - RegisterAssetBinds(wv); - RegisterDialogHandlerBinds(wv); - RegisterUnlinkingBinds(wv); - RegisterZoneBinds(wv); + RegisterAssetBinds(commands); + RegisterDialogHandlerBinds(commands); + RegisterUnlinkingBinds(commands); + RegisterZoneBinds(commands); } } // namespace ui diff --git a/src/ModMan/Web/Binds/Binds.h b/src/ModMan/Web/Binds/Binds.h index 3dd717ba..4029879d 100644 --- a/src/ModMan/Web/Binds/Binds.h +++ b/src/ModMan/Web/Binds/Binds.h @@ -1,8 +1,8 @@ #pragma once -#include "Web/WebViewLib.h" +#include "Web/WebWindowedLib.h" namespace ui { - void RegisterAllBinds(webview::webview& wv); + void RegisterAllBinds(webwindowed::commands_builder& commands); } diff --git a/src/ModMan/Web/Binds/DialogBinds.cpp b/src/ModMan/Web/Binds/DialogBinds.cpp index 3d72d9e3..af809599 100644 --- a/src/ModMan/Web/Binds/DialogBinds.cpp +++ b/src/ModMan/Web/Binds/DialogBinds.cpp @@ -32,24 +32,24 @@ namespace NLOHMANN_DEFINE_TYPE_EXTENSION(SaveFileDialogDto, filters); - void ReplyWithDialogResult(webview::webview& wv, + void ReplyWithDialogResult(webwindowed::detail::window_base& calling_window, const std::string& id, const ui::DialogCallbackResultType resultType, const std::optional& result) { if (resultType == ui::DialogCallbackResultType::FAILED) - ui::PromiseReject(wv, id, result); + ui::PromiseReject(calling_window, id, result); else - ui::PromiseResolve(wv, id, result); + ui::PromiseResolve(calling_window, id, result); } - void OpenFileDialogBind(webview::webview& wv, const std::string& id, const std::optional& dto) + void OpenFileDialogBind(webwindowed::detail::window_base& calling_window, const std::string& id, const std::optional& dto) { ui::OpenFileDialog dialog; dialog.SetCallback( - [&wv, id](const ui::DialogCallbackResultType resultType, const std::optional& result) + [&calling_window, id](const ui::DialogCallbackResultType resultType, const std::optional& result) { - ReplyWithDialogResult(wv, id, resultType, result); + ReplyWithDialogResult(calling_window, id, resultType, result); }); if (dto && dto->filters) @@ -63,13 +63,13 @@ namespace dialog.OpenAsync(); } - void SaveFileDialogBind(webview::webview& wv, const std::string& id, const std::optional& dto) + void SaveFileDialogBind(webwindowed::detail::window_base& calling_window, const std::string& id, const std::optional& dto) { ui::SaveFileDialog dialog; dialog.SetCallback( - [&wv, id](const ui::DialogCallbackResultType resultType, const std::optional& result) + [&calling_window, id](const ui::DialogCallbackResultType resultType, const std::optional& result) { - ReplyWithDialogResult(wv, id, resultType, result); + ReplyWithDialogResult(calling_window, id, resultType, result); }); if (dto && dto->filters) @@ -83,13 +83,13 @@ namespace dialog.OpenAsync(); } - void FolderSelectDialogBind(webview::webview& wv, const std::string& id) + void FolderSelectDialogBind(webwindowed::detail::window_base& calling_window, const std::string& id) { ui::FolderSelectDialog dialog; dialog.SetCallback( - [&wv, id](const ui::DialogCallbackResultType resultType, const std::optional& result) + [&calling_window, id](const ui::DialogCallbackResultType resultType, const std::optional& result) { - ReplyWithDialogResult(wv, id, resultType, result); + ReplyWithDialogResult(calling_window, id, resultType, result); }); dialog.OpenAsync(); @@ -98,27 +98,29 @@ namespace namespace ui { - void RegisterDialogHandlerBinds(webview::webview& wv) + void RegisterDialogHandlerBinds(webwindowed::commands_builder& commands) { - BindAsync>(wv, - "openFileDialog", - [&wv](const std::string& id, const std::optional& dto) - { - OpenFileDialogBind(wv, id, dto); - }); + BindAsync>( + commands, + "openFileDialog", + [](const std::string& id, webwindowed::detail::window_base& calling_window, const std::optional& dto) + { + OpenFileDialogBind(calling_window, id, dto); + }); - BindAsync>(wv, - "saveFileDialog", - [&wv](const std::string& id, const std::optional& dto) - { - SaveFileDialogBind(wv, id, dto); - }); + BindAsync>( + commands, + "saveFileDialog", + [](const std::string& id, webwindowed::detail::window_base& calling_window, const std::optional& dto) + { + SaveFileDialogBind(calling_window, id, dto); + }); - BindAsync(wv, + BindAsync(commands, "folderSelectDialog", - [&wv](const std::string& id) + [](const std::string& id, webwindowed::detail::window_base& calling_window) { - FolderSelectDialogBind(wv, id); + FolderSelectDialogBind(calling_window, id); }); } } // namespace ui diff --git a/src/ModMan/Web/Binds/DialogBinds.h b/src/ModMan/Web/Binds/DialogBinds.h index 2d5a923e..111e7008 100644 --- a/src/ModMan/Web/Binds/DialogBinds.h +++ b/src/ModMan/Web/Binds/DialogBinds.h @@ -1,8 +1,8 @@ #pragma once -#include "Web/WebViewLib.h" +#include "Web/WebWindowedLib.h" namespace ui { - void RegisterDialogHandlerBinds(webview::webview& wv); + void RegisterDialogHandlerBinds(webwindowed::commands_builder& commands); } diff --git a/src/ModMan/Web/Binds/UnlinkingBinds.cpp b/src/ModMan/Web/Binds/UnlinkingBinds.cpp index 6ed609eb..2226a93f 100644 --- a/src/ModMan/Web/Binds/UnlinkingBinds.cpp +++ b/src/ModMan/Web/Binds/UnlinkingBinds.cpp @@ -78,22 +78,24 @@ namespace return {}; } - void UnlinkZone(webview::webview& wv, std::string id, std::string zoneName) // NOLINT(performance-unnecessary-value-param) Copy is made for thread safety + void UnlinkZone(webwindowed::detail::window_base& calling_window, + std::string id, + std::string zoneName) // NOLINT(performance-unnecessary-value-param) Copy is made for thread safety { ModManContext::Get().m_db_thread.Dispatch( - [&wv, id, zoneName] + [&calling_window, id, zoneName] { auto result = UnlinkZoneInDbThread(zoneName); if (result) { con::debug("Unlinked zone \"{}\"", zoneName); - ui::PromiseResolve(wv, id, true); + ui::PromiseResolve(calling_window, id, true); } else { con::warn("Failed to unlink zone \"{}\": {}", zoneName, result.error()); - ui::PromiseReject(wv, id, std::move(result).error()); + ui::PromiseReject(calling_window, id, std::move(result).error()); } }); } @@ -107,16 +109,16 @@ namespace ui .zoneName = std::move(zoneName), .percentage = percentage, }; - Notify(*ModManContext::Get().m_main_webview, "zoneUnlinkProgress", dto); + Notify(*ModManContext::Get().m_main_window, "zoneUnlinkProgress", dto); } - void RegisterUnlinkingBinds(webview::webview& wv) + void RegisterUnlinkingBinds(webwindowed::commands_builder& commands) { - BindAsync(wv, + BindAsync(commands, "unlinkZone", - [&wv](const std::string& id, std::string zoneName) + [](const std::string& id, webwindowed::detail::window_base& calling_window, std::string zoneName) { - UnlinkZone(wv, id, std::move(zoneName)); + UnlinkZone(calling_window, id, std::move(zoneName)); }); } } // namespace ui diff --git a/src/ModMan/Web/Binds/UnlinkingBinds.h b/src/ModMan/Web/Binds/UnlinkingBinds.h index 6d2ac0ed..b8a8b79b 100644 --- a/src/ModMan/Web/Binds/UnlinkingBinds.h +++ b/src/ModMan/Web/Binds/UnlinkingBinds.h @@ -1,10 +1,12 @@ #pragma once -#include "Web/WebViewLib.h" +#include "Web/WebWindowedLib.h" + +#include namespace ui { void NotifyZoneUnlinkProgress(std::string zoneName, double percentage); - void RegisterUnlinkingBinds(webview::webview& wv); + void RegisterUnlinkingBinds(webwindowed::commands_builder& commands); } // namespace ui diff --git a/src/ModMan/Web/Binds/ZoneBinds.cpp b/src/ModMan/Web/Binds/ZoneBinds.cpp index 81744136..2bc98679 100644 --- a/src/ModMan/Web/Binds/ZoneBinds.cpp +++ b/src/ModMan/Web/Binds/ZoneBinds.cpp @@ -89,16 +89,18 @@ namespace return result; } - void LoadFastFile(webview::webview& wv, std::string id, std::string path) // NOLINT(performance-unnecessary-value-param) Copy is made for thread safety + void LoadFastFile(webwindowed::detail::window_base& calling_window, + std::string id, + std::string path) // NOLINT(performance-unnecessary-value-param) Copy is made for thread safety { ModManContext::Get().m_db_thread.Dispatch( - [&wv, id, path] + [&calling_window, id, path] { auto maybeZone = ModManContext::Get().m_fast_file.LoadFastFile(path); if (maybeZone) { - ui::PromiseResolve(wv, + ui::PromiseResolve(calling_window, id, ZoneLoadedDto{ .zone = CreateZoneDto(*maybeZone.value()), @@ -108,26 +110,28 @@ namespace else { con::warn("Failed to load zone \"{}\": {}", path, maybeZone.error()); - ui::PromiseReject(wv, id, std::move(maybeZone).error()); + ui::PromiseReject(calling_window, id, std::move(maybeZone).error()); } }); } - void UnloadZone(webview::webview& wv, std::string id, std::string zoneName) // NOLINT(performance-unnecessary-value-param) Copy is made for thread safety + void UnloadZone(webwindowed::detail::window_base& calling_window, + std::string id, + std::string zoneName) // NOLINT(performance-unnecessary-value-param) Copy is made for thread safety { ModManContext::Get().m_db_thread.Dispatch( - [&wv, id, zoneName] + [&calling_window, id, zoneName] { auto result = ModManContext::Get().m_fast_file.UnloadZone(zoneName); if (result) { con::debug("Unloaded zone \"{}\"", zoneName); - ui::PromiseResolve(wv, id, true); + ui::PromiseResolve(calling_window, id, true); } else { con::warn("Failed unloading zone {}: {}", zoneName, result.error()); - ui::PromiseReject(wv, id, std::move(result).error()); + ui::PromiseReject(calling_window, id, std::move(result).error()); } }); } @@ -141,7 +145,7 @@ namespace ui .zoneName = std::move(zoneName), .percentage = percentage, }; - Notify(*ModManContext::Get().m_main_webview, "zoneLoadProgress", dto); + Notify(*ModManContext::Get().m_main_window, "zoneLoadProgress", dto); } void NotifyZoneLoaded(const LoadedZone& loadedZone) @@ -149,7 +153,7 @@ namespace ui const ZoneLoadedDto dto{ .zone = CreateZoneDto(loadedZone), }; - Notify(*ModManContext::Get().m_main_webview, "zoneLoaded", dto); + Notify(*ModManContext::Get().m_main_window, "zoneLoaded", dto); } void NotifyZoneUnloaded(std::string zoneName) @@ -157,30 +161,30 @@ namespace ui const ZoneUnloadedDto dto{ .zoneName = std::move(zoneName), }; - Notify(*ModManContext::Get().m_main_webview, "zoneUnloaded", dto); + Notify(*ModManContext::Get().m_main_window, "zoneUnloaded", dto); } - void RegisterZoneBinds(webview::webview& wv) + void RegisterZoneBinds(webwindowed::commands_builder& commands) { - BindRetOnly>(wv, + BindRetOnly>(commands, "getZones", - [] + [](webwindowed::detail::window_base& calling_window) { return GetLoadedZones(); }); - BindAsync(wv, + BindAsync(commands, "loadFastFile", - [&wv](const std::string& id, std::string path) + [](const std::string& id, webwindowed::detail::window_base& calling_window, std::string path) { - LoadFastFile(wv, id, std::move(path)); + LoadFastFile(calling_window, id, std::move(path)); }); - BindAsync(wv, + BindAsync(commands, "unloadZone", - [&wv](const std::string& id, std::string zoneName) + [](const std::string& id, webwindowed::detail::window_base& calling_window, std::string zoneName) { - UnloadZone(wv, id, std::move(zoneName)); + UnloadZone(calling_window, id, std::move(zoneName)); }); } } // namespace ui diff --git a/src/ModMan/Web/Binds/ZoneBinds.h b/src/ModMan/Web/Binds/ZoneBinds.h index ee2efda8..3cbcef14 100644 --- a/src/ModMan/Web/Binds/ZoneBinds.h +++ b/src/ModMan/Web/Binds/ZoneBinds.h @@ -1,7 +1,7 @@ #pragma once #include "Context/FastFileContext.h" -#include "Web/WebViewLib.h" +#include "Web/WebWindowedLib.h" namespace ui { @@ -9,5 +9,5 @@ namespace ui void NotifyZoneLoaded(const LoadedZone& loadedZone); void NotifyZoneUnloaded(std::string zoneName); - void RegisterZoneBinds(webview::webview& wv); + void RegisterZoneBinds(webwindowed::commands_builder& commands); } // namespace ui diff --git a/src/ModMan/Web/Platform/AssetHandler.h b/src/ModMan/Web/Platform/AssetHandler.h deleted file mode 100644 index 89256ce2..00000000 --- a/src/ModMan/Web/Platform/AssetHandler.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Web/Platform/Platform.h" -#include "Web/WebViewLib.h" - -#include - -namespace ui -{ -#if defined(PLATFORM_WINDOWS) - constexpr auto URL_PREFIX = "http://modman.local/"; -#elif defined(PLATFORM_LINUX) - constexpr auto URL_PREFIX = "modman://localhost/"; -#endif - - void InstallAssetHandler(webview::webview& wv); -} // namespace ui diff --git a/src/ModMan/Web/Platform/FaviconHandler.h b/src/ModMan/Web/Platform/FaviconHandler.h deleted file mode 100644 index 52d2016e..00000000 --- a/src/ModMan/Web/Platform/FaviconHandler.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "Web/WebViewLib.h" - -#include - -namespace ui -{ - void InstallFaviconHandler(webview::webview& wv); -} // namespace ui diff --git a/src/ModMan/Web/Platform/Linux/AssetHandlerLinux.cpp b/src/ModMan/Web/Platform/Linux/AssetHandlerLinux.cpp deleted file mode 100644 index ae3826e3..00000000 --- a/src/ModMan/Web/Platform/Linux/AssetHandlerLinux.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "Web/Platform/AssetHandler.h" -#include "Web/Platform/Platform.h" - -#ifdef PLATFORM_LINUX - -#include "Web/UiAssets.h" - -#include -#include -#include - -namespace -{ - std::unordered_map assetLookup; - - void ModManUriSchemeRequestCb(WebKitURISchemeRequest* request, gpointer user_data) - { - const gchar* asset = webkit_uri_scheme_request_get_path(request); - - 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, ui::GetMimeTypeForFileName(foundUiFile->second.filename)); - g_object_unref(stream); - } - else - { - GError* error = g_error_new(G_SPAWN_ERROR, 123, "Could not find %s.", asset); - webkit_uri_scheme_request_finish_error(request, error); - g_error_free(error); - return; - } - } -} // namespace - -namespace ui -{ - void InstallAssetHandler(webview::webview& wv) - { - const auto widget = static_cast(wv.browser_controller().value()); - const auto webView = WEBKIT_WEB_VIEW(widget); - const auto context = webkit_web_view_get_context(webView); - - assetLookup = ui::BuildUiFileLookup(); - - webkit_web_context_register_uri_scheme(context, "modman", ModManUriSchemeRequestCb, NULL, nullptr); - } -} // namespace ui - -#endif diff --git a/src/ModMan/Web/Platform/Linux/FaviconHandlerLinux.cpp b/src/ModMan/Web/Platform/Linux/FaviconHandlerLinux.cpp deleted file mode 100644 index c0928934..00000000 --- a/src/ModMan/Web/Platform/Linux/FaviconHandlerLinux.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "Web/Platform/FaviconHandler.h" -#include "Web/Platform/Platform.h" - -#ifdef PLATFORM_LINUX - -#include "Web/UiAssets.h" - -#include -#include -#include - -namespace ui -{ - void InstallFaviconHandler(webview::webview& wv) - { - // The icon system on Linux works a bit different than on Windows - // and doesn't really support this kind of dynamic icon setting - // we skip it for now - } -} // namespace ui - -#endif diff --git a/src/ModMan/Web/Platform/Linux/TitleHandlerLinux.cpp b/src/ModMan/Web/Platform/Linux/TitleHandlerLinux.cpp deleted file mode 100644 index 78eb8e1a..00000000 --- a/src/ModMan/Web/Platform/Linux/TitleHandlerLinux.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "Web/Platform/Platform.h" -#include "Web/Platform/TitleHandler.h" - -#ifdef PLATFORM_LINUX - -#include "Web/UiAssets.h" - -#include -#include -#include - -namespace ui -{ - void InstallTitleHandler(webview::webview& wv) - { - const auto webViewWidget = static_cast(wv.browser_controller().value()); - const auto webView = WEBKIT_WEB_VIEW(webViewWidget); - const auto windowWidget = static_cast(wv.window().value()); - const auto window = GTK_WINDOW(windowWidget); - - auto on_title_changed = +[](GtkWidget* widget, GParamSpec paramSpec, GtkWindow* window) - { - gtk_window_set_title(window, webkit_web_view_get_title(WEBKIT_WEB_VIEW(widget))); - }; - - g_signal_connect(G_OBJECT(webView), "notify::title", G_CALLBACK(on_title_changed), (gpointer)window); - } -} // namespace ui - -#endif diff --git a/src/ModMan/Web/Platform/TitleHandler.h b/src/ModMan/Web/Platform/TitleHandler.h deleted file mode 100644 index 4ff8ffae..00000000 --- a/src/ModMan/Web/Platform/TitleHandler.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "Web/WebViewLib.h" - -#include - -namespace ui -{ - void InstallTitleHandler(webview::webview& wv); -} // namespace ui diff --git a/src/ModMan/Web/Platform/Windows/AssetHandlerWindows.cpp b/src/ModMan/Web/Platform/Windows/AssetHandlerWindows.cpp deleted file mode 100644 index 9e2309bb..00000000 --- a/src/ModMan/Web/Platform/Windows/AssetHandlerWindows.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "Web/Platform/AssetHandler.h" -#include "Web/Platform/Platform.h" - -#ifdef PLATFORM_WINDOWS - -#include "PlatformUtilsWindows.h" -#include "Web/UiAssets.h" - -#include -#include -#include -#include -#include -#include - -namespace -{ - constexpr auto LOCALHOST_PREFIX = "http://localhost:"; - - std::unordered_map assetLookup; - - std::wstring HeadersForAssetName(const std::string& assetName, const size_t contentLength) - { - std::wstringstream wss; - - wss << std::format(L"Content-Length: {}\n", contentLength); - wss << L"Content-Type: " << utils::StringToWideString(ui::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 = utils::WideStringToString(wUri); - bool fileFound = false; - -#ifdef _DEBUG - // Allow dev server access - if (uri.starts_with(LOCALHOST_PREFIX)) - return S_OK; -#endif - - if (uri.starts_with(ui::URL_PREFIX)) - { - const auto asset = uri.substr(std::char_traits::length(ui::URL_PREFIX) - 1); - - const auto foundUiFile = assetLookup.find(asset); - if (foundUiFile != assetLookup.end()) - { - const Microsoft::WRL::ComPtr responseStream = - SHCreateMemStream(static_cast(foundUiFile->second.data), static_cast(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 ui -{ - void InstallAssetHandler(webview::webview& wv) - { - assetLookup = ui::BuildUiFileLookup(); - - const auto controller = static_cast(wv.browser_controller().value()); - Microsoft::WRL::ComPtr core; - if (!SUCCEEDED(controller->get_CoreWebView2(&core))) - { - std::cerr << "Failed to get webview\n"; - return; - } - - Microsoft::WRL::ComPtr core22; - if (!SUCCEEDED(core->QueryInterface(IID_PPV_ARGS(&core22)))) - { - std::cerr << "Failed to get core22\n"; - return; - } - - if (!SUCCEEDED(core22->AddWebResourceRequestedFilterWithRequestSourceKinds( - L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL))) - { - std::cerr << "Failed to install request filter\n"; - return; - } - - EventRegistrationToken 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 ui - -#endif diff --git a/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.cpp b/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.cpp deleted file mode 100644 index 856deb68..00000000 --- a/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "Web/Platform/FaviconHandler.h" -#include "Web/Platform/Platform.h" - -#ifdef PLATFORM_WINDOWS - -#include "PlatformUtilsWindows.h" -#include "Web/UiAssets.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - class UniqueHIcon - { - public: - UniqueHIcon() - : m_icon(nullptr) - { - } - - ~UniqueHIcon() - { - if (m_icon) - { - DestroyIcon(m_icon); - m_icon = nullptr; - } - } - - UniqueHIcon(const UniqueHIcon& other) = default; - - UniqueHIcon(UniqueHIcon&& other) noexcept - : m_icon(other.m_icon) - { - other.m_icon = nullptr; - } - - UniqueHIcon& operator=(const UniqueHIcon& other) = default; - - UniqueHIcon& operator=(UniqueHIcon&& other) noexcept - { - m_icon = other.m_icon; - other.m_icon = nullptr; - return *this; - } - - HICON& get() - { - return m_icon; - } - - private: - HICON m_icon; - }; - - std::unordered_map icons; - - HRESULT HandleFaviconChanged(ICoreWebView2_15* core15, HWND window) - { - LPWSTR url; - - if (!SUCCEEDED(core15->get_FaviconUri(&url))) - { - std::cerr << "Failed to get favicon uri\n"; - return S_FALSE; - } - - const std::wstring strUrl(url); - CoTaskMemFree(url); - - if (strUrl.empty()) - { - icons.erase(icons.find(window)); - SendMessage(window, WM_SETICON, ICON_SMALL, (LPARAM)NULL); - } - else - { - if (!SUCCEEDED(core15->GetFavicon(COREWEBVIEW2_FAVICON_IMAGE_FORMAT_PNG, - Microsoft::WRL::Callback( - [window](HRESULT errorCode, IStream* iconStream) -> HRESULT - { - Gdiplus::Bitmap iconBitmap(iconStream); - UniqueHIcon icon; - if (iconBitmap.GetHICON(&icon.get()) == Gdiplus::Status::Ok) - { - SendMessage(window, WM_SETICON, ICON_SMALL, reinterpret_cast(icon.get())); - icons.emplace(window, std::move(icon)).first->second.get(); - } - else - { - icons.erase(icons.find(window)); - SendMessage(window, WM_SETICON, ICON_SMALL, NULL); - } - - return S_OK; - }) - .Get()))) - { - std::cerr << "Failed to get favicon\n"; - return S_FALSE; - } - } - return S_OK; - } -} // namespace - -namespace ui -{ - void InstallFaviconHandler(webview::webview& wv) - { - const auto controller = static_cast(wv.browser_controller().value()); - auto window = static_cast(wv.window().value()); - Microsoft::WRL::ComPtr core; - if (!SUCCEEDED(controller->get_CoreWebView2(&core))) - { - std::cerr << "Failed to get webview\n"; - return; - } - - Microsoft::WRL::ComPtr core15; - if (!SUCCEEDED(core->QueryInterface(IID_PPV_ARGS(&core15)))) - { - std::cerr << "Failed to get core15\n"; - return; - } - - const Gdiplus::GdiplusStartupInput gdiPlusStartupInput; - ULONG_PTR gdiPlusToken; - Gdiplus::GdiplusStartup(&gdiPlusToken, &gdiPlusStartupInput, nullptr); - EventRegistrationToken token; - if (!SUCCEEDED(core15->add_FaviconChanged(Microsoft::WRL::Callback( - [core15, window](ICoreWebView2* sender, IUnknown* args) -> HRESULT - { - return HandleFaviconChanged(core15.Get(), window); - }) - .Get(), - &token))) - { - std::cerr << "Failed to add favicon handler\n"; - } - } -} // namespace ui - -#endif diff --git a/src/ModMan/Web/Platform/Windows/TitleHandlerWindows.cpp b/src/ModMan/Web/Platform/Windows/TitleHandlerWindows.cpp deleted file mode 100644 index 37548484..00000000 --- a/src/ModMan/Web/Platform/Windows/TitleHandlerWindows.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "Web/Platform/Platform.h" -#include "Web/Platform/TitleHandler.h" - -#ifdef PLATFORM_WINDOWS - -#include "PlatformUtilsWindows.h" -#include "Web/UiAssets.h" - -#include -#include -#include -#include -#include -#include - -namespace -{ - HRESULT HandleTitleChanged(ICoreWebView2* core, HWND window) - { - LPWSTR title; - - if (!SUCCEEDED(core->get_DocumentTitle(&title))) - { - std::cerr << "Failed to get title\n"; - return S_FALSE; - } - - SetWindowTextW(window, title); - CoTaskMemFree(title); - - return S_OK; - } -} // namespace - -namespace ui -{ - void InstallTitleHandler(webview::webview& wv) - { - const auto controller = static_cast(wv.browser_controller().value()); - auto window = static_cast(wv.window().value()); - Microsoft::WRL::ComPtr core; - if (!SUCCEEDED(controller->get_CoreWebView2(&core))) - { - std::cerr << "Failed to get webview\n"; - return; - } - - EventRegistrationToken token; - if (!SUCCEEDED(core->add_DocumentTitleChanged(Microsoft::WRL::Callback( - [window](ICoreWebView2* sender, IUnknown* args) -> HRESULT - { - return HandleTitleChanged(sender, window); - }) - .Get(), - &token))) - { - std::cerr << "Failed to add title handler\n"; - } - } -} // namespace ui - -#endif diff --git a/src/ModMan/Web/UiAssets.cpp b/src/ModMan/Web/UiAssets.cpp deleted file mode 100644 index bf5c658d..00000000 --- a/src/ModMan/Web/UiAssets.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "UiAssets.h" - -#include - -namespace ui -{ - std::unordered_map BuildUiFileLookup() - { - std::unordered_map result; - - for (const auto& asset : MOD_MAN_UI_FILES) - { - result.emplace(std::format("/{}", asset.filename), asset); - } - - 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; - } -} // namespace ui diff --git a/src/ModMan/Web/UiAssets.h b/src/ModMan/Web/UiAssets.h deleted file mode 100644 index ea7e185b..00000000 --- a/src/ModMan/Web/UiAssets.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "Web/ViteAssets.h" - -#include -#include - -namespace ui -{ - std::unordered_map BuildUiFileLookup(); - const char* GetMimeTypeForFileName(const std::string& fileName); -} // namespace ui diff --git a/src/ModMan/Web/UiCommunication.h b/src/ModMan/Web/UiCommunication.h index 840d6bcf..a78d39a2 100644 --- a/src/ModMan/Web/UiCommunication.h +++ b/src/ModMan/Web/UiCommunication.h @@ -1,7 +1,7 @@ #pragma once #include "Utils/Logging/Log.h" -#include "WebViewLib.h" +#include "WebWindowedLib.h" #pragma warning(push, 0) #include @@ -9,145 +9,154 @@ namespace ui { - inline void Bind(webview::webview& wv, const std::string& name, std::function fn) + inline void Bind(webwindowed::commands_builder& commands, const std::string& name, std::function fn) { - wv.bind(name, - [fn](const std::string& req) -> std::string - { - fn(); - return ""; - }); + commands.add_command_void(name, + [fn2 = std::move(fn)](webwindowed::detail::window_base& calling_window, std::string message_json_str) -> std::string + { + fn2(calling_window); + return ""; + }); } - template void Bind(webview::webview& wv, const std::string& name, std::function fn) + template + void + Bind(webwindowed::commands_builder& commands, const std::string& name, std::function fn) { - wv.bind(name, - [fn](const std::string& req) -> std::string - { - TInput param; - try - { - const auto json = nlohmann::json::parse(req); - if (!json.is_array()) - { - con::error("Webview params are not an array: {}", req); - return ""; - } + commands.add_command_void(name, + [fn2 = std::move(fn)](webwindowed::detail::window_base& calling_window, std::string message_json_str) -> std::string + { + TInput param; + try + { + const auto json = nlohmann::json::parse(message_json_str); + if (!json.is_array()) + { + con::error("Webwindowed params are not an array: {}", message_json_str); + return ""; + } - if (json.empty()) - param = nlohmann::json().get(); - else - param = json.at(0).get(); - } - catch (const nlohmann::json::exception& e) - { - con::error("Failed to parse json of webview call: {}", e.what()); - return ""; - } + if (json.empty()) + param = nlohmann::json().get(); + else + param = json.at(0).get(); + } + catch (const nlohmann::json::exception& e) + { + con::error("Failed to parse json of webwindowed call: {}", e.what()); + return ""; + } - fn(std::move(param)); - return ""; - }); + fn2(calling_window, std::move(param)); + return ""; + }); } - template void BindRetOnly(webview::webview& wv, const std::string& name, std::function fn) + template + void BindRetOnly(webwindowed::commands_builder& commands, + const std::string& name, + std::function fn) { - wv.bind(name, - [fn](const std::string& req) -> std::string - { - auto result = fn(); + commands.add_command_sync(name, + [fn2 = std::move(fn)](webwindowed::detail::window_base& calling_window, std::string message_json_str) -> std::string + { + auto result = fn2(calling_window); - return nlohmann::json(result).dump(); - }); + return nlohmann::json(result).dump(); + }); } - template void Bind(webview::webview& wv, const std::string& name, std::function fn) + template + void Bind(webwindowed::commands_builder& commands, + const std::string& name, + std::function fn) { - wv.bind(name, - [fn](const std::string& req) -> std::string - { - TInput param; - try - { - const auto json = nlohmann::json::parse(req); - if (!json.is_array()) - { - con::error("Webview params are not an array: {}", req); - return ""; - } + commands.add_command_sync(name, + [fn2 = std::move(fn)](webwindowed::detail::window_base& calling_window, std::string message_json_str) -> std::string + { + TInput param; + try + { + const auto json = nlohmann::json::parse(message_json_str); + if (!json.is_array()) + { + con::error("Webwindowed params are not an array: {}", message_json_str); + return ""; + } - if (json.empty()) - param = nlohmann::json().get(); - else - param = json.at(0).get(); - } - catch (const nlohmann::json::exception& e) - { - con::error("Failed to parse json of webview call: {}", e.what()); - return ""; - } + if (json.empty()) + param = nlohmann::json().get(); + else + param = json.at(0).get(); + } + catch (const nlohmann::json::exception& e) + { + con::error("Failed to parse json of webwindowed call: {}", e.what()); + return ""; + } - auto result = fn(std::move(param)); - return nlohmann::json(result).dump(); - }); + auto result = fn2(calling_window, std::move(param)); + return nlohmann::json(result).dump(); + }); } - inline void BindAsync(webview::webview& wv, const std::string& name, std::function fn) + inline void BindAsync(webwindowed::commands_builder& commands, + const std::string& name, + std::function fn) { - wv.bind( - name, - [fn](const std::string& id, const std::string& req, void* /* arg */) - { - fn(id); - }, - nullptr); + commands.add_command_async(name, + [fn2 = std::move(fn)](std::string promise_id, webwindowed::detail::window_base& calling_window, std::string message_json_str) + { + fn2(promise_id, calling_window); + }); } - template void BindAsync(webview::webview& wv, const std::string& name, std::function fn) + template + void BindAsync(webwindowed::commands_builder& commands, + const std::string& name, + std::function fn) { - wv.bind( - name, - [fn](const std::string& id, const std::string& req, void* /* arg */) - { - TInput param; - try - { - const auto json = nlohmann::json::parse(req); - if (!json.is_array()) - { - con::error("Webview params are not an array: {}", req); - return ""; - } + commands.add_command_async(name, + [fn2 = std::move(fn)](std::string promise_id, webwindowed::detail::window_base& calling_window, std::string message_json_str) + { + TInput param; + try + { + const auto json = nlohmann::json::parse(message_json_str); + if (!json.is_array()) + { + con::error("Webwindowed params are not an array: {}", message_json_str); + return ""; + } - if (json.empty()) - param = nlohmann::json().get(); - else - param = json.at(0).get(); - } - catch (const nlohmann::json::exception& e) - { - con::error("Failed to parse json of webview call: {}", e.what()); - return ""; - } + if (json.empty()) + param = nlohmann::json().get(); + else + param = json.at(0).get(); + } + catch (const nlohmann::json::exception& e) + { + con::error("Failed to parse json of webwindowed call: {}", e.what()); + return ""; + } - fn(id, std::move(param)); - return ""; - }, - nullptr); + fn2(promise_id, calling_window, std::move(param)); + return ""; + }); } - template void PromiseResolve(webview::webview& wv, const std::string& id, const TPayload& payload) + template void PromiseResolve(webwindowed::detail::window_base& window, const std::string& id, const TPayload& payload) { - wv.resolve(id, 0, nlohmann::json(payload).dump()); + window.promise_resolve(id, nlohmann::json(payload).dump()); } - template void PromiseReject(webview::webview& wv, const std::string& id, const TPayload& payload) + template void PromiseReject(webwindowed::detail::window_base& window, const std::string& id, const TPayload& payload) { - wv.resolve(id, 1, nlohmann::json(payload).dump()); + window.promise_reject(id, nlohmann::json(payload).dump()); } - template void Notify(webview::webview& wv, const std::string& eventKey, const TPayload& payload) + template void Notify(webwindowed::detail::window_base& window, const std::string& eventKey, const TPayload& payload) { - wv.notify(eventKey, nlohmann::json(payload).dump()); + window.notify(eventKey, nlohmann::json(payload).dump()); } } // namespace ui diff --git a/src/ModMan/Web/WebViewLib.h b/src/ModMan/Web/WebWindowedLib.h similarity index 59% rename from src/ModMan/Web/WebViewLib.h rename to src/ModMan/Web/WebWindowedLib.h index f120396d..0ebfba05 100644 --- a/src/ModMan/Web/WebViewLib.h +++ b/src/ModMan/Web/WebWindowedLib.h @@ -9,7 +9,12 @@ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif -#include +#include + +// Plugins +#include +#include +#include #ifdef _MSC_VER #pragma warning(pop) diff --git a/src/ModMan/main.cpp b/src/ModMan/main.cpp index ebd59dbc..a43ff958 100644 --- a/src/ModMan/main.cpp +++ b/src/ModMan/main.cpp @@ -2,17 +2,13 @@ #include "GitVersion.h" #include "ModManArgs.h" #include "Web/Binds/Binds.h" -#include "Web/Platform/AssetHandler.h" -#include "Web/Platform/FaviconHandler.h" -#include "Web/Platform/TitleHandler.h" #include "Web/UiCommunication.h" #include "Web/ViteAssets.h" -#include "Web/WebViewLib.h" +#include "Web/WebWindowedLib.h" #include #include #include -#include #ifdef _WIN32 #include @@ -29,22 +25,13 @@ namespace auto& context = ModManContext::Get(); - try - { - context.m_dev_tools_webview = std::make_unique(false, nullptr); - auto& newWindow = *context.m_dev_tools_webview; - ui::InstallFaviconHandler(newWindow); - ui::InstallTitleHandler(newWindow); + context.m_dev_tools_window = std::make_shared(); + auto& newWindow = *context.m_dev_tools_window; - newWindow.set_title("Devtools"); - newWindow.set_size(640, 480, WEBVIEW_HINT_NONE); - newWindow.set_size(480, 320, WEBVIEW_HINT_MIN); - newWindow.navigate(std::format("http://localhost:{}/__devtools__/", VITE_DEV_SERVER_PORT)); - } - catch (const webview::exception& e) - { - std::cerr << e.what() << '\n'; - } + newWindow.set_title("Devtools"); + newWindow.set_window_size(640, 480); + newWindow.set_window_min(480, 320); + (void)newWindow.navigate(std::format("http://localhost:{}/__devtools__/", VITE_DEV_SERVER_PORT)); } #endif @@ -53,47 +40,45 @@ namespace con::debug("Creating main window"); auto& context = ModManContext::Get(); - try - { - context.m_main_webview = std::make_unique( -#ifdef _DEBUG - true, -#else - false, -#endif - nullptr); - auto& newWindow = *context.m_main_webview; - - newWindow.set_title("OpenAssetTools ModMan"); - newWindow.set_size(1280, 640, WEBVIEW_HINT_NONE); - newWindow.set_size(640, 480, WEBVIEW_HINT_MIN); - - ui::InstallAssetHandler(newWindow); - ui::InstallFaviconHandler(newWindow); - ui::InstallTitleHandler(newWindow); - ui::RegisterAllBinds(newWindow); + context.m_main_window = std::make_shared(); + auto& newWindow = *context.m_main_window; #ifdef _DEBUG - newWindow.navigate(VITE_DEV_SERVER ? std::format("http://localhost:{}", VITE_DEV_SERVER_PORT) : std::format("{}index.html", ui::URL_PREFIX)); - - if (VITE_DEV_SERVER) - { - newWindow.dispatch( - [] - { - SpawnDevToolsWindow(); - }); - } -#else - newWindow.navigate(std::format("{}index.html", ui::URL_PREFIX)); + newWindow.set_debug(true); #endif - newWindow.run(); - } - catch (const webview::exception& e) + + newWindow.set_title("OpenAssetTools ModMan"); + // newWindow.set_window_min(640, 480); + newWindow.set_window_size(1280, 640); + + const auto assetHandlerPlugin = std::make_shared(VITE_ASSETS, std::extent_v); + assetHandlerPlugin->set_protocol_name("modman"); + newWindow.register_plugin(assetHandlerPlugin); + + webwindowed::commands_builder commands; + ui::RegisterAllBinds(commands); + newWindow.set_commands(commands.build()); + +#ifdef _DEBUG + auto result = newWindow.navigate(VITE_DEV_SERVER ? std::format("http://localhost:{}", VITE_DEV_SERVER_PORT) + : assetHandlerPlugin->get_url_for_asset("index.html")); + if (VITE_DEV_SERVER) { - std::cerr << e.what() << '\n'; - return 1; + newWindow.dispatch( + [] + { + SpawnDevToolsWindow(); + }); } +#else + auto result = newWindow.navigate(assetHandlerPlugin->get_url_for_asset("index.html")); +#endif + + webwindowed::app app; + app.register_plugin(std::make_shared()); + app.register_plugin(std::make_shared()); + + (void)app.run(context.m_main_window); return 0; } diff --git a/src/ModManUi/build/HeaderTransformationPlugin.ts b/src/ModManUi/build/HeaderTransformationPlugin.ts deleted file mode 100644 index 86e675f6..00000000 --- a/src/ModManUi/build/HeaderTransformationPlugin.ts +++ /dev/null @@ -1,223 +0,0 @@ -import type { Plugin, UserConfig } from "vite"; -import type { OutputAsset, OutputChunk } from "rolldown"; -import path from "node:path"; -import fs from "node:fs"; - -type MinimalOutputAsset = Pick; -type MinimalOutputChunk = Pick; -type MinimalOutputBundle = Record; - -interface PublicDirFile { - fullPath: string; - relativePath: string; -} - -const textEncoder = new TextEncoder(); - -function getPublicDirFiles(publicDir?: string): PublicDirFile[] { - if (!publicDir) return []; - - const result: PublicDirFile[] = []; - const files = fs.readdirSync(publicDir, { recursive: true, withFileTypes: true }); - for (const file of files) { - if (!file.isFile()) continue; - const fullPath = path.join(file.parentPath, file.name); - let relativePath = path.relative(publicDir, fullPath).replaceAll(/\\/g, "/"); - if (relativePath.startsWith("./")) { - relativePath = relativePath.substring(2); - } - - result.push({ - fullPath, - relativePath, - }); - } - - return result; -} - -function createVarName(fileName: string) { - return fileName.replaceAll(/[\\/]/g, "__").replaceAll(/[\.-]/g, "_").toUpperCase(); -} - -function transformAsset(asset: MinimalOutputAsset) { - const varName = createVarName(asset.fileName); - - let buffer: Uint8Array; - if (typeof asset.source === "string") { - buffer = textEncoder.encode(asset.source); - } else { - buffer = asset.source; - } - - const bytes = [...buffer].map((v) => String(v)).join(","); - - return `constexpr const unsigned char ${varName}[] {${bytes}}; -`; -} - -function transformChunk(chunk: MinimalOutputChunk) { - const varName = createVarName(chunk.fileName); - const buffer = textEncoder.encode(chunk.code); - const bytes = [...buffer].map((v) => String(v)).join(","); - - return `constexpr const unsigned char ${varName}[] {${bytes}}; -`; -} - -function transformPublicFile(publicFile: PublicDirFile) { - const varName = createVarName(publicFile.relativePath); - const bytes = [...fs.readFileSync(publicFile.fullPath)].map((v) => String(v)).join(","); - - return `constexpr const unsigned char ${varName}[] {${bytes}}; -`; -} - -function writeHeader( - bundle: MinimalOutputBundle, - outputDir?: string, - options?: HeaderTransformationPluginOptions, - publicDir?: string, - devServerPort?: number, -) { - const outputPath = options?.outputPath ?? path.join(outputDir ?? "dist", "ViteAssets.h"); - const outputPathParentDir = path.dirname(outputPath); - - fs.mkdirSync(outputPathParentDir, { recursive: true }); - - const fd = fs.openSync(outputPath, "w"); - const includeFileEnumeration = options?.includeFileEnumeration ?? true; - - fs.writeSync( - fd, - `#pragma once - -`, - ); - - if (includeFileEnumeration) { - fs.writeSync( - fd, - `#include -#include - -`, - ); - } - - fs.writeSync( - fd, - `constexpr auto VITE_DEV_SERVER = ${devServerPort ? "true" : "false"}; -constexpr auto VITE_DEV_SERVER_PORT = ${devServerPort ? String(devServerPort) : "-1"}; -`, - ); - - const fileNames: string[] = []; - for (const curBundle of Object.values(bundle)) { - if (curBundle.type === "asset") { - fs.writeSync(fd, transformAsset(curBundle)); - } else { - fs.writeSync(fd, transformChunk(curBundle)); - } - fileNames.push(curBundle.fileName); - } - for (const publicDirFile of getPublicDirFiles(publicDir)) { - fs.writeSync(fd, transformPublicFile(publicDirFile)); - fileNames.push(publicDirFile.relativePath); - } - - if (includeFileEnumeration) { - fs.writeSync( - fd, - ` -struct UiFile -{ - const char* filename; - const void* data; - const size_t dataSize; -}; - -static inline const UiFile MOD_MAN_UI_FILES[] { -`, - ); - - let index = 0; - for (const fileName of fileNames) { - const varName = createVarName(fileName); - - let prefix = " "; - if (index > 0) { - prefix = `, - `; - } - - fs.writeSync( - fd, - `${prefix}{ "${fileName}", ${varName}, std::extent_v }`, - ); - index++; - } - - fs.writeSync( - fd, - ` -}; -`, - ); - - fs.closeSync(fd); - } -} - -export interface HeaderTransformationPluginOptions { - outputPath?: string; - includeFileEnumeration?: boolean; -} - -export default function headerTransformationPlugin( - options?: HeaderTransformationPluginOptions, -): Plugin { - let writeServerActive = false; - let writeBundleActive = false; - let publicDir: string | undefined = undefined; - - return { - name: "vite-plugin-header-transformation", - enforce: "post", - config(userOptions: UserConfig, env) { - if (env.command === "serve") { - writeServerActive = true; - } else { - writeBundleActive = true; - } - - if (typeof userOptions.publicDir === "string") { - publicDir = userOptions.publicDir; - } - }, - configureServer(server) { - if (!writeServerActive) { - return; - } - server.httpServer?.once("listening", () => { - writeHeader( - { - // We need at least one array entry for MSVC - dummyfile: { type: "chunk", fileName: "dummyfile", code: "dummy" }, - }, - server.config.build.outDir, - options, - publicDir, - server.config.server.port, - ); - }); - }, - writeBundle(outputOptions, bundle) { - if (!writeBundleActive) { - return; - } - - writeHeader(bundle, outputOptions.dir, options, publicDir); - }, - }; -} diff --git a/src/ModManUi/package.json b/src/ModManUi/package.json index 3b737c9a..8991dd2d 100644 --- a/src/ModManUi/package.json +++ b/src/ModManUi/package.json @@ -22,6 +22,7 @@ "vue-router": "5.1.0" }, "devDependencies": { + "@laupetin/vite-plugin-cpp-header": "1.1.0", "@tsconfig/node24": "24.0.4", "@types/jsdom": "28.0.3", "@types/node": "25.9.2", diff --git a/src/ModManUi/src/native/index.ts b/src/ModManUi/src/native/index.ts index ca0c185f..a6378d25 100644 --- a/src/ModManUi/src/native/index.ts +++ b/src/ModManUi/src/native/index.ts @@ -7,20 +7,22 @@ export type NativeMethods = AssetBinds & DialogBinds & UnlinkingBinds & ZoneBind type NativeEventMap = UnlinkingEventMap & ZoneEventMap; -type WebViewExtensions = { - webviewBinds: NativeMethods; - webviewAddEventListener( +type WebWindowedExtensions = { + webwindowedBinds: NativeMethods; + webwindowedAddEventListener( eventKey: K, callback: (payload: NativeEventMap[K]) => void, ): void; - webviewRemoveEventListener( + webwindowedRemoveEventListener( eventKey: K, callback: (payload: NativeEventMap[K]) => void, ): boolean; }; -const windowWithWebViewExtensions = window as typeof window & WebViewExtensions; +const windowWithWebWindowedExtensions = window as typeof window & WebWindowedExtensions; -export const webviewBinds = windowWithWebViewExtensions.webviewBinds; -export const webviewAddEventListener = windowWithWebViewExtensions.webviewAddEventListener; -export const webviewRemoveEventListener = windowWithWebViewExtensions.webviewRemoveEventListener; +export const webwindowedBinds = windowWithWebWindowedExtensions.webwindowedBinds; +export const webwindowedAddEventListener = + windowWithWebWindowedExtensions.webwindowedAddEventListener; +export const webwindowedRemoveEventListener = + windowWithWebWindowedExtensions.webwindowedRemoveEventListener; diff --git a/src/ModManUi/src/stores/AssetStore.ts b/src/ModManUi/src/stores/AssetStore.ts index 80117f97..b8755d7f 100644 --- a/src/ModManUi/src/stores/AssetStore.ts +++ b/src/ModManUi/src/stores/AssetStore.ts @@ -1,7 +1,7 @@ import { computed, ref } from "vue"; import { defineStore } from "pinia"; import type { ZoneAssetsDto } from "@/native/AssetBinds"; -import { webviewBinds } from "@/native"; +import { webwindowedBinds } from "@/native"; export const useAssetStore = defineStore("asset", () => { const zoneName = ref(null); @@ -21,7 +21,7 @@ export const useAssetStore = defineStore("asset", () => { // Only load assets when there is a new zone name specified if (!newZoneName) return; - webviewBinds.getAssetsForZone(newZoneName).then((res) => { + webwindowedBinds.getAssetsForZone(newZoneName).then((res) => { if (zoneName.value === newZoneName) { assetsOfZone.value = res; } diff --git a/src/ModManUi/src/stores/UnlinkingStore.ts b/src/ModManUi/src/stores/UnlinkingStore.ts index 6f10cc27..d178ffad 100644 --- a/src/ModManUi/src/stores/UnlinkingStore.ts +++ b/src/ModManUi/src/stores/UnlinkingStore.ts @@ -1,6 +1,6 @@ import { ref } from "vue"; import { defineStore } from "pinia"; -import { webviewAddEventListener, webviewBinds } from "@/native"; +import { webwindowedAddEventListener, webwindowedBinds } from "@/native"; export const useUnlinkingStore = defineStore("unlinking", () => { const isUnlinking = ref(false); @@ -11,7 +11,7 @@ export const useUnlinkingStore = defineStore("unlinking", () => { isUnlinking.value = true; lastPercentage.value = 0; failureMessage.value = null; - return webviewBinds + return webwindowedBinds .unlinkZone(zoneName) .catch((e: string) => { console.error("Failed to unlink fastfile:", e); @@ -23,7 +23,7 @@ export const useUnlinkingStore = defineStore("unlinking", () => { }); } - webviewAddEventListener("zoneUnlinkProgress", (dto) => { + webwindowedAddEventListener("zoneUnlinkProgress", (dto) => { lastPercentage.value = dto.percentage; }); diff --git a/src/ModManUi/src/stores/ZoneStore.ts b/src/ModManUi/src/stores/ZoneStore.ts index b8a5f4b5..0d9e7d26 100644 --- a/src/ModManUi/src/stores/ZoneStore.ts +++ b/src/ModManUi/src/stores/ZoneStore.ts @@ -1,6 +1,6 @@ import { computed, ref } from "vue"; import { defineStore } from "pinia"; -import { webviewAddEventListener, webviewBinds } from "@/native"; +import { webwindowedAddEventListener, webwindowedBinds } from "@/native"; import type { ZoneDto, ZoneLoadedDto } from "@/native/ZoneBinds"; export const useZoneStore = defineStore("zone", () => { @@ -21,7 +21,7 @@ export const useZoneStore = defineStore("zone", () => { zonesCurrentlyBeingLoaded.value.push(expectedZoneName); lastPercentageByZoneName.value[expectedZoneName] = 0; - return webviewBinds + return webwindowedBinds .loadFastFile(fastFilePath) .catch((e: string) => { console.error("Failed to load fastfile:", e); @@ -44,21 +44,21 @@ export const useZoneStore = defineStore("zone", () => { } // Initially get all loaded zones - webviewBinds.getZones().then((allZones) => { + webwindowedBinds.getZones().then((allZones) => { loadedZones.value = allZones; }); - webviewAddEventListener("zoneLoadProgress", (dto) => { + webwindowedAddEventListener("zoneLoadProgress", (dto) => { if (lastPercentageByZoneName.value[dto.zoneName] !== undefined) { lastPercentageByZoneName.value[dto.zoneName] = dto.percentage; } }); - webviewAddEventListener("zoneLoaded", (dto) => { + webwindowedAddEventListener("zoneLoaded", (dto) => { loadedZones.value.push(dto.zone); }); - webviewAddEventListener("zoneUnloaded", (dto) => { + webwindowedAddEventListener("zoneUnloaded", (dto) => { const index = loadedZones.value.findIndex((zone) => zone.name === dto.zoneName); if (index >= 0) { loadedZones.value.splice(index, 1); diff --git a/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue b/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue index 4a10814d..02d2c51e 100644 --- a/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue +++ b/src/ModManUi/src/view/inspect/ZoneInspectorZoneList.vue @@ -4,7 +4,7 @@ import ProgressBar from "primevue/progressbar"; import Listbox from "primevue/listbox"; import { computed } from "vue"; import { useZoneStore } from "@/stores/ZoneStore"; -import { webviewBinds } from "@/native"; +import { webwindowedBinds } from "@/native"; interface SelectableZone { isLoading: boolean; @@ -15,7 +15,9 @@ const zoneStore = useZoneStore(); const selectedZone = defineModel("selectedZone"); async function openFastFileSelect() { - return await webviewBinds.openFileDialog({ filters: [{ name: "Fastfiles", filter: "*.ff" }] }); + return await webwindowedBinds.openFileDialog({ + filters: [{ name: "Fastfiles", filter: "*.ff" }], + }); } async function onOpenFastFileClick() { @@ -51,7 +53,7 @@ const availableZones = computed(() => { function onUnloadClicked() { if (!selectedZone.value) return; - webviewBinds.unloadZone(selectedZone.value).catch((e: string) => { + webwindowedBinds.unloadZone(selectedZone.value).catch((e: string) => { console.error("Failed to unload zone:", e); }); } diff --git a/src/ModManUi/vite.config.ts b/src/ModManUi/vite.config.ts index 0409fc43..5b0b15e1 100644 --- a/src/ModManUi/vite.config.ts +++ b/src/ModManUi/vite.config.ts @@ -3,13 +3,13 @@ import { fileURLToPath, URL } from "node:url"; import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import vueDevTools from "vite-plugin-vue-devtools"; -import headerTransformationPlugin from "./build/HeaderTransformationPlugin"; +import PluginCppHeader from "@laupetin/vite-plugin-cpp-header"; // https://vite.dev/config/ export default defineConfig({ build: { emptyOutDir: true, - rollupOptions: { + rolldownOptions: { output: { assetFileNames: "[name][extname]", entryFileNames: "[name].js", @@ -21,7 +21,7 @@ export default defineConfig({ plugins: [ vue(), vueDevTools(), - headerTransformationPlugin({ + PluginCppHeader({ outputPath: fileURLToPath( new URL("../../build/src/ModMan/Web/ViteAssets.h", import.meta.url), ), diff --git a/thirdparty/webview b/thirdparty/webview deleted file mode 160000 index 0ae23fc2..00000000 --- a/thirdparty/webview +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0ae23fc2da788d5089bc01aea60ef1ac2543fc50 diff --git a/thirdparty/webwindowed b/thirdparty/webwindowed new file mode 160000 index 00000000..1e5e89d0 --- /dev/null +++ b/thirdparty/webwindowed @@ -0,0 +1 @@ +Subproject commit 1e5e89d054386d821e82b8ace4fa38e52f1b5bef diff --git a/thirdparty/webview.lua b/thirdparty/webwindowed.lua similarity index 80% rename from thirdparty/webview.lua rename to thirdparty/webwindowed.lua index 20fecd52..3602de09 100644 --- a/thirdparty/webview.lua +++ b/thirdparty/webwindowed.lua @@ -1,20 +1,17 @@ -webview = {} +webwindowed = {} -function webview:include(includes) +function webwindowed:include(includes) if includes:handle(self:name()) then includedirs { - path.join(ThirdPartyFolder(), "webview/core/include"), + path.join(ThirdPartyFolder(), "webwindowed/include"), path.join(self:msWebviewDir(), "build/native/include") } end end -function webview:link(links) +function webwindowed:link(links) if os.host() == "windows" then - links:add("WebView2LoaderStatic") - links:add("gdiplus.lib") - filter "platforms:x86" libdirs { path.join(self:msWebviewDir(), "build/native/x86") @@ -30,32 +27,26 @@ function webview:link(links) links:add(self:name()) end -function webview:use() +function webwindowed:use() end -function webview:name() - return "webview" +function webwindowed:name() + return "webwindowed" end -function webview:project() +function webwindowed:project() local folder = ThirdPartyFolder() local includes = Includes:create() project(self:name()) targetdir(TargetDirectoryLib) location "%{wks.location}/thirdparty/%{prj.name}" - kind "StaticLib" + kind "Utility" language "C++" files { - path.join(folder, "webview/core/include/**.h"), - path.join(folder, "webview/core/include/**.hh"), - path.join(folder, "webview/core/src/**.cc") - } - - defines { - "WEBVIEW_STATIC" + path.join(folder, "webwindowed/include/**.hpp") } if os.host() == "windows" then @@ -73,11 +64,11 @@ function webview:project() warnings "off" end -function webview:msWebviewDir() +function webwindowed:msWebviewDir() return path.join(BuildFolder(), "thirdparty/ms-webview2") end -function webview:installWebview2() +function webwindowed:installWebview2() local version = "1.0.3485.44" local webviewDir = self:msWebviewDir() local versionFile = path.join(webviewDir, "ms-webview2.txt")