diff --git a/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.cpp b/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.cpp new file mode 100644 index 00000000..63872934 --- /dev/null +++ b/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.cpp @@ -0,0 +1,151 @@ +#include "AssetHandlerWindows.h" + +#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE) + +#include "PlatformUtilsWindows.h" +#include "Web/UiAssets.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace PLATFORM_NAMESPACE_WINDOWS; + +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 PLATFORM_NAMESPACE_WINDOWS +{ + 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 PLATFORM_NAMESPACE_WINDOWS + +#endif diff --git a/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.h b/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.h new file mode 100644 index 00000000..83763da8 --- /dev/null +++ b/src/ModMan/Web/Platform/Windows/FaviconHandlerWindows.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Web/Platform/Platform.h" + +#include + +#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE) + +#include "Web/WebViewLib.h" + +namespace PLATFORM_NAMESPACE_WINDOWS +{ + void InstallFaviconHandler(webview::webview& wv); +} // namespace PLATFORM_NAMESPACE_WINDOWS + +#endif diff --git a/src/ModMan/main.cpp b/src/ModMan/main.cpp index b7f82fa6..14384981 100644 --- a/src/ModMan/main.cpp +++ b/src/ModMan/main.cpp @@ -3,6 +3,7 @@ #include "ModManArgs.h" #include "Web/Binds/Binds.h" #include "Web/Platform/AssetHandler.h" +#include "Web/Platform/Windows/FaviconHandlerWindows.h" #include "Web/UiCommunication.h" #include "Web/ViteAssets.h" #include "Web/WebViewLib.h" @@ -32,6 +33,7 @@ namespace { context.m_dev_tools_webview = std::make_unique(false, nullptr); auto& newWindow = *context.m_dev_tools_webview; + InstallFaviconHandler(newWindow); newWindow.set_title("Devtools"); newWindow.set_size(640, 480, WEBVIEW_HINT_NONE); @@ -66,6 +68,7 @@ namespace newWindow.set_size(640, 480, WEBVIEW_HINT_MIN); InstallAssetHandler(newWindow); + InstallFaviconHandler(newWindow); ui::RegisterAllBinds(newWindow); #ifdef _DEBUG diff --git a/thirdparty/webview.lua b/thirdparty/webview.lua index 5fef3927..20fecd52 100644 --- a/thirdparty/webview.lua +++ b/thirdparty/webview.lua @@ -13,6 +13,7 @@ function webview:link(links) if os.host() == "windows" then links:add("WebView2LoaderStatic") + links:add("gdiplus.lib") filter "platforms:x86" libdirs {