Skip to main content

windows_webview/
options.rs

1use super::*;
2use windows_core::implement_decl;
3
4/// The scrollbar appearance WebView2 uses for pages, set with
5/// [`EnvironmentOptions::scrollbar_style`].
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
7pub enum ScrollBarStyle {
8    /// The browser default scrollbars.
9    #[default]
10    Default,
11    /// Thin overlay scrollbars in the Fluent style.
12    FluentOverlay,
13}
14
15impl ScrollBarStyle {
16    fn to_raw(self) -> COREWEBVIEW2_SCROLLBAR_STYLE {
17        match self {
18            Self::Default => 0,
19            Self::FluentOverlay => 1,
20        }
21    }
22}
23
24/// Configures the WebView2 [`Environment`], including the user data folder, the
25/// browser executable folder, additional browser command-line arguments, and the
26/// UI language. Build one with the fluent setters and pass it to
27/// [`Environment::with_options`].
28///
29/// ```
30/// use windows_webview::EnvironmentOptions;
31///
32/// let options = EnvironmentOptions::new()
33///     .user_data_folder(r"C:\MyApp\WebView2")
34///     .additional_browser_arguments("--disable-features=msSmartScreenProtection")
35///     .language("en-US");
36/// ```
37#[derive(Clone, Debug, Default)]
38pub struct EnvironmentOptions {
39    browser_executable_folder: Option<String>,
40    user_data_folder: Option<String>,
41    additional_browser_arguments: Option<String>,
42    language: Option<String>,
43    target_compatible_browser_version: Option<String>,
44    allow_single_sign_on_using_os_primary_account: bool,
45    are_browser_extensions_enabled: bool,
46    scrollbar_style: ScrollBarStyle,
47}
48
49impl EnvironmentOptions {
50    /// Creates options with all WebView2 defaults.
51    pub fn new() -> Self {
52        Self::default()
53    }
54
55    /// Sets the folder containing the WebView2 browser (Edge) binaries to use
56    /// instead of the installed runtime.
57    pub fn browser_executable_folder(mut self, value: impl Into<String>) -> Self {
58        self.browser_executable_folder = Some(value.into());
59        self
60    }
61
62    /// Sets the folder where WebView2 stores its user data (cache, cookies, ...).
63    pub fn user_data_folder(mut self, value: impl Into<String>) -> Self {
64        self.user_data_folder = Some(value.into());
65        self
66    }
67
68    /// Sets additional command-line arguments passed to the browser process.
69    pub fn additional_browser_arguments(mut self, value: impl Into<String>) -> Self {
70        self.additional_browser_arguments = Some(value.into());
71        self
72    }
73
74    /// Sets the default display language (for example `"en-US"`).
75    pub fn language(mut self, value: impl Into<String>) -> Self {
76        self.language = Some(value.into());
77        self
78    }
79
80    /// Sets the minimum compatible browser version the environment requires.
81    ///
82    /// When unset, the environment uses the WebView2 GA baseline
83    /// (`86.0.616.0`), which every supported runtime satisfies.
84    pub fn target_compatible_browser_version(mut self, value: impl Into<String>) -> Self {
85        self.target_compatible_browser_version = Some(value.into());
86        self
87    }
88
89    /// Enables single sign-on using the operating system's primary account.
90    pub fn allow_single_sign_on_using_os_primary_account(mut self, value: bool) -> Self {
91        self.allow_single_sign_on_using_os_primary_account = value;
92        self
93    }
94
95    /// Enables loading and running browser extensions in the environment.
96    pub fn are_browser_extensions_enabled(mut self, value: bool) -> Self {
97        self.are_browser_extensions_enabled = value;
98        self
99    }
100
101    /// Sets the scrollbar style pages render with.
102    pub fn scrollbar_style(mut self, value: ScrollBarStyle) -> Self {
103        self.scrollbar_style = value;
104        self
105    }
106
107    pub(crate) fn create_environment<F: FnOnce(Result<Environment>) + 'static>(
108        &self,
109        handler: F,
110    ) -> Result<()> {
111        let handler = handler::EnvironmentCompleted::create(handler);
112        let options: ICoreWebView2EnvironmentOptions = OptionsObject::new(self).into();
113
114        let browser = self.browser_executable_folder.as_deref().map(HSTRING::from);
115        let user_data = self.user_data_folder.as_deref().map(HSTRING::from);
116        let browser = browser
117            .as_ref()
118            .map_or(PCWSTR::null(), |value| PCWSTR::from_raw(value.as_ptr()));
119        let user_data = user_data
120            .as_ref()
121            .map_or(PCWSTR::null(), |value| PCWSTR::from_raw(value.as_ptr()));
122
123        unsafe {
124            CreateCoreWebView2EnvironmentWithOptions(
125                browser,
126                user_data,
127                Interface::as_raw(&options),
128                Interface::as_raw(&handler),
129            )
130            .ok()
131        }
132    }
133}
134
135/// Read-only COM options object backed by [`EnvironmentOptions`].
136pub(crate) struct OptionsObject {
137    additional_browser_arguments: String,
138    language: String,
139    target_compatible_browser_version: String,
140    allow_single_sign_on_using_os_primary_account: BOOL,
141    are_browser_extensions_enabled: BOOL,
142    scrollbar_style: COREWEBVIEW2_SCROLLBAR_STYLE,
143}
144
145implement_decl! {
146    impl OptionsObject as pub(crate) OptionsObject_Impl:
147        [ICoreWebView2EnvironmentOptions, ICoreWebView2EnvironmentOptions6, ICoreWebView2EnvironmentOptions8]
148}
149
150/// Default `TargetCompatibleBrowserVersion`; WebView2 rejects an empty value.
151const DEFAULT_TARGET_COMPATIBLE_BROWSER_VERSION: &str = "86.0.616.0";
152
153impl OptionsObject {
154    fn new(options: &EnvironmentOptions) -> Self {
155        Self {
156            additional_browser_arguments: options
157                .additional_browser_arguments
158                .clone()
159                .unwrap_or_default(),
160            language: options.language.clone().unwrap_or_default(),
161            target_compatible_browser_version: options
162                .target_compatible_browser_version
163                .clone()
164                .unwrap_or_else(|| DEFAULT_TARGET_COMPATIBLE_BROWSER_VERSION.to_string()),
165            allow_single_sign_on_using_os_primary_account: options
166                .allow_single_sign_on_using_os_primary_account
167                .into(),
168            are_browser_extensions_enabled: options.are_browser_extensions_enabled.into(),
169            scrollbar_style: options.scrollbar_style.to_raw(),
170        }
171    }
172}
173
174impl ICoreWebView2EnvironmentOptions_Impl for OptionsObject_Impl {
175    fn AdditionalBrowserArguments(&self) -> Result<LPWSTR> {
176        unsafe { string::allocate(&self.additional_browser_arguments) }
177    }
178
179    fn SetAdditionalBrowserArguments(&self, _value: &PCWSTR) -> Result<()> {
180        Ok(())
181    }
182
183    fn Language(&self) -> Result<LPWSTR> {
184        unsafe { string::allocate(&self.language) }
185    }
186
187    fn SetLanguage(&self, _value: &PCWSTR) -> Result<()> {
188        Ok(())
189    }
190
191    fn TargetCompatibleBrowserVersion(&self) -> Result<LPWSTR> {
192        unsafe { string::allocate(&self.target_compatible_browser_version) }
193    }
194
195    fn SetTargetCompatibleBrowserVersion(&self, _value: &PCWSTR) -> Result<()> {
196        Ok(())
197    }
198
199    fn AllowSingleSignOnUsingOSPrimaryAccount(&self) -> Result<BOOL> {
200        Ok(self.allow_single_sign_on_using_os_primary_account)
201    }
202
203    fn SetAllowSingleSignOnUsingOSPrimaryAccount(&self, _allow: BOOL) -> Result<()> {
204        Ok(())
205    }
206}
207
208impl ICoreWebView2EnvironmentOptions6_Impl for OptionsObject_Impl {
209    fn AreBrowserExtensionsEnabled(&self) -> Result<BOOL> {
210        Ok(self.are_browser_extensions_enabled)
211    }
212
213    fn SetAreBrowserExtensionsEnabled(&self, _value: BOOL) -> Result<()> {
214        Ok(())
215    }
216}
217
218impl ICoreWebView2EnvironmentOptions8_Impl for OptionsObject_Impl {
219    fn ScrollBarStyle(&self) -> Result<COREWEBVIEW2_SCROLLBAR_STYLE> {
220        Ok(self.scrollbar_style)
221    }
222
223    fn SetScrollBarStyle(&self, _value: COREWEBVIEW2_SCROLLBAR_STYLE) -> Result<()> {
224        Ok(())
225    }
226}