From 563a497d7f842c760ad05a0017059e7781c2b810 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Tue, 13 Dec 2022 13:51:48 +0200 Subject: [PATCH] feat(webview2): add theme API, closes #806 (#809) --- .changes/webview2-theme.md | 5 +++++ src/webview/mod.rs | 27 ++++++++++++++++++++++++ src/webview/webview2/mod.rs | 42 ++++++++++++++++++++++++++----------- 3 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 .changes/webview2-theme.md diff --git a/.changes/webview2-theme.md b/.changes/webview2-theme.md new file mode 100644 index 000000000..485f3f1e8 --- /dev/null +++ b/.changes/webview2-theme.md @@ -0,0 +1,5 @@ +--- +"wry": "patch" +--- + +On Windows, Add `WebviewBuilderExtWindows::with_theme` and `WebviewExtWindows::set_theme` to change webview2 theme. \ No newline at end of file diff --git a/src/webview/mod.rs b/src/webview/mod.rs index c9dffb196..1c541aa80 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -256,9 +256,11 @@ impl Default for WebViewAttributes { } #[cfg(windows)] +#[derive(Clone)] pub(crate) struct PlatformSpecificWebViewAttributes { additional_browser_args: Option, browser_accelerator_keys: bool, + theme: Option, } #[cfg(windows)] impl Default for PlatformSpecificWebViewAttributes { @@ -266,6 +268,7 @@ impl Default for PlatformSpecificWebViewAttributes { Self { additional_browser_args: None, browser_accelerator_keys: true, // This is WebView2's default behavior + theme: None, } } } @@ -610,6 +613,11 @@ pub trait WebViewBuilderExtWindows { /// /// https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings#arebrowseracceleratorkeysenabled fn with_browser_accelerator_keys(self, enabled: bool) -> Self; + + /// Specifies the theme of webview2. This affects things like `prefers-color-scheme`. + /// + /// Defaults to [`Theme::Auto`] which will follow the OS defaults. + fn with_theme(self, theme: Theme) -> Self; } #[cfg(windows)] @@ -623,6 +631,11 @@ impl WebViewBuilderExtWindows for WebViewBuilder<'_> { self.platform_specific.browser_accelerator_keys = enabled; self } + + fn with_theme(mut self, theme: Theme) -> Self { + self.platform_specific.theme = Some(theme); + self + } } /// The fundamental type to present a [`WebView`]. @@ -796,6 +809,9 @@ pub fn webview_version() -> Result { pub trait WebviewExtWindows { /// Returns WebView2 Controller fn controller(&self) -> ICoreWebView2Controller; + + // Changes the webview2 theme. + fn set_theme(&self, theme: Theme); } #[cfg(target_os = "windows")] @@ -803,6 +819,10 @@ impl WebviewExtWindows for WebView { fn controller(&self) -> ICoreWebView2Controller { self.webview.controller.clone() } + + fn set_theme(&self, theme: Theme) { + self.webview.set_theme(theme) + } } /// Additional methods on `WebView` that are specific to Linux. @@ -858,6 +878,13 @@ impl WebviewExtAndroid for WebView { } } +#[derive(Debug, Clone, Copy)] +pub enum Theme { + Dark, + Light, + Auto, +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/webview/webview2/mod.rs b/src/webview/webview2/mod.rs index da3fb628b..bd2eb34e6 100644 --- a/src/webview/webview2/mod.rs +++ b/src/webview/webview2/mod.rs @@ -42,6 +42,8 @@ use webview2_com::{Microsoft::Web::WebView2::Win32::*, *}; use crate::application::{platform::windows::WindowExtWindows, window::Window}; use http::Request; +use super::Theme; + impl From for Error { fn from(err: webview2_com::Error) -> Self { Error::WebView2Error(err) @@ -69,17 +71,9 @@ impl InnerWebView { let file_drop_handler = attributes.file_drop_handler.take(); let file_drop_window = window.clone(); - let browser_accelerator_keys = pl_attrs.browser_accelerator_keys; - let env = Self::create_environment(&web_context, pl_attrs)?; + let env = Self::create_environment(&web_context, pl_attrs.clone())?; let controller = Self::create_controller(hwnd, &env)?; - let webview = Self::init_webview( - window, - hwnd, - attributes, - &env, - &controller, - browser_accelerator_keys, - )?; + let webview = Self::init_webview(window, hwnd, attributes, &env, &controller, pl_attrs)?; if let Some(file_drop_handler) = file_drop_handler { let mut controller = FileDropController::new(); @@ -198,11 +192,16 @@ impl InnerWebView { mut attributes: WebViewAttributes, env: &ICoreWebView2Environment, controller: &ICoreWebView2Controller, - browser_accelerator_keys: bool, + pl_attrs: super::PlatformSpecificWebViewAttributes, ) -> webview2_com::Result { let webview = unsafe { controller.CoreWebView2() }.map_err(webview2_com::Error::WindowsError)?; + // theme + if let Some(theme) = pl_attrs.theme { + set_theme(&webview, theme); + } + // background color if !attributes.transparent { if let Some(background_color) = attributes.background_color { @@ -255,7 +254,7 @@ impl InnerWebView { .SetAreDevToolsEnabled(true) .map_err(webview2_com::Error::WindowsError)?; } - if !browser_accelerator_keys { + if !pl_attrs.browser_accelerator_keys { if let Ok(settings3) = settings.cast::() { settings3 .SetAreBrowserAcceleratorKeysEnabled(false) @@ -828,6 +827,10 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_ let url = encode_wide(url); let _ = unsafe { self.webview.Navigate(PCWSTR::from_raw(url.as_ptr())) }; } + + pub fn set_theme(&self, theme: Theme) { + set_theme(&self.webview, theme); + } } fn encode_wide(string: impl AsRef) -> Vec { @@ -858,6 +861,21 @@ pub fn set_background_color( } } +fn set_theme(webview: &ICoreWebView2, theme: Theme) { + unsafe { + let _ = webview + .cast::() + .unwrap() + .Profile() + .unwrap() + .SetPreferredColorScheme(match theme { + Theme::Dark => COREWEBVIEW2_PREFERRED_COLOR_SCHEME_DARK, + Theme::Light => COREWEBVIEW2_PREFERRED_COLOR_SCHEME_LIGHT, + Theme::Auto => COREWEBVIEW2_PREFERRED_COLOR_SCHEME_AUTO, + }); + } +} + pub fn platform_webview_version() -> Result { let mut versioninfo = PWSTR::null(); unsafe { GetAvailableCoreWebView2BrowserVersionString(PCWSTR::null(), &mut versioninfo) }