Skip to content

Commit

Permalink
feat(webview2): add theme API, closes #806 (#809)
Browse files Browse the repository at this point in the history
  • Loading branch information
amrbashir committed Dec 13, 2022
1 parent 4b27b07 commit 563a497
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changes/webview2-theme.md
@@ -0,0 +1,5 @@
---
"wry": "patch"
---

On Windows, Add `WebviewBuilderExtWindows::with_theme` and `WebviewExtWindows::set_theme` to change webview2 theme.
27 changes: 27 additions & 0 deletions src/webview/mod.rs
Expand Up @@ -256,16 +256,19 @@ impl Default for WebViewAttributes {
}

#[cfg(windows)]
#[derive(Clone)]
pub(crate) struct PlatformSpecificWebViewAttributes {
additional_browser_args: Option<String>,
browser_accelerator_keys: bool,
theme: Option<Theme>,
}
#[cfg(windows)]
impl Default for PlatformSpecificWebViewAttributes {
fn default() -> Self {
Self {
additional_browser_args: None,
browser_accelerator_keys: true, // This is WebView2's default behavior
theme: None,
}
}
}
Expand Down Expand Up @@ -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)]
Expand All @@ -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`].
Expand Down Expand Up @@ -796,13 +809,20 @@ pub fn webview_version() -> Result<String> {
pub trait WebviewExtWindows {
/// Returns WebView2 Controller
fn controller(&self) -> ICoreWebView2Controller;

// Changes the webview2 theme.
fn set_theme(&self, theme: Theme);
}

#[cfg(target_os = "windows")]
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.
Expand Down Expand Up @@ -858,6 +878,13 @@ impl WebviewExtAndroid for WebView {
}
}

#[derive(Debug, Clone, Copy)]
pub enum Theme {
Dark,
Light,
Auto,
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
42 changes: 30 additions & 12 deletions src/webview/webview2/mod.rs
Expand Up @@ -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<webview2_com::Error> for Error {
fn from(err: webview2_com::Error) -> Self {
Error::WebView2Error(err)
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -198,11 +192,16 @@ impl InnerWebView {
mut attributes: WebViewAttributes,
env: &ICoreWebView2Environment,
controller: &ICoreWebView2Controller,
browser_accelerator_keys: bool,
pl_attrs: super::PlatformSpecificWebViewAttributes,
) -> webview2_com::Result<ICoreWebView2> {
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 {
Expand Down Expand Up @@ -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::<ICoreWebView2Settings3>() {
settings3
.SetAreBrowserAcceleratorKeysEnabled(false)
Expand Down Expand Up @@ -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<std::ffi::OsStr>) -> Vec<u16> {
Expand Down Expand Up @@ -858,6 +861,21 @@ pub fn set_background_color(
}
}

fn set_theme(webview: &ICoreWebView2, theme: Theme) {
unsafe {
let _ = webview
.cast::<ICoreWebView2_13>()
.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<String> {
let mut versioninfo = PWSTR::null();
unsafe { GetAvailableCoreWebView2BrowserVersionString(PCWSTR::null(), &mut versioninfo) }
Expand Down

0 comments on commit 563a497

Please sign in to comment.