wry/
lib.rs

1// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5//! <p align="center"><img height="100" src="https://raw.githubusercontent.com/tauri-apps/wry/refs/heads/dev/.github/splash.png" alt="WRY Webview Rendering library" /></p>
6//!
7//! [![](https://img.shields.io/crates/v/wry?style=flat-square)](https://crates.io/crates/wry) [![](https://img.shields.io/docsrs/wry?style=flat-square)](https://docs.rs/wry/)
8//! [![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg)](https://opencollective.com/tauri)
9//! [![Chat Server](https://img.shields.io/badge/chat-discord-7289da.svg)](https://discord.gg/SpmNs4S)
10//! [![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app)
11//! [![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation)
12//! [![support](https://img.shields.io/badge/sponsor-Open%20Collective-blue.svg)](https://opencollective.com/tauri)
13//!
14//! Wry is a cross-platform WebView rendering library.
15//!
16//! The webview requires a running event loop and a window type that implements [`HasWindowHandle`],
17//! or a gtk container widget if you need to support X11 and Wayland.
18//! You can use a windowing library like [`tao`] or [`winit`].
19//!
20//! ## Examples
21//!
22//! This example leverages the [`HasWindowHandle`] and supports Windows, macOS, iOS, Android and Linux (X11 Only).
23//! See the following example using [`winit`]:
24//!
25//! ```no_run
26//! # use wry::{WebViewBuilder, raw_window_handle};
27//! # use winit::{application::ApplicationHandler, event::WindowEvent, event_loop::{ActiveEventLoop, EventLoop}, window::{Window, WindowId}};
28//! #[derive(Default)]
29//! struct App {
30//!   window: Option<Window>,
31//!   webview: Option<wry::WebView>,
32//! }
33//!
34//! impl ApplicationHandler for App {
35//!   fn resumed(&mut self, event_loop: &ActiveEventLoop) {
36//!     let window = event_loop.create_window(Window::default_attributes()).unwrap();
37//!     let webview = WebViewBuilder::new()
38//!       .with_url("https://tauri.app")
39//!       .build(&window)
40//!       .unwrap();
41//!
42//!     self.window = Some(window);
43//!     self.webview = Some(webview);
44//!   }
45//!
46//!   fn window_event(&mut self, _event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {}
47//! }
48//!
49//! let event_loop = EventLoop::new().unwrap();
50//! let mut app = App::default();
51//! event_loop.run_app(&mut app).unwrap();
52//! ```
53//!
54//! If you also want to support Wayland too, then we recommend you use [`WebViewBuilderExtUnix::new_gtk`] on Linux.
55//! See the following example using [`tao`]:
56//!
57//! ```no_run
58//! # use wry::WebViewBuilder;
59//! # use tao::{window::WindowBuilder, event_loop::EventLoop};
60//! # #[cfg(target_os = "linux")]
61//! # use tao::platform::unix::WindowExtUnix;
62//! # #[cfg(target_os = "linux")]
63//! # use wry::WebViewBuilderExtUnix;
64//! let event_loop = EventLoop::new();
65//! let window = WindowBuilder::new().build(&event_loop).unwrap();
66//!
67//! let builder = WebViewBuilder::new().with_url("https://tauri.app");
68//!
69//! #[cfg(not(target_os = "linux"))]
70//! let webview = builder.build(&window).unwrap();
71//! #[cfg(target_os = "linux")]
72//! let webview = builder.build_gtk(window.gtk_window()).unwrap();
73//! ```
74//!
75//! ## Child webviews
76//!
77//! You can use [`WebView::new_as_child`] or [`WebViewBuilder::new_as_child`] to create the webview as a child inside another window. This is supported on
78//! macOS, Windows and Linux (X11 Only).
79//!
80//! ```no_run
81//! # use wry::{WebViewBuilder, raw_window_handle, Rect, dpi::*};
82//! # use winit::{application::ApplicationHandler, event::WindowEvent, event_loop::{ActiveEventLoop, EventLoop}, window::{Window, WindowId}};
83//! #[derive(Default)]
84//! struct App {
85//!   window: Option<Window>,
86//!   webview: Option<wry::WebView>,
87//! }
88//!
89//! impl ApplicationHandler for App {
90//!   fn resumed(&mut self, event_loop: &ActiveEventLoop) {
91//!     let window = event_loop.create_window(Window::default_attributes()).unwrap();
92//!     let webview = WebViewBuilder::new()
93//!       .with_url("https://tauri.app")
94//!       .with_bounds(Rect {
95//!         position: LogicalPosition::new(100, 100).into(),
96//!         size: LogicalSize::new(200, 200).into(),
97//!       })
98//!       .build_as_child(&window)
99//!       .unwrap();
100//!
101//!     self.window = Some(window);
102//!     self.webview = Some(webview);
103//!   }
104//!
105//!   fn window_event(&mut self, _event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {}
106//! }
107//!
108//! let event_loop = EventLoop::new().unwrap();
109//! let mut app = App::default();
110//! event_loop.run_app(&mut app).unwrap();
111//! ```
112//!
113//! If you want to support X11 and Wayland at the same time, we recommend using
114//! [`WebViewExtUnix::new_gtk`] or [`WebViewBuilderExtUnix::new_gtk`] with [`gtk::Fixed`].
115//!
116//! ```no_run
117//! # use wry::{WebViewBuilder, raw_window_handle, Rect, dpi::*};
118//! # use tao::{window::WindowBuilder, event_loop::EventLoop};
119//! # #[cfg(target_os = "linux")]
120//! # use wry::WebViewBuilderExtUnix;
121//! # #[cfg(target_os = "linux")]
122//! # use tao::platform::unix::WindowExtUnix;
123//! let event_loop = EventLoop::new();
124//! let window = WindowBuilder::new().build(&event_loop).unwrap();
125//!
126//! let builder = WebViewBuilder::new()
127//!   .with_url("https://tauri.app")
128//!   .with_bounds(Rect {
129//!     position: LogicalPosition::new(100, 100).into(),
130//!     size: LogicalSize::new(200, 200).into(),
131//!   });
132//!
133//! #[cfg(not(target_os = "linux"))]
134//! let webview = builder.build_as_child(&window).unwrap();
135//! #[cfg(target_os = "linux")]
136//! let webview = {
137//!   # use gtk::prelude::*;
138//!   let vbox = window.default_vbox().unwrap(); // tao adds a gtk::Box by default
139//!   let fixed = gtk::Fixed::new();
140//!   fixed.show_all();
141//!   vbox.pack_start(&fixed, true, true, 0);
142//!   builder.build_gtk(&fixed).unwrap()
143//! };
144//! ```
145//!
146//! ## Platform Considerations
147//!
148//! Here is the underlying web engine each platform uses, and some dependencies you might need to install.
149//!
150//! ### Linux
151//!
152//! [WebKitGTK](https://webkitgtk.org/) is used to provide webviews on Linux which requires GTK,
153//! so if the windowing library doesn't support GTK (as in [`winit`])
154//! you'll need to call [`gtk::init`] before creating the webview and then call [`gtk::main_iteration_do`] alongside
155//! your windowing library event loop.
156//!
157//! ```no_run
158//! # use wry::{WebView, WebViewBuilder};
159//! # use winit::{application::ApplicationHandler, event::WindowEvent, event_loop::{ActiveEventLoop, EventLoop}, window::{Window, WindowId}};
160//! #[derive(Default)]
161//! struct App {
162//!   webview_window: Option<(Window, WebView)>,
163//! }
164//!
165//! impl ApplicationHandler for App {
166//!   fn resumed(&mut self, event_loop: &ActiveEventLoop) {
167//!     let window = event_loop.create_window(Window::default_attributes()).unwrap();
168//!     let webview = WebViewBuilder::new()
169//!       .with_url("https://tauri.app")
170//!       .build(&window)
171//!       .unwrap();
172//!
173//!     self.webview_window = Some((window, webview));
174//!   }
175//!
176//!   fn window_event(&mut self, _event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {}
177//!
178//!   // Advance GTK event loop <!----- IMPORTANT
179//!   fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
180//!     #[cfg(target_os = "linux")]
181//!     while gtk::events_pending() {
182//!       gtk::main_iteration_do(false);
183//!     }
184//!   }
185//! }
186//!
187//! let event_loop = EventLoop::new().unwrap();
188//! let mut app = App::default();
189//! event_loop.run_app(&mut app).unwrap();
190//! ```
191//!
192//! #### Linux Dependencies
193//!
194//! ##### Arch Linux / Manjaro:
195//!
196//! ```bash
197//! sudo pacman -S webkit2gtk-4.1
198//! ```
199//!
200//! ##### Debian / Ubuntu:
201//!
202//! ```bash
203//! sudo apt install libwebkit2gtk-4.1-dev
204//! ```
205//!
206//! ##### Fedora
207//!
208//! ```bash
209//! sudo dnf install gtk3-devel webkit2gtk4.1-devel
210//! ```
211//!
212//! ##### Nix & NixOS
213//!
214//! ```nix
215//! # shell.nix
216//!
217//! let
218//!    # Unstable Channel | Rolling Release
219//!    pkgs = import (fetchTarball("channel:nixpkgs-unstable")) { };
220//!    packages = with pkgs; [
221//!      pkg-config
222//!      webkitgtk_4_1
223//!    ];
224//!  in
225//!  pkgs.mkShell {
226//!    buildInputs = packages;
227//!  }
228//! ```
229//!
230//! ```sh
231//! nix-shell shell.nix
232//! ```
233//!
234//! ##### GUIX
235//!
236//! ```scheme
237//! ;; manifest.scm
238//!
239//! (specifications->manifest
240//!   '("pkg-config"                ; Helper tool used when compiling
241//!     "webkitgtk"                 ; Web content engine fot GTK+
242//!  ))
243//! ```
244//!
245//! ```bash
246//! guix shell -m manifest.scm
247//! ```
248//!
249//! ### macOS
250//!
251//! WebKit is native on macOS so everything should be fine.
252//!
253//! If you are cross-compiling for macOS using [osxcross](https://github.com/tpoechtrager/osxcross) and encounter a runtime panic like `Class with name WKWebViewConfiguration could not be found` it's possible that `WebKit.framework` has not been linked correctly, to fix this set the `RUSTFLAGS` environment variable:
254//!
255//! ```bash
256//! RUSTFLAGS="-l framework=WebKit" cargo build --target=x86_64-apple-darwin --release
257//! ```
258//!
259//! ### Windows
260//!
261//! WebView2 provided by Microsoft Edge Chromium is used. So wry supports Windows 7, 8, 10 and 11.
262//!
263//! ### Android
264//!
265//! In order for `wry` to be able to create webviews on Android, there are a few requirements that your application needs to uphold:
266//!
267//! 1. You need to set a few environment variables that will be used to generate the necessary kotlin
268//!    files that you need to include in your Android application for wry to function properly.
269//!    - `WRY_ANDROID_PACKAGE`: which is the reversed domain name of your android project and the app name in snake_case, for example, `com.wry.example.wry_app`
270//!    - `WRY_ANDROID_LIBRARY`: for example, if your cargo project has a lib name `wry_app`, it will generate `libwry_app.so` so you set this env var to `wry_app`
271//!    - `WRY_ANDROID_KOTLIN_FILES_OUT_DIR`: for example, `path/to/app/src/main/kotlin/com/wry/example`
272//! 2. Your main Android Activity needs to inherit `AppCompatActivity`, preferably it should use the generated `WryActivity` or inherit it.
273//! 3. Your Rust app needs to call `wry::android_setup` function to setup the necessary logic to be able to create webviews later on.
274//! 4. Your Rust app needs to call `wry::android_binding!` macro to setup the JNI functions that will be called by `WryActivity` and various other places.
275//!
276//! It is recommended to use the [`tao`](https://docs.rs/tao/latest/tao/) crate as it provides maximum compatibility with `wry`.
277//!
278//! ```
279//! #[cfg(target_os = "android")]
280//! {
281//!   tao::android_binding!(
282//!       com_example,
283//!       wry_app,
284//!       WryActivity,
285//!       wry::android_setup, // pass the wry::android_setup function to tao which will be invoked when the event loop is created
286//!       _start_app
287//!   );
288//!   wry::android_binding!(com_example, ttt);
289//! }
290//! ```
291//!
292//! If this feels overwhelming, you can just use the preconfigured template from [`cargo-mobile2`](https://github.com/tauri-apps/cargo-mobile2).
293//!
294//! For more information, check out [MOBILE.md](https://github.com/tauri-apps/wry/blob/dev/MOBILE.md).
295//!
296//! ## Feature flags
297//!
298//! Wry uses a set of feature flags to toggle several advanced features.
299//!
300//! - `os-webview` (default): Enables the default WebView framework on the platform. This must be enabled
301//!   for the crate to work. This feature was added in preparation of other ports like cef and servo.
302//! - `protocol` (default): Enables [`WebViewBuilder::with_custom_protocol`] to define custom URL scheme for handling tasks like
303//!   loading assets.
304//! - `drag-drop` (default): Enables [`WebViewBuilder::with_drag_drop_handler`] to control the behavior when there are files
305//!   interacting with the window.
306//! - `devtools`: Enables devtools on release builds. Devtools are always enabled in debug builds.
307//!   On **macOS**, enabling devtools, requires calling private APIs so you should not enable this flag in release
308//!   build if your app needs to publish to App Store.
309//! - `transparent`: Transparent background on **macOS** requires calling private functions.
310//!   Avoid this in release build if your app needs to publish to App Store.
311//! - `fullscreen`: Fullscreen video and other media on **macOS** requires calling private functions.
312//!   Avoid this in release build if your app needs to publish to App Store.
313//! - `linux-body`: Enables body support of custom protocol request on Linux. Requires
314//!   WebKit2GTK v2.40 or above.
315//! - `tracing`: enables [`tracing`] for `evaluate_script`, `ipc_handler`, and `custom_protocols`.
316//!
317//! ## Partners
318//!
319//! <table>
320//!   <tbody>
321//!     <tr>
322//!       <td align="center" valign="middle">
323//!         <a href="https://crabnebula.dev" target="_blank">
324//!           <img src=".github/sponsors/crabnebula.svg" alt="CrabNebula" width="283">
325//!         </a>
326//!       </td>
327//!     </tr>
328//!   </tbody>
329//! </table>
330//!
331//! For the complete list of sponsors please visit our [website](https://tauri.app#sponsors) and [Open Collective](https://opencollective.com/tauri).
332//!
333//! ## License
334//!
335//! Apache-2.0/MIT
336//!
337//! [`tao`]: https://docs.rs/tao
338//! [`winit`]: https://docs.rs/winit
339//! [`tracing`]: https://docs.rs/tracing
340
341#![allow(clippy::new_without_default)]
342#![allow(clippy::default_constructed_unit_structs)]
343#![allow(clippy::type_complexity)]
344#![cfg_attr(docsrs, feature(doc_cfg))]
345
346// #[cfg(any(target_os = "macos", target_os = "ios"))]
347// #[macro_use]
348// extern crate objc;
349
350mod error;
351mod proxy;
352#[cfg(any(target_os = "macos", target_os = "android", target_os = "ios"))]
353mod util;
354mod web_context;
355
356#[cfg(target_os = "android")]
357pub(crate) mod android;
358#[cfg(target_os = "android")]
359pub use crate::android::android_setup;
360#[cfg(target_os = "android")]
361pub mod prelude {
362  pub use crate::android::{binding::*, dispatch, find_class, Context};
363  pub use tao_macros::{android_fn, generate_package_name};
364}
365#[cfg(target_os = "android")]
366pub use android::JniHandle;
367#[cfg(target_os = "android")]
368use android::*;
369
370#[cfg(gtk)]
371pub(crate) mod webkitgtk;
372/// Re-exported [raw-window-handle](https://docs.rs/raw-window-handle/latest/raw_window_handle/) crate.
373pub use raw_window_handle;
374use raw_window_handle::HasWindowHandle;
375#[cfg(gtk)]
376use webkitgtk::*;
377
378#[cfg(any(target_os = "macos", target_os = "ios"))]
379use objc2::rc::Retained;
380#[cfg(target_os = "macos")]
381use objc2_app_kit::NSWindow;
382#[cfg(any(target_os = "macos", target_os = "ios"))]
383use objc2_web_kit::WKUserContentController;
384#[cfg(any(target_os = "macos", target_os = "ios"))]
385pub(crate) mod wkwebview;
386#[cfg(any(target_os = "macos", target_os = "ios"))]
387use wkwebview::*;
388#[cfg(any(target_os = "macos", target_os = "ios"))]
389pub use wkwebview::{PrintMargin, PrintOptions, WryWebView};
390
391#[cfg(target_os = "windows")]
392pub(crate) mod webview2;
393#[cfg(target_os = "windows")]
394pub use self::webview2::ScrollBarStyle;
395#[cfg(target_os = "windows")]
396use self::webview2::*;
397#[cfg(target_os = "windows")]
398use webview2_com::Microsoft::Web::WebView2::Win32::{
399  ICoreWebView2, ICoreWebView2Controller, ICoreWebView2Environment,
400};
401
402use std::{borrow::Cow, collections::HashMap, path::PathBuf, rc::Rc};
403
404use http::{Request, Response};
405
406pub use cookie;
407pub use dpi;
408pub use error::*;
409pub use http;
410pub use proxy::{ProxyConfig, ProxyEndpoint};
411pub use web_context::WebContext;
412
413#[cfg(target_os = "ios")]
414pub type InputAccessoryViewBuilder =
415  dyn Fn(&objc2_ui_kit::UIView) -> Option<Retained<objc2_ui_kit::UIView>>;
416
417/// A rectangular region.
418#[derive(Clone, Copy, Debug)]
419pub struct Rect {
420  /// Rect position.
421  pub position: dpi::Position,
422  /// Rect size.
423  pub size: dpi::Size,
424}
425
426impl Default for Rect {
427  fn default() -> Self {
428    Self {
429      position: dpi::LogicalPosition::new(0, 0).into(),
430      size: dpi::LogicalSize::new(0, 0).into(),
431    }
432  }
433}
434
435/// Resolves a custom protocol [`Request`] asynchronously.
436///
437/// See [`WebViewBuilder::with_asynchronous_custom_protocol`] for more information.
438pub struct RequestAsyncResponder {
439  pub(crate) responder: Box<dyn FnOnce(Response<Cow<'static, [u8]>>)>,
440}
441
442// SAFETY: even though the webview bindings do not indicate the responder is Send,
443// it actually is and we need it in order to let the user do the protocol computation
444// on a separate thread or async task.
445unsafe impl Send for RequestAsyncResponder {}
446
447impl RequestAsyncResponder {
448  /// Resolves the request with the given response.
449  pub fn respond<T: Into<Cow<'static, [u8]>>>(self, response: Response<T>) {
450    let (parts, body) = response.into_parts();
451    (self.responder)(Response::from_parts(parts, body.into()))
452  }
453}
454
455/// Response for the new window request handler.
456///
457/// See [`WebViewBuilder::with_new_window_req_handler`].
458pub enum NewWindowResponse {
459  /// Allow the window to be opened with the default implementation.
460  Allow,
461  /// Allow the window to be opened, with the given platform webview instance.
462  ///
463  /// ## Platform-specific:
464  ///
465  /// **Linux**: The webview must be related to the caller webview. See [`WebViewBuilderExtUnix::with_related_view`].
466  /// **Windows**: The webview must use the same environment as the caller webview. See [`WebViewBuilderExtWindows::with_environment`].
467  /// **macOS**: The webview must use the same configuration as the caller webview. See [`WebViewBuilderExtMacos::with_webview_configuration`].
468  #[cfg(not(any(target_os = "android", target_os = "ios")))]
469  Create {
470    #[cfg(any(
471      target_os = "linux",
472      target_os = "dragonfly",
473      target_os = "freebsd",
474      target_os = "netbsd",
475      target_os = "openbsd",
476    ))]
477    webview: webkit2gtk::WebView,
478    #[cfg(windows)]
479    webview: ICoreWebView2,
480    #[cfg(target_os = "macos")]
481    webview: Retained<objc2_web_kit::WKWebView>,
482  },
483  /// Deny the window from being opened.
484  Deny,
485}
486
487/// Information about the webview that initiated a new window request.
488#[derive(Debug)]
489pub struct NewWindowOpener {
490  /// The instance of the webview that initiated the new window request.
491  ///
492  /// This must be set as the related view of the new webview. See [`WebViewBuilderExtUnix::with_related_view`].
493  #[cfg(any(
494    target_os = "linux",
495    target_os = "dragonfly",
496    target_os = "freebsd",
497    target_os = "netbsd",
498    target_os = "openbsd",
499  ))]
500  pub webview: webkit2gtk::WebView,
501  /// The instance of the webview that initiated the new window request.
502  #[cfg(windows)]
503  pub webview: ICoreWebView2,
504  /// The environment of the webview that initiated the new window request.
505  ///
506  /// The target webview environment **MUST** match the environment of the opener webview. See [`WebViewBuilderExtWindows::with_environment`].
507  #[cfg(windows)]
508  pub environment: ICoreWebView2Environment,
509  /// The instance of the webview that initiated the new window request.
510  #[cfg(target_os = "macos")]
511  pub webview: Retained<objc2_web_kit::WKWebView>,
512  /// Configuration of the target webview.
513  ///
514  /// This **MUST** be used when creating the target webview. See [`WebViewBuilderExtMacos::with_webview_configuration`].
515  #[cfg(target_os = "macos")]
516  pub target_configuration: Retained<objc2_web_kit::WKWebViewConfiguration>,
517}
518
519unsafe impl Send for NewWindowOpener {}
520unsafe impl Sync for NewWindowOpener {}
521
522/// Window features of a window requested to open.
523#[non_exhaustive]
524#[derive(Debug)]
525pub struct NewWindowFeatures {
526  /// Specifies the size of the content area
527  /// as defined by the user's operating system where the new window will be generated.
528  pub size: Option<dpi::LogicalSize<f64>>,
529  /// Specifies the position of the window relative to the work area
530  /// as defined by the user's operating system where the new window will be generated.
531  pub position: Option<dpi::LogicalPosition<f64>>,
532  /// Information about the webview opener containing data that must be used when creating the new webview.
533  pub opener: NewWindowOpener,
534}
535
536/// An id for a webview
537pub type WebViewId<'a> = &'a str;
538
539pub struct WebViewAttributes<'a> {
540  /// An id that will be passed when this webview makes requests in certain callbacks.
541  pub id: Option<WebViewId<'a>>,
542
543  /// Web context to be shared with this webview.
544  pub context: Option<&'a mut WebContext>,
545
546  /// Whether the WebView should have a custom user-agent.
547  pub user_agent: Option<String>,
548
549  /// Whether the WebView window should be visible.
550  pub visible: bool,
551
552  /// Whether the WebView should be transparent.
553  ///
554  /// ## Platform-specific:
555  ///
556  /// **Windows 7**: Not supported.
557  pub transparent: bool,
558
559  /// Specify the webview background color. This will be ignored if `transparent` is set to `true`.
560  ///
561  /// The color uses the RGBA format.
562  ///
563  /// ## Platform-specific:
564  ///
565  /// - **macOS**: Not implemented.
566  /// - **Windows**:
567  ///   - On Windows 7, transparency is not supported and the alpha value will be ignored.
568  ///   - On Windows higher than 7: translucent colors are not supported so any alpha value other than `0` will be replaced by `255`
569  pub background_color: Option<RGBA>,
570
571  /// Whether load the provided URL to [`WebView`].
572  ///
573  /// ## Note
574  ///
575  /// Data URLs are not supported, use [`html`](Self::html) option instead.
576  pub url: Option<String>,
577
578  /// Headers used when loading the requested [`url`](Self::url).
579  pub headers: Option<http::HeaderMap>,
580
581  /// Whether page zooming by hotkeys is enabled
582  ///
583  /// ## Platform-specific
584  ///
585  /// **macOS / Linux / Android / iOS**: Unsupported
586  pub zoom_hotkeys_enabled: bool,
587
588  /// Whether load the provided html string to [`WebView`].
589  /// This will be ignored if the `url` is provided.
590  ///
591  /// # Warning
592  ///
593  /// The Page loaded from html string will have `null` origin.
594  ///
595  /// ## PLatform-specific:
596  ///
597  /// - **Windows:** the string can not be larger than 2 MB (2 * 1024 * 1024 bytes) in total size
598  pub html: Option<String>,
599
600  /// A list of initialization javascript scripts to run when loading new pages.
601  /// When webview load a new page, this initialization code will be executed.
602  /// It is guaranteed that code is executed before `window.onload`.
603  ///
604  /// ## Platform-specific
605  ///
606  /// - **Windows**: scripts are always injected into sub frames.
607  /// - **Android:** When [addDocumentStartJavaScript] is not supported,
608  ///   we prepend them to each HTML head (implementation only supported on custom protocol URLs).
609  ///   For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
610  ///
611  /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
612  /// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
613  pub initialization_scripts: Vec<InitializationScript>,
614
615  /// A list of custom loading protocols with pairs of scheme uri string and a handling
616  /// closure.
617  ///
618  /// The closure takes an Id ([WebViewId]), [Request] and [RequestAsyncResponder] as arguments and returns a [Response].
619  ///
620  /// # Note
621  ///
622  /// If using a shared [WebContext], make sure custom protocols were not already registered on that web context on Linux.
623  ///
624  /// # Warning
625  ///
626  /// Pages loaded from custom protocol will have different Origin on different platforms. And
627  /// servers which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin`
628  /// if you wish to send requests with native `fetch` and `XmlHttpRequest` APIs. Here are the
629  /// different Origin headers across platforms:
630  ///
631  /// - macOS, iOS and Linux: `<scheme_name>://<path>` (so it will be `wry://path/to/page/`).
632  /// - Windows and Android: `http://<scheme_name>.<path>` by default (so it will be `http://wry.path/to/page). To use `https` instead of `http`, use [`WebViewBuilderExtWindows::with_https_scheme`] and [`WebViewBuilderExtAndroid::with_https_scheme`].
633  ///
634  /// # Reading assets on mobile
635  ///
636  /// - Android: Android has `assets` and `resource` path finder to
637  ///   locate your files in those directories. For more information, see [Loading in-app content](https://developer.android.com/guide/webapps/load-local-content) page.
638  /// - iOS: To get the path of your assets, you can call [`CFBundle::resources_path`](https://docs.rs/core-foundation/latest/core_foundation/bundle/struct.CFBundle.html#method.resources_path). So url like `wry://assets/index.html` could get the html file in assets directory.
639  pub custom_protocols:
640    HashMap<String, Box<dyn Fn(WebViewId, Request<Vec<u8>>, RequestAsyncResponder)>>,
641
642  /// The IPC handler to receive the message from Javascript on webview
643  /// using `window.ipc.postMessage("insert_message_here")` to host Rust code.
644  pub ipc_handler: Option<Box<dyn Fn(Request<String>)>>,
645
646  /// A handler closure to process incoming [`DragDropEvent`] of the webview.
647  ///
648  /// # Blocking OS Default Behavior
649  /// Return `true` in the callback to block the OS' default behavior.
650  ///
651  /// Note, that if you do block this behavior, it won't be possible to drop files on `<input type="file">` forms.
652  /// Also note, that it's not possible to manually set the value of a `<input type="file">` via JavaScript for security reasons.
653  #[cfg(feature = "drag-drop")]
654  #[cfg_attr(docsrs, doc(cfg(feature = "drag-drop")))]
655  pub drag_drop_handler: Option<Box<dyn Fn(DragDropEvent) -> bool>>,
656  #[cfg(not(feature = "drag-drop"))]
657  drag_drop_handler: Option<Box<dyn Fn(DragDropEvent) -> bool>>,
658
659  /// A navigation handler to decide if incoming url is allowed to navigate.
660  ///
661  /// The closure take a `String` parameter as url and returns a `bool` to determine whether the navigation should happen.
662  /// `true` allows to navigate and `false` does not.
663  pub navigation_handler: Option<Box<dyn Fn(String) -> bool>>,
664
665  /// A download started handler to manage incoming downloads.
666  ///
667  /// The closure takes two parameters, the first is a `String` representing the url being downloaded from and and the
668  /// second is a mutable `PathBuf` reference that (possibly) represents where the file will be downloaded to. The latter
669  /// parameter can be used to set the download location by assigning a new path to it, the assigned path _must_ be
670  /// absolute. The closure returns a `bool` to allow or deny the download.
671  ///
672  /// [`Self::default()`] sets a handler allowing all downloads to match browser behavior.
673  pub download_started_handler: Option<Box<dyn FnMut(String, &mut PathBuf) -> bool + 'static>>,
674
675  /// A download completion handler to manage downloads that have finished.
676  ///
677  /// The closure is fired when the download completes, whether it was successful or not.
678  /// The closure takes a `String` representing the URL of the original download request, an `Option<PathBuf>`
679  /// potentially representing the filesystem path the file was downloaded to, and a `bool` indicating if the download
680  /// succeeded. A value of `None` being passed instead of a `PathBuf` does not necessarily indicate that the download
681  /// did not succeed, and may instead indicate some other failure, always check the third parameter if you need to
682  /// know if the download succeeded.
683  ///
684  /// ## Platform-specific:
685  ///
686  /// - **macOS**: The second parameter indicating the path the file was saved to, is always empty,
687  ///   due to API limitations.
688  pub download_completed_handler: Option<Rc<dyn Fn(String, Option<PathBuf>, bool) + 'static>>,
689
690  /// A new window request handler to decide if incoming url is allowed to be opened.
691  ///
692  /// A new window is requested to be opened by the [window.open] API.
693  ///
694  /// The closure take the URL to open and the window features object and returns [`NewWindowResponse`] to determine whether the window should open.
695  ///
696  /// ## Platform-specific:
697  ///
698  /// - **Windows**: The closure is executed on a separate thread to prevent a deadlock.
699  ///
700  /// [window.open]: https://developer.mozilla.org/en-US/docs/Web/API/Window/open
701  pub new_window_req_handler:
702    Option<Box<dyn Fn(String, NewWindowFeatures) -> NewWindowResponse + Send + Sync>>,
703
704  /// Enables clipboard access for the page rendered on **Linux** and **Windows**.
705  ///
706  /// macOS doesn't provide such method and is always enabled by default. But your app will still need to add menu
707  /// item accelerators to use the clipboard shortcuts.
708  pub clipboard: bool,
709
710  /// Enable web inspector which is usually called browser devtools.
711  ///
712  /// Note this only enables devtools to the webview. To open it, you can call
713  /// [`WebView::open_devtools`], or right click the page and open it from the context menu.
714  ///
715  /// ## Platform-specific
716  ///
717  /// - macOS: This will call private functions on **macOS**. It is enabled in **debug** builds,
718  ///   but requires `devtools` feature flag to actually enable it in **release** builds.
719  /// - Android: Open `chrome://inspect/#devices` in Chrome to get the devtools window. Wry's `WebView` devtools API isn't supported on Android.
720  /// - iOS: Open Safari > Develop > [Your Device Name] > [Your WebView] to get the devtools window.
721  pub devtools: bool,
722
723  /// Whether clicking an inactive window also clicks through to the webview. Default is `false`.
724  ///
725  /// ## Platform-specific
726  ///
727  /// This configuration only impacts macOS.
728  pub accept_first_mouse: bool,
729
730  /// Indicates whether horizontal swipe gestures trigger backward and forward page navigation.
731  ///
732  /// ## Platform-specific:
733  ///
734  /// - Windows: Setting to `false` does nothing on WebView2 Runtime version before 92.0.902.0,
735  ///   see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10902-prerelease
736  ///
737  /// - **Android / iOS:** Unsupported.
738  pub back_forward_navigation_gestures: bool,
739
740  /// Set a handler closure to process the change of the webview's document title.
741  pub document_title_changed_handler: Option<Box<dyn Fn(String)>>,
742
743  /// Run the WebView with incognito mode. Note that WebContext will be ingored if incognito is
744  /// enabled.
745  ///
746  /// ## Platform-specific:
747  ///
748  /// - **Windows**: Requires WebView2 Runtime version 101.0.1210.39 or higher, does nothing on older versions,
749  ///   see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10121039
750  /// - **Android:** Unsupported yet.
751  /// - **macOS / iOS**: Uses the nonPersistent DataStore.
752  pub incognito: bool,
753
754  /// Whether all media can be played without user interaction.
755  pub autoplay: bool,
756
757  /// Set a handler closure to process page load events.
758  pub on_page_load_handler: Option<Box<dyn Fn(PageLoadEvent, String)>>,
759
760  /// Set a proxy configuration for the webview. Supports HTTP CONNECT and SOCKSv5 proxies
761  ///
762  /// - **macOS**: Requires macOS 14.0+ and the `mac-proxy` feature flag to be enabled.
763  /// - **Android / iOS:** Not supported.
764  pub proxy_config: Option<ProxyConfig>,
765
766  /// Whether the webview should be focused when created.
767  ///
768  /// ## Platform-specific:
769  ///
770  /// - **macOS / Android / iOS:** Unsupported.
771  pub focused: bool,
772
773  /// The webview bounds. Defaults to `x: 0, y: 0, width: 200, height: 200`.
774  /// This is only effective if the webview was created by [`WebView::new_as_child`] or [`WebViewBuilder::new_as_child`]
775  /// or on Linux, if was created by [`WebViewExtUnix::new_gtk`] or [`WebViewBuilderExtUnix::new_gtk`] with [`gtk::Fixed`].
776  pub bounds: Option<Rect>,
777
778  /// Whether background throttling should be disabled.
779  ///
780  /// By default, browsers throttle timers and even unload the whole tab (view) to free resources after roughly 5 minutes when
781  /// a view became minimized or hidden. This will permanently suspend all tasks until the documents visibility state
782  /// changes back from hidden to visible by bringing the view back to the foreground.
783  ///
784  /// ## Platform-specific
785  ///
786  /// - **Linux / Windows / Android**: Unsupported. Workarounds like a pending WebLock transaction might suffice.
787  /// - **iOS**: Supported since version 17.0+.
788  /// - **macOS**: Supported since version 14.0+.
789  ///
790  /// see https://github.com/tauri-apps/tauri/issues/5250#issuecomment-2569380578
791  pub background_throttling: Option<BackgroundThrottlingPolicy>,
792
793  /// Whether JavaScript should be disabled.
794  pub javascript_disabled: bool,
795}
796
797impl Default for WebViewAttributes<'_> {
798  fn default() -> Self {
799    Self {
800      id: Default::default(),
801      context: None,
802      user_agent: None,
803      visible: true,
804      transparent: false,
805      background_color: None,
806      url: None,
807      headers: None,
808      html: None,
809      initialization_scripts: Default::default(),
810      custom_protocols: Default::default(),
811      ipc_handler: None,
812      drag_drop_handler: None,
813      navigation_handler: None,
814      download_started_handler: Some(Box::new(|_, _| true)),
815      download_completed_handler: None,
816      new_window_req_handler: None,
817      clipboard: false,
818      #[cfg(debug_assertions)]
819      devtools: true,
820      #[cfg(not(debug_assertions))]
821      devtools: false,
822      zoom_hotkeys_enabled: false,
823      accept_first_mouse: false,
824      back_forward_navigation_gestures: false,
825      document_title_changed_handler: None,
826      incognito: false,
827      autoplay: true,
828      on_page_load_handler: None,
829      proxy_config: None,
830      focused: true,
831      bounds: Some(Rect {
832        position: dpi::LogicalPosition::new(0, 0).into(),
833        size: dpi::LogicalSize::new(200, 200).into(),
834      }),
835      background_throttling: None,
836      javascript_disabled: false,
837    }
838  }
839}
840
841/// Builder type of [`WebView`].
842///
843/// [`WebViewBuilder`] / [`WebView`] are the basic building blocks to construct WebView contents and
844/// scripts for those who prefer to control fine grained window creation and event handling.
845/// [`WebViewBuilder`] provides ability to setup initialization before web engine starts.
846pub struct WebViewBuilder<'a> {
847  attrs: WebViewAttributes<'a>,
848  platform_specific: PlatformSpecificWebViewAttributes,
849  /// Records errors before the [`WebViewBuilder::build`] is called
850  error: crate::Result<()>,
851}
852
853impl<'a> WebViewBuilder<'a> {
854  /// Create a new [`WebViewBuilder`].
855  pub fn new() -> Self {
856    Self {
857      attrs: WebViewAttributes::default(),
858      #[allow(clippy::default_constructed_unit_structs)]
859      platform_specific: PlatformSpecificWebViewAttributes::default(),
860      error: Ok(()),
861    }
862  }
863
864  /// Create a new [`WebViewBuilder`] with a web context that can be shared with multiple [`WebView`]s.
865  pub fn new_with_web_context(web_context: &'a mut WebContext) -> Self {
866    let attrs = WebViewAttributes {
867      context: Some(web_context),
868      ..Default::default()
869    };
870
871    Self {
872      attrs,
873      #[allow(clippy::default_constructed_unit_structs)]
874      platform_specific: PlatformSpecificWebViewAttributes::default(),
875      error: Ok(()),
876    }
877  }
878
879  /// Create a new [`WebViewBuilder`] with the given [`WebViewAttributes`]
880  pub fn new_with_attributes(attrs: WebViewAttributes<'a>) -> Self {
881    Self {
882      attrs,
883      #[allow(clippy::default_constructed_unit_structs)]
884      platform_specific: PlatformSpecificWebViewAttributes::default(),
885      error: Ok(()),
886    }
887  }
888
889  /// Set an id that will be passed when this webview makes requests in certain callbacks.
890  pub fn with_id(mut self, id: WebViewId<'a>) -> Self {
891    self.attrs.id = Some(id);
892    self
893  }
894
895  /// Indicates whether horizontal swipe gestures trigger backward and forward page navigation.
896  ///
897  /// ## Platform-specific:
898  ///
899  /// - **Android / iOS:** Unsupported.
900  pub fn with_back_forward_navigation_gestures(mut self, gesture: bool) -> Self {
901    self.attrs.back_forward_navigation_gestures = gesture;
902    self
903  }
904
905  /// Sets whether the WebView should be transparent.
906  ///
907  /// ## Platform-specific:
908  ///
909  /// **Windows 7**: Not supported.
910  pub fn with_transparent(mut self, transparent: bool) -> Self {
911    self.attrs.transparent = transparent;
912    self
913  }
914
915  /// Specify the webview background color. This will be ignored if `transparent` is set to `true`.
916  ///
917  /// The color uses the RGBA format.
918  ///
919  /// ## Platfrom-specific:
920  ///
921  /// - **macOS**: Not implemented.
922  /// - **Windows**:
923  ///   - on Windows 7, transparency is not supported and the alpha value will be ignored.
924  ///   - on Windows higher than 7: translucent colors are not supported so any alpha value other than `0` will be replaced by `255`
925  pub fn with_background_color(mut self, background_color: RGBA) -> Self {
926    self.attrs.background_color = Some(background_color);
927    self
928  }
929
930  /// Sets whether the WebView should be visible or not.
931  pub fn with_visible(mut self, visible: bool) -> Self {
932    self.attrs.visible = visible;
933    self
934  }
935
936  /// Sets whether all media can be played without user interaction.
937  pub fn with_autoplay(mut self, autoplay: bool) -> Self {
938    self.attrs.autoplay = autoplay;
939    self
940  }
941
942  /// Initialize javascript code when loading new pages. When webview load a new page, this
943  /// initialization code will be executed. It is guaranteed that code is executed before
944  /// `window.onload`.
945  ///
946  /// ## Example
947  /// ```ignore
948  /// let webview = WebViewBuilder::new()
949  ///   .with_initialization_script("console.log('Running inside main frame only')")
950  ///   .with_url("https://tauri.app")
951  ///   .build(&window)
952  ///   .unwrap();
953  /// ```
954  ///
955  /// ## Platform-specific
956  ///
957  ///- **Windows:** scripts are always added to subframes.
958  /// - **Android:** When [addDocumentStartJavaScript] is not supported,
959  ///   we prepend them to each HTML head (implementation only supported on custom protocol URLs).
960  ///   For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
961  ///
962  /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
963  /// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
964  pub fn with_initialization_script<S: Into<String>>(self, js: S) -> Self {
965    self.with_initialization_script_for_main_only(js, true)
966  }
967
968  /// Same as [`with_initialization_script`](Self::with_initialization_script) but with option to inject into main frame only or sub frames.
969  ///
970  /// ## Example
971  /// ```ignore
972  /// let webview = WebViewBuilder::new()
973  ///   .with_initialization_script_for_main_only("console.log('Running inside main frame only')", true)
974  ///   .with_initialization_script_for_main_only("console.log('Running  main frame and sub frames')", false)
975  ///   .with_url("https://tauri.app")
976  ///   .build(&window)
977  ///   .unwrap();
978  /// ```
979  ///
980  /// ## Platform-specific:
981  ///
982  /// - **Windows:** scripts are always added to subframes regardless of the `for_main_frame_only` option.
983  /// - **Android**: When [addDocumentStartJavaScript] is not supported, scripts are always injected into main frame only.
984  ///
985  /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
986  pub fn with_initialization_script_for_main_only<S: Into<String>>(
987    mut self,
988    js: S,
989    for_main_frame_only: bool,
990  ) -> Self {
991    let script = js.into();
992    if !script.is_empty() {
993      self
994        .attrs
995        .initialization_scripts
996        .push(InitializationScript {
997          script,
998          for_main_frame_only,
999        });
1000    }
1001    self
1002  }
1003
1004  /// Register custom loading protocols with pairs of scheme uri string and a handling
1005  /// closure.
1006  ///
1007  /// The closure takes a [Request] and returns a [Response]
1008  ///
1009  /// When registering a custom protocol with the same name, only the last regisered one will be used.
1010  ///
1011  /// # Warning
1012  ///
1013  /// Pages loaded from custom protocol will have different Origin on different platforms. And
1014  /// servers which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin`
1015  /// if you wish to send requests with native `fetch` and `XmlHttpRequest` APIs. Here are the
1016  /// different Origin headers across platforms:
1017  ///
1018  /// - macOS, iOS and Linux: `<scheme_name>://<path>` (so it will be `wry://path/to/page).
1019  /// - Windows and Android: `http://<scheme_name>.<path>` by default (so it will be `http://wry.path/to/page`). To use `https` instead of `http`, use [`WebViewBuilderExtWindows::with_https_scheme`] and [`WebViewBuilderExtAndroid::with_https_scheme`].
1020  ///
1021  /// # Reading assets on mobile
1022  ///
1023  /// - Android: For loading content from the `assets` folder (which is copied to the Andorid apk) please
1024  ///   use the function [`with_asset_loader`] from [`WebViewBuilderExtAndroid`] instead.
1025  ///   This function on Android can only be used to serve assets you can embed in the binary or are
1026  ///   elsewhere in Android (provided the app has appropriate access), but not from the `assets`
1027  ///   folder which lives within the apk. For the cases where this can be used, it works the same as in macOS and Linux.
1028  /// - iOS: To get the path of your assets, you can call [`CFBundle::resources_path`](https://docs.rs/core-foundation/latest/core_foundation/bundle/struct.CFBundle.html#method.resources_path). So url like `wry://assets/index.html` could get the html file in assets directory.
1029  #[cfg(feature = "protocol")]
1030  pub fn with_custom_protocol<F>(mut self, name: String, handler: F) -> Self
1031  where
1032    F: Fn(WebViewId, Request<Vec<u8>>) -> Response<Cow<'static, [u8]>> + 'static,
1033  {
1034    #[cfg(any(
1035      target_os = "linux",
1036      target_os = "dragonfly",
1037      target_os = "freebsd",
1038      target_os = "netbsd",
1039      target_os = "openbsd",
1040    ))]
1041    if let Some(context) = &mut self.attrs.context {
1042      if context.is_custom_protocol_registered(&name) {
1043        let err = Err(crate::Error::DuplicateCustomProtocol(name));
1044        self.error = self.error.and(err);
1045        return self;
1046      }
1047    }
1048
1049    if self.attrs.custom_protocols.contains_key(&name) {
1050      let err = Err(crate::Error::DuplicateCustomProtocol(name));
1051      self.error = self.error.and(err);
1052      return self;
1053    }
1054
1055    self.attrs.custom_protocols.insert(
1056      name,
1057      Box::new(move |id, request, responder| {
1058        let http_response = handler(id, request);
1059        responder.respond(http_response);
1060      }),
1061    );
1062    self
1063  }
1064
1065  /// Same as [`Self::with_custom_protocol`] but with an asynchronous responder.
1066  ///
1067  /// When registering a custom protocol with the same name, only the last regisered one will be used.
1068  ///
1069  /// # Warning
1070  ///
1071  /// Pages loaded from custom protocol will have different Origin on different platforms. And
1072  /// servers which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin`
1073  /// if you wish to send requests with native `fetch` and `XmlHttpRequest` APIs. Here are the
1074  /// different Origin headers across platforms:
1075  ///
1076  /// - macOS, iOS and Linux: `<scheme_name>://<path>` (so it will be `wry://path/to/page).
1077  /// - Windows and Android: `http://<scheme_name>.<path>` by default (so it will be `http://wry.path/to/page`). To use `https` instead of `http`, use [`WebViewBuilderExtWindows::with_https_scheme`] and [`WebViewBuilderExtAndroid::with_https_scheme`].
1078  ///
1079  /// # Examples
1080  ///
1081  /// ```no_run
1082  /// use wry::{WebViewBuilder, raw_window_handle};
1083  /// WebViewBuilder::new()
1084  ///   .with_asynchronous_custom_protocol("wry".into(), |_webview_id, request, responder| {
1085  ///     // here you can use a tokio task, thread pool or anything
1086  ///     // to do heavy computation to resolve your request
1087  ///     // e.g. downloading files, opening the camera...
1088  ///     std::thread::spawn(move || {
1089  ///       std::thread::sleep(std::time::Duration::from_secs(2));
1090  ///       responder.respond(http::Response::builder().body(Vec::new()).unwrap());
1091  ///     });
1092  ///   });
1093  /// ```
1094  #[cfg(feature = "protocol")]
1095  pub fn with_asynchronous_custom_protocol<F>(mut self, name: String, handler: F) -> Self
1096  where
1097    F: Fn(WebViewId, Request<Vec<u8>>, RequestAsyncResponder) + 'static,
1098  {
1099    #[cfg(any(
1100      target_os = "linux",
1101      target_os = "dragonfly",
1102      target_os = "freebsd",
1103      target_os = "netbsd",
1104      target_os = "openbsd",
1105    ))]
1106    if let Some(context) = &mut self.attrs.context {
1107      if context.is_custom_protocol_registered(&name) {
1108        let err = Err(crate::Error::DuplicateCustomProtocol(name));
1109        self.error = self.error.and(err);
1110        return self;
1111      }
1112    }
1113
1114    if self.attrs.custom_protocols.contains_key(&name) {
1115      let err = Err(crate::Error::DuplicateCustomProtocol(name));
1116      self.error = self.error.and(err);
1117      return self;
1118    }
1119
1120    self.attrs.custom_protocols.insert(name, Box::new(handler));
1121    self
1122  }
1123
1124  /// Set the IPC handler to receive the message from Javascript on webview
1125  /// using `window.ipc.postMessage("insert_message_here")` to host Rust code.
1126  ///
1127  /// ## Platform-specific
1128  ///
1129  /// - **Linux / Android**: The request URL is not supported on iframes and the main frame URL is used instead.
1130  pub fn with_ipc_handler<F>(mut self, handler: F) -> Self
1131  where
1132    F: Fn(Request<String>) + 'static,
1133  {
1134    self.attrs.ipc_handler = Some(Box::new(handler));
1135    self
1136  }
1137
1138  /// Set a handler closure to process incoming [`DragDropEvent`] of the webview.
1139  ///
1140  /// # Blocking OS Default Behavior
1141  /// Return `true` in the callback to block the OS' default behavior.
1142  ///
1143  /// Note, that if you do block this behavior, it won't be possible to drop files on `<input type="file">` forms.
1144  /// Also note, that it's not possible to manually set the value of a `<input type="file">` via JavaScript for security reasons.
1145  #[cfg(feature = "drag-drop")]
1146  #[cfg_attr(docsrs, doc(cfg(feature = "drag-drop")))]
1147  pub fn with_drag_drop_handler<F>(mut self, handler: F) -> Self
1148  where
1149    F: Fn(DragDropEvent) -> bool + 'static,
1150  {
1151    self.attrs.drag_drop_handler = Some(Box::new(handler));
1152    self
1153  }
1154
1155  /// Load the provided URL with given headers when the builder calling [`WebViewBuilder::build`] to create the [`WebView`].
1156  /// The provided URL must be valid.
1157  ///
1158  /// ## Note
1159  ///
1160  /// Data URLs are not supported, use [`html`](Self::with_html) option instead.
1161  pub fn with_url_and_headers(mut self, url: impl Into<String>, headers: http::HeaderMap) -> Self {
1162    self.attrs.url = Some(url.into());
1163    self.attrs.headers = Some(headers);
1164    self
1165  }
1166
1167  /// Load the provided URL when the builder calling [`WebViewBuilder::build`] to create the [`WebView`].
1168  /// The provided URL must be valid.
1169  ///
1170  /// ## Note
1171  ///
1172  /// Data URLs are not supported, use [`html`](Self::with_html) option instead.
1173  pub fn with_url(mut self, url: impl Into<String>) -> Self {
1174    self.attrs.url = Some(url.into());
1175    self.attrs.headers = None;
1176    self
1177  }
1178
1179  /// Set headers used when loading the requested [`url`](Self::with_url).
1180  pub fn with_headers(mut self, headers: http::HeaderMap) -> Self {
1181    self.attrs.headers = Some(headers);
1182    self
1183  }
1184
1185  /// Load the provided HTML string when the builder calling [`WebViewBuilder::build`] to create the [`WebView`].
1186  /// This will be ignored if `url` is provided.
1187  ///
1188  /// # Warning
1189  ///
1190  /// The Page loaded from html string will have `null` origin.
1191  ///
1192  /// ## PLatform-specific:
1193  ///
1194  /// - **Windows:** the string can not be larger than 2 MB (2 * 1024 * 1024 bytes) in total size
1195  pub fn with_html(mut self, html: impl Into<String>) -> Self {
1196    self.attrs.html = Some(html.into());
1197    self
1198  }
1199
1200  /// Set a custom [user-agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) for the WebView.
1201  ///
1202  /// ## Platform-specific
1203  ///
1204  /// - Windows: Requires WebView2 Runtime version 86.0.616.0 or higher, does nothing on older versions,
1205  ///   see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10790-prerelease
1206  pub fn with_user_agent(mut self, user_agent: impl Into<String>) -> Self {
1207    self.attrs.user_agent = Some(user_agent.into());
1208    self
1209  }
1210
1211  /// Enable or disable web inspector which is usually called devtools.
1212  ///
1213  /// Note this only enables devtools to the webview. To open it, you can call
1214  /// [`WebView::open_devtools`], or right click the page and open it from the context menu.
1215  ///
1216  /// ## Platform-specific
1217  ///
1218  /// - macOS: This will call private functions on **macOS**. It is enabled in **debug** builds,
1219  ///   but requires `devtools` feature flag to actually enable it in **release** builds.
1220  /// - Android: Open `chrome://inspect/#devices` in Chrome to get the devtools window. Wry's `WebView` devtools API isn't supported on Android.
1221  /// - iOS: Open Safari > Develop > [Your Device Name] > [Your WebView] to get the devtools window.
1222  pub fn with_devtools(mut self, devtools: bool) -> Self {
1223    self.attrs.devtools = devtools;
1224    self
1225  }
1226
1227  /// Whether page zooming by hotkeys or gestures is enabled
1228  ///
1229  /// ## Platform-specific
1230  ///
1231  /// - Windows: Setting to `false` can't disable pinch zoom on WebView2 Runtime version before 91.0.865.0,
1232  ///   see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10865-prerelease
1233  ///
1234  /// - **macOS / Linux / Android / iOS**: Unsupported
1235  pub fn with_hotkeys_zoom(mut self, zoom: bool) -> Self {
1236    self.attrs.zoom_hotkeys_enabled = zoom;
1237    self
1238  }
1239
1240  /// Set a navigation handler to decide if incoming url is allowed to navigate.
1241  ///
1242  /// The closure take a `String` parameter as url and returns a `bool` to determine whether the navigation should happen.
1243  /// `true` allows to navigate and `false` does not.
1244  pub fn with_navigation_handler(mut self, callback: impl Fn(String) -> bool + 'static) -> Self {
1245    self.attrs.navigation_handler = Some(Box::new(callback));
1246    self
1247  }
1248
1249  /// Set a download started handler to manage incoming downloads.
1250  ///
1251  /// The closure takes two parameters, the first is a `String` representing the url being downloaded from and and the
1252  /// second is a mutable `PathBuf` reference that (possibly) represents where the file will be downloaded to. The latter
1253  /// parameter can be used to set the download location by assigning a new path to it, the assigned path _must_ be
1254  /// absolute. The closure returns a `bool` to allow or deny the download.
1255  ///
1256  /// By default a handler that allows all downloads is set to match browser behavior.
1257  pub fn with_download_started_handler(
1258    mut self,
1259    download_started_handler: impl FnMut(String, &mut PathBuf) -> bool + 'static,
1260  ) -> Self {
1261    self.attrs.download_started_handler = Some(Box::new(download_started_handler));
1262    self
1263  }
1264
1265  /// Sets a download completion handler to manage downloads that have finished.
1266  ///
1267  /// The closure is fired when the download completes, whether it was successful or not.
1268  /// The closure takes a `String` representing the URL of the original download request, an `Option<PathBuf>`
1269  /// potentially representing the filesystem path the file was downloaded to, and a `bool` indicating if the download
1270  /// succeeded. A value of `None` being passed instead of a `PathBuf` does not necessarily indicate that the download
1271  /// did not succeed, and may instead indicate some other failure, always check the third parameter if you need to
1272  /// know if the download succeeded.
1273  ///
1274  /// ## Platform-specific:
1275  ///
1276  /// - **macOS**: The second parameter indicating the path the file was saved to, is always empty,
1277  ///   due to API limitations.
1278  pub fn with_download_completed_handler(
1279    mut self,
1280    download_completed_handler: impl Fn(String, Option<PathBuf>, bool) + 'static,
1281  ) -> Self {
1282    self.attrs.download_completed_handler = Some(Rc::new(download_completed_handler));
1283    self
1284  }
1285
1286  /// Enables clipboard access for the page rendered on **Linux** and **Windows**.
1287  ///
1288  /// macOS doesn't provide such method and is always enabled by default. But your app will still need to add menu
1289  /// item accelerators to use the clipboard shortcuts.
1290  pub fn with_clipboard(mut self, clipboard: bool) -> Self {
1291    self.attrs.clipboard = clipboard;
1292    self
1293  }
1294
1295  /// Set a new window request handler to decide if incoming url is allowed to be opened.
1296  ///
1297  /// A new window is requested to be opened by the [window.open] API.
1298  ///
1299  /// The closure take the URL to open and the window features object and returns [`NewWindowResponse`] to determine whether the window should open.
1300  ///
1301  /// ## Platform-specific:
1302  ///
1303  /// - **Windows**: The closure is executed on a separate thread to prevent a deadlock.
1304  ///
1305  /// [window.open]: https://developer.mozilla.org/en-US/docs/Web/API/Window/open
1306  pub fn with_new_window_req_handler(
1307    mut self,
1308    callback: impl Fn(String, NewWindowFeatures) -> NewWindowResponse + Send + Sync + 'static,
1309  ) -> Self {
1310    self.attrs.new_window_req_handler = Some(Box::new(callback));
1311    self
1312  }
1313
1314  /// Sets whether clicking an inactive window also clicks through to the webview. Default is `false`.
1315  ///
1316  /// ## Platform-specific
1317  ///
1318  /// This configuration only impacts macOS.
1319  pub fn with_accept_first_mouse(mut self, accept_first_mouse: bool) -> Self {
1320    self.attrs.accept_first_mouse = accept_first_mouse;
1321    self
1322  }
1323
1324  /// Set a handler closure to process the change of the webview's document title.
1325  pub fn with_document_title_changed_handler(
1326    mut self,
1327    callback: impl Fn(String) + 'static,
1328  ) -> Self {
1329    self.attrs.document_title_changed_handler = Some(Box::new(callback));
1330    self
1331  }
1332
1333  /// Run the WebView with incognito mode. Note that WebContext will be ingored if incognito is
1334  /// enabled.
1335  ///
1336  /// ## Platform-specific:
1337  ///
1338  /// - Windows: Requires WebView2 Runtime version 101.0.1210.39 or higher, does nothing on older versions,
1339  ///   see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10121039
1340  /// - **Android:** Unsupported yet.
1341  pub fn with_incognito(mut self, incognito: bool) -> Self {
1342    self.attrs.incognito = incognito;
1343    self
1344  }
1345
1346  /// Set a handler to process page loading events.
1347  pub fn with_on_page_load_handler(
1348    mut self,
1349    handler: impl Fn(PageLoadEvent, String) + 'static,
1350  ) -> Self {
1351    self.attrs.on_page_load_handler = Some(Box::new(handler));
1352    self
1353  }
1354
1355  /// Set a proxy configuration for the webview.
1356  ///
1357  /// - **macOS**: Requires macOS 14.0+ and the `mac-proxy` feature flag to be enabled. Supports HTTP CONNECT and SOCKSv5 proxies.
1358  /// - **Windows / Linux**: Supports HTTP CONNECT and SOCKSv5 proxies.
1359  /// - **Android / iOS:** Not supported.
1360  pub fn with_proxy_config(mut self, configuration: ProxyConfig) -> Self {
1361    self.attrs.proxy_config = Some(configuration);
1362    self
1363  }
1364
1365  /// Set whether the webview should be focused when created.
1366  ///
1367  /// ## Platform-specific:
1368  ///
1369  /// - **macOS / Android / iOS:** Unsupported.
1370  pub fn with_focused(mut self, focused: bool) -> Self {
1371    self.attrs.focused = focused;
1372    self
1373  }
1374
1375  /// Specify the webview position relative to its parent if it will be created as a child
1376  /// or if created using [`WebViewBuilderExtUnix::new_gtk`] with [`gtk::Fixed`].
1377  ///
1378  /// Defaults to `x: 0, y: 0, width: 200, height: 200`.
1379  pub fn with_bounds(mut self, bounds: Rect) -> Self {
1380    self.attrs.bounds = Some(bounds);
1381    self
1382  }
1383
1384  /// Set whether background throttling should be disabled.
1385  ///
1386  /// By default, browsers throttle timers and even unload the whole tab (view) to free resources after roughly 5 minutes when
1387  /// a view became minimized or hidden. This will permanently suspend all tasks until the documents visibility state
1388  /// changes back from hidden to visible by bringing the view back to the foreground.
1389  ///
1390  /// ## Platform-specific
1391  ///
1392  /// - **Linux / Windows / Android**: Unsupported. Workarounds like a pending WebLock transaction might suffice.
1393  /// - **iOS**: Supported since version 17.0+.
1394  /// - **macOS**: Supported since version 14.0+.
1395  ///
1396  /// see https://github.com/tauri-apps/tauri/issues/5250#issuecomment-2569380578
1397  pub fn with_background_throttling(mut self, policy: BackgroundThrottlingPolicy) -> Self {
1398    self.attrs.background_throttling = Some(policy);
1399    self
1400  }
1401
1402  /// Whether JavaScript should be disabled.
1403  pub fn with_javascript_disabled(mut self) -> Self {
1404    self.attrs.javascript_disabled = true;
1405    self
1406  }
1407
1408  /// Consume the builder and create the [`WebView`] from a type that implements [`HasWindowHandle`].
1409  ///
1410  /// # Platform-specific:
1411  ///
1412  /// - **Linux**: Only X11 is supported, if you want to support Wayland too, use [`WebViewBuilderExtUnix::new_gtk`].
1413  ///
1414  ///   Although this methods only needs an X11 window handle, we use webkit2gtk, so you still need to initialize gtk
1415  ///   by callling [`gtk::init`] and advance its loop alongside your event loop using [`gtk::main_iteration_do`].
1416  ///   Checkout the [Platform Considerations](https://docs.rs/wry/latest/wry/#platform-considerations) section in the crate root documentation.
1417  /// - **Windows**: The webview will auto-resize when the passed handle is resized.
1418  /// - **Linux (X11)**: Unlike macOS and Windows, the webview will not auto-resize and you'll need to call [`WebView::set_bounds`] manually.
1419  ///
1420  /// # Panics:
1421  ///
1422  /// - Panics if the provided handle was not supported or invalid.
1423  /// - Panics on Linux, if [`gtk::init`] was not called in this thread.
1424  pub fn build<W: HasWindowHandle>(self, window: &'a W) -> Result<WebView> {
1425    self.error?;
1426
1427    InnerWebView::new(window, self.attrs, self.platform_specific).map(|webview| WebView { webview })
1428  }
1429
1430  /// Consume the builder and create the [`WebView`] as a child window inside the provided [`HasWindowHandle`].
1431  ///
1432  /// ## Platform-specific
1433  ///
1434  /// - **Windows**: This will create the webview as a child window of the `parent` window.
1435  /// - **macOS**: This will create the webview as a `NSView` subview of the `parent` window's
1436  ///   content view.
1437  /// - **Linux**: This will create the webview as a child window of the `parent` window. Only X11
1438  ///   is supported. This method won't work on Wayland.
1439  ///
1440  ///   Although this methods only needs an X11 window handle, you use webkit2gtk, so you still need to initialize gtk
1441  ///   by callling [`gtk::init`] and advance its loop alongside your event loop using [`gtk::main_iteration_do`].
1442  ///   Checkout the [Platform Considerations](https://docs.rs/wry/latest/wry/#platform-considerations) section in the crate root documentation.
1443  ///
1444  ///   If you want to support child webviews on X11 and Wayland at the same time,
1445  ///   we recommend using [`WebViewBuilderExtUnix::new_gtk`] with [`gtk::Fixed`].
1446  /// - **Android/iOS:** Unsupported.
1447  ///
1448  /// # Panics:
1449  ///
1450  /// - Panics if the provided handle was not support or invalid.
1451  /// - Panics on Linux, if [`gtk::init`] was not called in this thread.
1452  pub fn build_as_child<W: HasWindowHandle>(self, window: &'a W) -> Result<WebView> {
1453    self.error?;
1454
1455    InnerWebView::new_as_child(window, self.attrs, self.platform_specific)
1456      .map(|webview| WebView { webview })
1457  }
1458}
1459
1460#[cfg(any(target_os = "macos", target_os = "ios"))]
1461pub(crate) struct PlatformSpecificWebViewAttributes {
1462  data_store_identifier: Option<[u8; 16]>,
1463  traffic_light_inset: Option<dpi::Position>,
1464  allow_link_preview: bool,
1465  on_web_content_process_terminate_handler: Option<Box<dyn Fn()>>,
1466  #[cfg(target_os = "ios")]
1467  input_accessory_view_builder: Option<Box<InputAccessoryViewBuilder>>,
1468  #[cfg(target_os = "ios")]
1469  limit_navigations_to_app_bound_domains: bool,
1470  #[cfg(target_os = "macos")]
1471  webview_configuration: Option<Retained<objc2_web_kit::WKWebViewConfiguration>>,
1472}
1473
1474#[cfg(any(target_os = "macos", target_os = "ios"))]
1475impl Default for PlatformSpecificWebViewAttributes {
1476  fn default() -> Self {
1477    Self {
1478      data_store_identifier: None,
1479      traffic_light_inset: None,
1480      // platform default for this is true
1481      allow_link_preview: true,
1482      on_web_content_process_terminate_handler: None,
1483      #[cfg(target_os = "ios")]
1484      input_accessory_view_builder: None,
1485      #[cfg(target_os = "ios")]
1486      limit_navigations_to_app_bound_domains: false,
1487      #[cfg(target_os = "macos")]
1488      webview_configuration: None,
1489    }
1490  }
1491}
1492
1493#[cfg(any(target_os = "macos", target_os = "ios"))]
1494pub trait WebViewBuilderExtDarwin {
1495  /// Initialize the WebView with a custom data store identifier.
1496  /// Can be used as a replacement for data_directory not being available in WKWebView.
1497  ///
1498  /// - **macOS / iOS**: Available on macOS >= 14 and iOS >= 17
1499  ///
1500  /// Note: Enable incognito mode to use the `nonPersistent` DataStore.
1501  fn with_data_store_identifier(self, identifier: [u8; 16]) -> Self;
1502  /// Move the window controls to the specified position.
1503  /// Normally this is handled by the Window but because `WebViewBuilder::build()` overwrites the window's NSView the controls will flicker on resizing.
1504  /// Note: This method has no effects if the WebView is injected via `WebViewBuilder::build_as_child();` and there should be no flickers.
1505  /// Warning: Do not use this if your chosen window library does not support traffic light insets.
1506  /// Warning: Only use this in **decorated** windows with a **hidden titlebar**!
1507  fn with_traffic_light_inset<P: Into<dpi::Position>>(self, position: P) -> Self;
1508  /// Whether to show a link preview when long pressing on links. Available on macOS and iOS only.
1509  ///
1510  /// Default is true.
1511  ///
1512  /// See https://developer.apple.com/documentation/webkit/wkwebview/allowslinkpreview
1513  fn with_allow_link_preview(self, allow_link_preview: bool) -> Self;
1514  /// Set a handler closure to respond to web content process termination. Available on macOS and iOS only.
1515  fn with_on_web_content_process_terminate_handler(self, handler: impl Fn() + 'static) -> Self;
1516}
1517
1518#[cfg(any(target_os = "macos", target_os = "ios"))]
1519impl WebViewBuilderExtDarwin for WebViewBuilder<'_> {
1520  fn with_data_store_identifier(mut self, identifier: [u8; 16]) -> Self {
1521    self.platform_specific.data_store_identifier = Some(identifier);
1522    self
1523  }
1524
1525  fn with_traffic_light_inset<P: Into<dpi::Position>>(mut self, position: P) -> Self {
1526    self.platform_specific.traffic_light_inset = Some(position.into());
1527    self
1528  }
1529
1530  fn with_allow_link_preview(mut self, allow_link_preview: bool) -> Self {
1531    self.platform_specific.allow_link_preview = allow_link_preview;
1532    self
1533  }
1534
1535  fn with_on_web_content_process_terminate_handler(mut self, handler: impl Fn() + 'static) -> Self {
1536    self
1537      .platform_specific
1538      .on_web_content_process_terminate_handler = Some(Box::new(handler));
1539    self
1540  }
1541}
1542
1543#[cfg(target_os = "macos")]
1544pub trait WebViewBuilderExtMacos {
1545  /// Set the webview configuration that must be used to create the new webview.
1546  fn with_webview_configuration(
1547    self,
1548    configuration: Retained<objc2_web_kit::WKWebViewConfiguration>,
1549  ) -> Self;
1550}
1551
1552#[cfg(target_os = "macos")]
1553impl WebViewBuilderExtMacos for WebViewBuilder<'_> {
1554  fn with_webview_configuration(
1555    mut self,
1556    configuration: Retained<objc2_web_kit::WKWebViewConfiguration>,
1557  ) -> Self {
1558    self
1559      .platform_specific
1560      .webview_configuration
1561      .replace(configuration);
1562    self
1563  }
1564}
1565
1566#[cfg(target_os = "ios")]
1567pub trait WebViewBuilderExtIos {
1568  /// Allows overriding the the keyboard accessory view on iOS.
1569  /// Returning `None` effectively removes the view.
1570  ///
1571  /// The closure parameter is the webview instance.
1572  ///
1573  /// The accessory view is the view that appears above the keyboard when a text input element is focused.
1574  /// It usually displays a view with "Done", "Next" buttons.
1575  fn with_input_accessory_view_builder<
1576    F: Fn(&objc2_ui_kit::UIView) -> Option<Retained<objc2_ui_kit::UIView>> + 'static,
1577  >(
1578    self,
1579    builder: F,
1580  ) -> Self;
1581  /// Whether to limit navigations to App-Bound Domains. This is necessary
1582  /// to enable Service Workers on iOS.
1583  ///
1584  /// Note: If you set limit_navigations to true
1585  /// make sure to add the following to Info.plist in the iOS project:
1586  /// ```xml
1587  /// <plist>
1588  /// <dict>
1589  /// 	<key>WKAppBoundDomains</key>
1590  /// 	<array>
1591  /// 		<string>localhost</string>
1592  /// 	</array>
1593  /// </dict>
1594  /// </plist>
1595  /// ```
1596  /// You should also add any additional domains which your app requests assets from.
1597  /// Assets served through custom protocols like Tauri's IPC are added to the
1598  /// list automatically. Available on iOS only.
1599  ///
1600  /// Default is false.
1601  ///
1602  /// See https://webkit.org/blog/10882/app-bound-domains/ and
1603  /// https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/limitsnavigationstoappbounddomains
1604  fn with_limit_navigations_to_app_bound_domains(self, limit_navigations: bool) -> Self;
1605}
1606
1607#[cfg(target_os = "ios")]
1608impl WebViewBuilderExtIos for WebViewBuilder<'_> {
1609  fn with_input_accessory_view_builder<
1610    F: Fn(&objc2_ui_kit::UIView) -> Option<Retained<objc2_ui_kit::UIView>> + 'static,
1611  >(
1612    mut self,
1613    builder: F,
1614  ) -> Self {
1615    self
1616      .platform_specific
1617      .input_accessory_view_builder
1618      .replace(Box::new(builder));
1619    self
1620  }
1621  fn with_limit_navigations_to_app_bound_domains(mut self, limit_navigations: bool) -> Self {
1622    self
1623      .platform_specific
1624      .limit_navigations_to_app_bound_domains = limit_navigations;
1625    self
1626  }
1627}
1628
1629#[cfg(windows)]
1630#[derive(Clone)]
1631pub(crate) struct PlatformSpecificWebViewAttributes {
1632  additional_browser_args: Option<String>,
1633  browser_accelerator_keys: bool,
1634  theme: Option<Theme>,
1635  use_https: bool,
1636  scroll_bar_style: ScrollBarStyle,
1637  browser_extensions_enabled: bool,
1638  extension_path: Option<PathBuf>,
1639  default_context_menus: bool,
1640  environment: Option<ICoreWebView2Environment>,
1641}
1642
1643#[cfg(windows)]
1644impl Default for PlatformSpecificWebViewAttributes {
1645  fn default() -> Self {
1646    Self {
1647      additional_browser_args: None,
1648      browser_accelerator_keys: true, // This is WebView2's default behavior
1649      default_context_menus: true,    // This is WebView2's default behavior
1650      theme: None,
1651      use_https: false, // To match macOS & Linux behavior in the context of mixed content.
1652      scroll_bar_style: ScrollBarStyle::default(),
1653      browser_extensions_enabled: false,
1654      extension_path: None,
1655      environment: None,
1656    }
1657  }
1658}
1659
1660#[cfg(windows)]
1661pub trait WebViewBuilderExtWindows {
1662  /// Pass additional args to WebView2 upon creating the webview.
1663  ///
1664  /// ## Warning
1665  ///
1666  /// - Webview instances with different browser arguments must also have different [data directories](struct.WebContext.html#method.new).
1667  /// - By default wry passes `--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection`
1668  ///   `--autoplay-policy=no-user-gesture-required` if autoplay is enabled
1669  ///   and `--proxy-server=<scheme>://<host>:<port>` if a proxy is set.
1670  ///   so if you use this method, you have to add these arguments yourself if you want to keep the same behavior.
1671  fn with_additional_browser_args<S: Into<String>>(self, additional_args: S) -> Self;
1672
1673  /// Determines whether browser-specific accelerator keys are enabled. When this setting is set to
1674  /// `false`, it disables all accelerator keys that access features specific to a web browser.
1675  /// The default value is `true`. See the following link to know more details.
1676  ///
1677  /// Setting to `false` does nothing on WebView2 Runtime version before 92.0.902.0,
1678  /// see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10824-prerelease
1679  ///
1680  /// <https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings#arebrowseracceleratorkeysenabled>
1681  fn with_browser_accelerator_keys(self, enabled: bool) -> Self;
1682
1683  /// Determines whether the webview's default context menus are enabled. When this setting is set to `false`,
1684  /// it disables all context menus on the webview - menus on the window's native decorations for example are not affected.
1685  ///
1686  /// The default value is `true` (context menus are enabled).
1687  ///
1688  /// <https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings#aredefaultcontextmenusenabled>
1689  fn with_default_context_menus(self, enabled: bool) -> Self;
1690
1691  /// Specifies the theme of webview2. This affects things like `prefers-color-scheme`.
1692  ///
1693  /// Defaults to [`Theme::Auto`] which will follow the OS defaults.
1694  ///
1695  /// Requires WebView2 Runtime version 101.0.1210.39 or higher, does nothing on older versions,
1696  /// see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10121039
1697  fn with_theme(self, theme: Theme) -> Self;
1698
1699  /// Determines whether the custom protocols should use `https://<scheme>.path/to/page` instead of the default `http://<scheme>.path/to/page`.
1700  ///
1701  /// Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints
1702  /// and is therefore less secure but will match the behavior of the `<scheme>://path/to/page` protocols used on macOS and Linux.
1703  ///
1704  /// The default value is `false`.
1705  fn with_https_scheme(self, enabled: bool) -> Self;
1706
1707  /// Specifies the native scrollbar style to use with webview2.
1708  /// CSS styles that modify the scrollbar are applied on top of the native appearance configured here.
1709  ///
1710  /// Defaults to [`ScrollbarStyle::Default`] which is the browser default used by Microsoft Edge.
1711  ///
1712  /// Requires WebView2 Runtime version 125.0.2535.41 or higher, does nothing on older versions,
1713  /// see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/?tabs=dotnetcsharp#10253541
1714  fn with_scroll_bar_style(self, style: ScrollBarStyle) -> Self;
1715
1716  /// Determines whether the ability to install and enable extensions is enabled.
1717  ///
1718  /// By default, extensions are disabled.
1719  ///
1720  /// Requires WebView2 Runtime version 1.0.2210.55 or higher, does nothing on older versions,
1721  /// see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10221055
1722  fn with_browser_extensions_enabled(self, enabled: bool) -> Self;
1723
1724  /// Set the path from which to load extensions from. Extensions stored in this path should be unpacked.
1725  ///
1726  /// Does nothing if browser extensions are disabled. See [`with_browser_extensions_enabled`](Self::with_browser_extensions_enabled)
1727  fn with_extensions_path(self, path: impl Into<PathBuf>) -> Self;
1728
1729  /// Set the environment for the webview.
1730  /// Useful if you need to share the same environment, for instance when using the [`WebViewBuilder::with_new_window_req_handler`].
1731  fn with_environment(self, environment: ICoreWebView2Environment) -> Self;
1732}
1733
1734#[cfg(windows)]
1735impl WebViewBuilderExtWindows for WebViewBuilder<'_> {
1736  fn with_additional_browser_args<S: Into<String>>(mut self, additional_args: S) -> Self {
1737    self.platform_specific.additional_browser_args = Some(additional_args.into());
1738    self
1739  }
1740
1741  fn with_browser_accelerator_keys(mut self, enabled: bool) -> Self {
1742    self.platform_specific.browser_accelerator_keys = enabled;
1743    self
1744  }
1745
1746  fn with_default_context_menus(mut self, enabled: bool) -> Self {
1747    self.platform_specific.default_context_menus = enabled;
1748    self
1749  }
1750
1751  fn with_theme(mut self, theme: Theme) -> Self {
1752    self.platform_specific.theme = Some(theme);
1753    self
1754  }
1755
1756  fn with_https_scheme(mut self, enabled: bool) -> Self {
1757    self.platform_specific.use_https = enabled;
1758    self
1759  }
1760
1761  fn with_scroll_bar_style(mut self, style: ScrollBarStyle) -> Self {
1762    self.platform_specific.scroll_bar_style = style;
1763    self
1764  }
1765
1766  fn with_browser_extensions_enabled(mut self, enabled: bool) -> Self {
1767    self.platform_specific.browser_extensions_enabled = enabled;
1768    self
1769  }
1770
1771  fn with_extensions_path(mut self, path: impl Into<PathBuf>) -> Self {
1772    self.platform_specific.extension_path = Some(path.into());
1773    self
1774  }
1775
1776  fn with_environment(mut self, environment: ICoreWebView2Environment) -> Self {
1777    self.platform_specific.environment.replace(environment);
1778    self
1779  }
1780}
1781
1782#[cfg(target_os = "android")]
1783#[derive(Default)]
1784pub(crate) struct PlatformSpecificWebViewAttributes {
1785  on_webview_created:
1786    Option<Box<dyn Fn(prelude::Context) -> std::result::Result<(), jni::errors::Error> + Send>>,
1787  with_asset_loader: bool,
1788  asset_loader_domain: Option<String>,
1789  https_scheme: bool,
1790}
1791
1792#[cfg(target_os = "android")]
1793pub trait WebViewBuilderExtAndroid {
1794  fn on_webview_created<
1795    F: Fn(prelude::Context<'_, '_>) -> std::result::Result<(), jni::errors::Error> + Send + 'static,
1796  >(
1797    self,
1798    f: F,
1799  ) -> Self;
1800
1801  /// Use [WebViewAssetLoader](https://developer.android.com/reference/kotlin/androidx/webkit/WebViewAssetLoader)
1802  /// to load assets from Android's `asset` folder when using `with_url` as `<protocol>://assets/` (e.g.:
1803  /// `wry://assets/index.html`). Note that this registers a custom protocol with the provided
1804  /// String, similar to [`with_custom_protocol`], but also sets the WebViewAssetLoader with the
1805  /// necessary domain (which is fixed as `<protocol>.assets`). This cannot be used in conjunction
1806  /// to `with_custom_protocol` for Android, as it changes the way in which requests are handled.
1807  #[cfg(feature = "protocol")]
1808  fn with_asset_loader(self, protocol: String) -> Self;
1809
1810  /// Determines whether the custom protocols should use `https://<scheme>.localhost` instead of the default `http://<scheme>.localhost`.
1811  ///
1812  /// Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints
1813  /// and is therefore less secure but will match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.
1814  ///
1815  /// The default value is `false`.
1816  fn with_https_scheme(self, enabled: bool) -> Self;
1817}
1818
1819#[cfg(target_os = "android")]
1820impl WebViewBuilderExtAndroid for WebViewBuilder<'_> {
1821  fn on_webview_created<
1822    F: Fn(prelude::Context<'_, '_>) -> std::result::Result<(), jni::errors::Error> + Send + 'static,
1823  >(
1824    mut self,
1825    f: F,
1826  ) -> Self {
1827    self.platform_specific.on_webview_created = Some(Box::new(f));
1828    self
1829  }
1830
1831  #[cfg(feature = "protocol")]
1832  fn with_asset_loader(mut self, protocol: String) -> Self {
1833    // register custom protocol with empty Response return,
1834    // this is necessary due to the need of fixing a domain
1835    // in WebViewAssetLoader.
1836    self.attrs.custom_protocols.insert(
1837      protocol.clone(),
1838      Box::new(|_, _, api| {
1839        api.respond(Response::builder().body(Vec::new()).unwrap());
1840      }),
1841    );
1842    self.platform_specific.with_asset_loader = true;
1843    self.platform_specific.asset_loader_domain = Some(format!("{}.assets", protocol));
1844    self
1845  }
1846
1847  fn with_https_scheme(mut self, enabled: bool) -> Self {
1848    self.platform_specific.https_scheme = enabled;
1849    self
1850  }
1851}
1852
1853#[cfg(any(
1854  target_os = "linux",
1855  target_os = "dragonfly",
1856  target_os = "freebsd",
1857  target_os = "netbsd",
1858  target_os = "openbsd",
1859))]
1860#[derive(Default)]
1861pub(crate) struct PlatformSpecificWebViewAttributes {
1862  extension_path: Option<PathBuf>,
1863  related_view: Option<webkit2gtk::WebView>,
1864}
1865
1866#[cfg(any(
1867  target_os = "linux",
1868  target_os = "dragonfly",
1869  target_os = "freebsd",
1870  target_os = "netbsd",
1871  target_os = "openbsd",
1872))]
1873pub trait WebViewBuilderExtUnix<'a> {
1874  /// Consume the builder and create the webview inside a GTK container widget, such as GTK window.
1875  ///
1876  /// - If the container is [`gtk::Box`], it is added using [`Box::pack_start(webview, true, true, 0)`](gtk::prelude::BoxExt::pack_start).
1877  /// - If the container is [`gtk::Fixed`], its [size request](gtk::prelude::WidgetExt::set_size_request) will be set using the (width, height) bounds passed in
1878  ///   and will be added to the container using [`Fixed::put`](gtk::prelude::FixedExt::put) using the (x, y) bounds passed in.
1879  /// - For all other containers, it will be added using [`gtk::prelude::ContainerExt::add`]
1880  ///
1881  /// # Panics:
1882  ///
1883  /// - Panics if [`gtk::init`] was not called in this thread.
1884  fn build_gtk<W>(self, widget: &'a W) -> Result<WebView>
1885  where
1886    W: gtk::prelude::IsA<gtk::Container>;
1887
1888  /// Set the path from which to load extensions from.
1889  fn with_extensions_path(self, path: impl Into<PathBuf>) -> Self;
1890
1891  /// Creates a new webview sharing the same web process with the provided webview.
1892  /// Useful if you need to link a webview to another, for instance when using the [`WebViewBuilder::with_new_window_req_handler`].
1893  fn with_related_view(self, webview: webkit2gtk::WebView) -> Self;
1894}
1895
1896#[cfg(any(
1897  target_os = "linux",
1898  target_os = "dragonfly",
1899  target_os = "freebsd",
1900  target_os = "netbsd",
1901  target_os = "openbsd",
1902))]
1903impl<'a> WebViewBuilderExtUnix<'a> for WebViewBuilder<'a> {
1904  fn build_gtk<W>(self, widget: &'a W) -> Result<WebView>
1905  where
1906    W: gtk::prelude::IsA<gtk::Container>,
1907  {
1908    self.error?;
1909
1910    InnerWebView::new_gtk(widget, self.attrs, self.platform_specific)
1911      .map(|webview| WebView { webview })
1912  }
1913
1914  fn with_extensions_path(mut self, path: impl Into<PathBuf>) -> Self {
1915    self.platform_specific.extension_path = Some(path.into());
1916    self
1917  }
1918
1919  fn with_related_view(mut self, webview: webkit2gtk::WebView) -> Self {
1920    self.platform_specific.related_view.replace(webview);
1921    self
1922  }
1923}
1924
1925/// The fundamental type to present a [`WebView`].
1926///
1927/// [`WebViewBuilder`] / [`WebView`] are the basic building blocks to construct WebView contents and
1928/// scripts for those who prefer to control fine grained window creation and event handling.
1929/// [`WebView`] presents the actual WebView window and let you still able to perform actions on it.
1930pub struct WebView {
1931  webview: InnerWebView,
1932}
1933
1934impl WebView {
1935  /// Create a [`WebView`] from from a type that implements [`HasWindowHandle`].
1936  /// Note that calling this directly loses
1937  /// abilities to initialize scripts, add ipc handler, and many more before starting WebView. To
1938  /// benefit from above features, create a [`WebViewBuilder`] instead.
1939  ///
1940  /// # Platform-specific:
1941  ///
1942  /// - **Linux**: Only X11 is supported, if you want to support Wayland too, use [`WebViewExtUnix::new_gtk`].
1943  ///
1944  ///   Although this methods only needs an X11 window handle, you use webkit2gtk, so you still need to initialize gtk
1945  ///   by callling [`gtk::init`] and advance its loop alongside your event loop using [`gtk::main_iteration_do`].
1946  ///   Checkout the [Platform Considerations](https://docs.rs/wry/latest/wry/#platform-considerations) section in the crate root documentation.
1947  /// - **macOS / Windows**: The webview will auto-resize when the passed handle is resized.
1948  /// - **Linux (X11)**: Unlike macOS and Windows, the webview will not auto-resize and you'll need to call [`WebView::set_bounds`] manually.
1949  ///
1950  /// # Panics:
1951  ///
1952  /// - Panics if the provided handle was not supported or invalid.
1953  /// - Panics on Linux, if [`gtk::init`] was not called in this thread.
1954  pub fn new(window: &impl HasWindowHandle, attrs: WebViewAttributes) -> Result<Self> {
1955    WebViewBuilder::new_with_attributes(attrs).build(window)
1956  }
1957
1958  /// Create [`WebViewBuilder`] as a child window inside the provided [`HasWindowHandle`].
1959  ///
1960  /// ## Platform-specific
1961  ///
1962  /// - **Windows**: This will create the webview as a child window of the `parent` window.
1963  /// - **macOS**: This will create the webview as a `NSView` subview of the `parent` window's
1964  ///   content view.
1965  /// - **Linux**: This will create the webview as a child window of the `parent` window. Only X11
1966  ///   is supported. This method won't work on Wayland.
1967  ///
1968  ///   Although this methods only needs an X11 window handle, you use webkit2gtk, so you still need to initialize gtk
1969  ///   by callling [`gtk::init`] and advance its loop alongside your event loop using [`gtk::main_iteration_do`].
1970  ///   Checkout the [Platform Considerations](https://docs.rs/wry/latest/wry/#platform-considerations) section in the crate root documentation.
1971  ///
1972  ///   If you want to support child webviews on X11 and Wayland at the same time,
1973  ///   we recommend using [`WebViewBuilderExtUnix::new_gtk`] with [`gtk::Fixed`].
1974  /// - **Android/iOS:** Unsupported.
1975  ///
1976  /// # Panics:
1977  ///
1978  /// - Panics if the provided handle was not support or invalid.
1979  /// - Panics on Linux, if [`gtk::init`] was not called in this thread.
1980  pub fn new_as_child(parent: &impl HasWindowHandle, attrs: WebViewAttributes) -> Result<Self> {
1981    WebViewBuilder::new_with_attributes(attrs).build_as_child(parent)
1982  }
1983
1984  /// Returns the id of this webview.
1985  pub fn id(&self) -> WebViewId<'_> {
1986    self.webview.id()
1987  }
1988
1989  /// Get the current url of the webview
1990  pub fn url(&self) -> Result<String> {
1991    self.webview.url()
1992  }
1993
1994  /// Evaluate and run javascript code.
1995  pub fn evaluate_script(&self, js: &str) -> Result<()> {
1996    self
1997      .webview
1998      .eval(js, None::<Box<dyn Fn(String) + Send + 'static>>)
1999  }
2000
2001  /// Evaluate and run javascript code with callback function. The evaluation result will be
2002  /// serialized into a JSON string and passed to the callback function.
2003  ///
2004  /// Exception is ignored because of the limitation on windows. You can catch it yourself and return as string as a workaround.
2005  ///
2006  /// - ** Android:** Not implemented yet.
2007  pub fn evaluate_script_with_callback(
2008    &self,
2009    js: &str,
2010    callback: impl Fn(String) + Send + 'static,
2011  ) -> Result<()> {
2012    self.webview.eval(js, Some(callback))
2013  }
2014
2015  /// Launch print modal for the webview content.
2016  pub fn print(&self) -> Result<()> {
2017    self.webview.print()
2018  }
2019
2020  /// Get a list of cookies for specific url.
2021  pub fn cookies_for_url(&self, url: &str) -> Result<Vec<cookie::Cookie<'static>>> {
2022    self.webview.cookies_for_url(url)
2023  }
2024
2025  /// Get the list of cookies.
2026  ///
2027  /// ## Platform-specific
2028  ///
2029  /// - **Android**: Unsupported, always returns an empty [`Vec`].
2030  pub fn cookies(&self) -> Result<Vec<cookie::Cookie<'static>>> {
2031    self.webview.cookies()
2032  }
2033
2034  /// Set a cookie for the webview.
2035  ///
2036  /// ## Platform-specific
2037  ///
2038  /// - **Android**: Not supported.
2039  pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
2040    self.webview.set_cookie(cookie)
2041  }
2042
2043  /// Delete a cookie for the webview.
2044  ///
2045  /// ## Platform-specific
2046  ///
2047  /// - **Android**: Not supported.
2048  pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
2049    self.webview.delete_cookie(cookie)
2050  }
2051
2052  /// Open the web inspector which is usually called dev tool.
2053  ///
2054  /// ## Platform-specific
2055  ///
2056  /// - **Android / iOS:** Not supported.
2057  #[cfg(any(debug_assertions, feature = "devtools"))]
2058  pub fn open_devtools(&self) {
2059    self.webview.open_devtools()
2060  }
2061
2062  /// Close the web inspector which is usually called dev tool.
2063  ///
2064  /// ## Platform-specific
2065  ///
2066  /// - **Windows / Android / iOS:** Not supported.
2067  #[cfg(any(debug_assertions, feature = "devtools"))]
2068  pub fn close_devtools(&self) {
2069    self.webview.close_devtools()
2070  }
2071
2072  /// Gets the devtool window's current visibility state.
2073  ///
2074  /// ## Platform-specific
2075  ///
2076  /// - **Windows / Android / iOS:** Not supported.
2077  #[cfg(any(debug_assertions, feature = "devtools"))]
2078  pub fn is_devtools_open(&self) -> bool {
2079    self.webview.is_devtools_open()
2080  }
2081
2082  /// Set the webview zoom level
2083  ///
2084  /// ## Platform-specific:
2085  ///
2086  /// - **Android**: Not supported.
2087  /// - **macOS**: available on macOS 11+ only.
2088  /// - **iOS**: available on iOS 14+ only.
2089  pub fn zoom(&self, scale_factor: f64) -> Result<()> {
2090    self.webview.zoom(scale_factor)
2091  }
2092
2093  /// Specify the webview background color.
2094  ///
2095  /// The color uses the RGBA format.
2096  ///
2097  /// ## Platfrom-specific:
2098  ///
2099  /// - **macOS**: Not implemented.
2100  /// - **Windows**:
2101  ///   - On Windows 7, transparency is not supported and the alpha value will be ignored.
2102  ///   - On Windows higher than 7: translucent colors are not supported so any alpha value other than `0` will be replaced by `255`
2103  pub fn set_background_color(&self, background_color: RGBA) -> Result<()> {
2104    self.webview.set_background_color(background_color)
2105  }
2106
2107  /// Navigate to the specified url
2108  pub fn load_url(&self, url: &str) -> Result<()> {
2109    self.webview.load_url(url)
2110  }
2111
2112  /// Reloads the current page.
2113  pub fn reload(&self) -> crate::Result<()> {
2114    self.webview.reload()
2115  }
2116
2117  /// Navigate to the specified url using the specified headers
2118  pub fn load_url_with_headers(&self, url: &str, headers: http::HeaderMap) -> Result<()> {
2119    self.webview.load_url_with_headers(url, headers)
2120  }
2121
2122  /// Load html content into the webview
2123  pub fn load_html(&self, html: &str) -> Result<()> {
2124    self.webview.load_html(html)
2125  }
2126
2127  /// Clear all browsing data
2128  pub fn clear_all_browsing_data(&self) -> Result<()> {
2129    self.webview.clear_all_browsing_data()
2130  }
2131
2132  pub fn bounds(&self) -> Result<Rect> {
2133    self.webview.bounds()
2134  }
2135
2136  /// Set the webview bounds.
2137  ///
2138  /// This is only effective if the webview was created as a child
2139  /// or created using [`WebViewBuilderExtUnix::new_gtk`] with [`gtk::Fixed`].
2140  pub fn set_bounds(&self, bounds: Rect) -> Result<()> {
2141    self.webview.set_bounds(bounds)
2142  }
2143
2144  /// Shows or hides the webview.
2145  pub fn set_visible(&self, visible: bool) -> Result<()> {
2146    self.webview.set_visible(visible)
2147  }
2148
2149  /// Try moving focus to the webview.
2150  pub fn focus(&self) -> Result<()> {
2151    self.webview.focus()
2152  }
2153
2154  /// Try moving focus away from the webview back to the parent window.
2155  ///
2156  /// ## Platform-specific:
2157  ///
2158  /// - **Android**: Not implemented.
2159  pub fn focus_parent(&self) -> Result<()> {
2160    self.webview.focus_parent()
2161  }
2162}
2163
2164/// An event describing drag and drop operations on the webview.
2165#[non_exhaustive]
2166#[derive(Debug, Clone)]
2167pub enum DragDropEvent {
2168  /// A drag operation has entered the webview.
2169  Enter {
2170    /// List of paths that are being dragged onto the webview.
2171    paths: Vec<PathBuf>,
2172    /// Position of the drag operation, relative to the webview top-left corner.
2173    position: (i32, i32),
2174  },
2175  /// A drag operation is moving over the window.
2176  Over {
2177    /// Position of the drag operation, relative to the webview top-left corner.
2178    position: (i32, i32),
2179  },
2180  /// The file(s) have been dropped onto the window.
2181  Drop {
2182    /// List of paths that are being dropped onto the window.
2183    paths: Vec<PathBuf>,
2184    /// Position of the drag operation, relative to the webview top-left corner.
2185    position: (i32, i32),
2186  },
2187  /// The drag operation has been cancelled or left the window.
2188  Leave,
2189}
2190
2191/// Get WebView/Webkit version on current platform.
2192#[cfg(feature = "os-webview")]
2193#[cfg_attr(docsrs, doc(cfg(feature = "os-webview")))]
2194pub fn webview_version() -> Result<String> {
2195  platform_webview_version()
2196}
2197
2198/// The [memory usage target level][1]. There are two levels 'Low' and 'Normal' and the default
2199/// level is 'Normal'. When the application is going inactive, setting the level to 'Low' can
2200/// significantly reduce the application's memory consumption.
2201///
2202/// [1]: https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2memoryusagetargetlevel
2203#[cfg(target_os = "windows")]
2204#[non_exhaustive]
2205#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
2206pub enum MemoryUsageLevel {
2207  /// The 'Normal' memory usage. Applications should set this level when they are becoming active.
2208  #[default]
2209  Normal,
2210  /// The 'Low' memory usage. Applications can reduce memory comsumption by setting this level when
2211  /// they are becoming inactive.
2212  Low,
2213}
2214
2215/// Additional methods on `WebView` that are specific to Windows.
2216#[cfg(target_os = "windows")]
2217pub trait WebViewExtWindows {
2218  /// Returns the WebView2 controller.
2219  fn controller(&self) -> ICoreWebView2Controller;
2220
2221  /// Webview environment.
2222  fn environment(&self) -> ICoreWebView2Environment;
2223
2224  /// Webview instance.
2225  fn webview(&self) -> ICoreWebView2;
2226
2227  /// Changes the webview2 theme.
2228  ///
2229  /// Requires WebView2 Runtime version 101.0.1210.39 or higher, returns error on older versions,
2230  /// see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10121039
2231  fn set_theme(&self, theme: Theme) -> Result<()>;
2232
2233  /// Sets the [memory usage target level][1].
2234  ///
2235  /// When to best use this mode depends on the app in question. Most commonly it's called when
2236  /// the app's visiblity state changes.
2237  ///
2238  /// Please read the [guide for WebView2][2] for more details.
2239  ///
2240  /// This method uses a WebView2 API added in Runtime version 114.0.1823.32. When it is used in
2241  /// an older Runtime version, it does nothing.
2242  ///
2243  /// [1]: https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2memoryusagetargetlevel
2244  /// [2]: https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.memoryusagetargetlevel?view=webview2-dotnet-1.0.2088.41#remarks
2245  fn set_memory_usage_level(&self, level: MemoryUsageLevel) -> Result<()>;
2246
2247  /// Attaches this webview to the given HWND and removes it from the current one.
2248  fn reparent(&self, hwnd: isize) -> Result<()>;
2249}
2250
2251#[cfg(target_os = "windows")]
2252impl WebViewExtWindows for WebView {
2253  fn controller(&self) -> ICoreWebView2Controller {
2254    self.webview.controller.clone()
2255  }
2256
2257  fn environment(&self) -> ICoreWebView2Environment {
2258    self.webview.env.clone()
2259  }
2260
2261  fn webview(&self) -> ICoreWebView2 {
2262    self.webview.webview.clone()
2263  }
2264
2265  fn set_theme(&self, theme: Theme) -> Result<()> {
2266    self.webview.set_theme(theme)
2267  }
2268
2269  fn set_memory_usage_level(&self, level: MemoryUsageLevel) -> Result<()> {
2270    self.webview.set_memory_usage_level(level)
2271  }
2272
2273  fn reparent(&self, hwnd: isize) -> Result<()> {
2274    self.webview.reparent(hwnd)
2275  }
2276}
2277
2278/// Additional methods on `WebView` that are specific to Linux.
2279#[cfg(gtk)]
2280pub trait WebViewExtUnix: Sized {
2281  /// Create the webview inside a GTK container widget, such as GTK window.
2282  ///
2283  /// - If the container is [`gtk::Box`], it is added using [`Box::pack_start(webview, true, true, 0)`](gtk::prelude::BoxExt::pack_start).
2284  /// - If the container is [`gtk::Fixed`], its [size request](gtk::prelude::WidgetExt::set_size_request) will be set using the (width, height) bounds passed in
2285  ///   and will be added to the container using [`Fixed::put`](gtk::prelude::FixedExt::put) using the (x, y) bounds passed in.
2286  /// - For all other containers, it will be added using [`gtk::prelude::ContainerExt::add`]
2287  ///
2288  /// # Panics:
2289  ///
2290  /// - Panics if [`gtk::init`] was not called in this thread.
2291  fn new_gtk<W>(widget: &W) -> Result<Self>
2292  where
2293    W: gtk::prelude::IsA<gtk::Container>;
2294
2295  /// Returns Webkit2gtk Webview handle
2296  fn webview(&self) -> webkit2gtk::WebView;
2297
2298  /// Attaches this webview to the given Widget and removes it from the current one.
2299  fn reparent<W>(&self, widget: &W) -> Result<()>
2300  where
2301    W: gtk::prelude::IsA<gtk::Container>;
2302}
2303
2304#[cfg(gtk)]
2305impl WebViewExtUnix for WebView {
2306  fn new_gtk<W>(widget: &W) -> Result<Self>
2307  where
2308    W: gtk::prelude::IsA<gtk::Container>,
2309  {
2310    WebViewBuilder::new().build_gtk(widget)
2311  }
2312
2313  fn webview(&self) -> webkit2gtk::WebView {
2314    self.webview.webview.clone()
2315  }
2316
2317  fn reparent<W>(&self, widget: &W) -> Result<()>
2318  where
2319    W: gtk::prelude::IsA<gtk::Container>,
2320  {
2321    self.webview.reparent(widget)
2322  }
2323}
2324
2325/// Additional methods on `WebView` that are specific to macOS or iOS.
2326#[cfg(any(target_os = "macos", target_os = "ios"))]
2327pub trait WebViewExtDarwin {
2328  /// Prints with extra options
2329  fn print_with_options(&self, options: &PrintOptions) -> Result<()>;
2330  /// Fetches all Data Store Identifiers of this application
2331  ///
2332  /// Needs to run on main thread and needs an event loop to run.
2333  fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(cb: F) -> Result<()>;
2334  /// Deletes a Data Store by an identifier.
2335  ///
2336  /// You must drop any WebView instances using the data store before you call this method.
2337  ///
2338  /// Needs to run on main thread and needs an event loop to run.
2339  fn remove_data_store<F: FnOnce(Result<()>) + Send + 'static>(uuid: &[u8; 16], cb: F);
2340}
2341
2342#[cfg(any(target_os = "macos", target_os = "ios"))]
2343impl WebViewExtDarwin for WebView {
2344  fn print_with_options(&self, options: &PrintOptions) -> Result<()> {
2345    self.webview.print_with_options(options)
2346  }
2347
2348  fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(cb: F) -> Result<()> {
2349    wkwebview::InnerWebView::fetch_data_store_identifiers(cb)
2350  }
2351
2352  fn remove_data_store<F: FnOnce(Result<()>) + Send + 'static>(uuid: &[u8; 16], cb: F) {
2353    wkwebview::InnerWebView::remove_data_store(uuid, cb)
2354  }
2355}
2356
2357/// Additional methods on `WebView` that are specific to macOS.
2358#[cfg(target_os = "macos")]
2359pub trait WebViewExtMacOS {
2360  /// Returns WKWebView handle
2361  fn webview(&self) -> Retained<WryWebView>;
2362  /// Returns WKWebView manager [(userContentController)](https://developer.apple.com/documentation/webkit/wkscriptmessagehandler/1396222-usercontentcontroller) handle
2363  fn manager(&self) -> Retained<WKUserContentController>;
2364  /// Returns NSWindow associated with the WKWebView webview
2365  fn ns_window(&self) -> Retained<NSWindow>;
2366  /// Attaches this webview to the given NSWindow and removes it from the current one.
2367  fn reparent(&self, window: *mut NSWindow) -> Result<()>;
2368  /// Prints with extra options
2369  fn print_with_options(&self, options: &PrintOptions) -> Result<()>;
2370  /// Move the window controls to the specified position.
2371  /// Normally this is handled by the Window but because `WebViewBuilder::build()` overwrites the window's NSView the controls will flicker on resizing.
2372  /// Note: This method has no effects if the WebView is injected via `WebViewBuilder::build_as_child();` and there should be no flickers.
2373  /// Warning: Do not use this if your chosen window library does not support traffic light insets.
2374  /// Warning: Only use this in **decorated** windows with a **hidden titlebar**!
2375  fn set_traffic_light_inset<P: Into<dpi::Position>>(&self, position: P) -> Result<()>;
2376}
2377
2378#[cfg(target_os = "macos")]
2379impl WebViewExtMacOS for WebView {
2380  fn webview(&self) -> Retained<WryWebView> {
2381    self.webview.webview.clone()
2382  }
2383
2384  fn manager(&self) -> Retained<WKUserContentController> {
2385    self.webview.manager.clone()
2386  }
2387
2388  fn ns_window(&self) -> Retained<NSWindow> {
2389    self.webview.webview.window().unwrap().clone()
2390  }
2391
2392  fn reparent(&self, window: *mut NSWindow) -> Result<()> {
2393    self.webview.reparent(window)
2394  }
2395
2396  fn print_with_options(&self, options: &PrintOptions) -> Result<()> {
2397    self.webview.print_with_options(options)
2398  }
2399
2400  fn set_traffic_light_inset<P: Into<dpi::Position>>(&self, position: P) -> Result<()> {
2401    self.webview.set_traffic_light_inset(position.into())
2402  }
2403}
2404
2405/// Additional methods on `WebView` that are specific to iOS.
2406#[cfg(target_os = "ios")]
2407pub trait WebViewExtIOS {
2408  /// Returns WKWebView handle
2409  fn webview(&self) -> Retained<WryWebView>;
2410  /// Returns WKWebView manager [(userContentController)](https://developer.apple.com/documentation/webkit/wkscriptmessagehandler/1396222-usercontentcontroller) handle
2411  fn manager(&self) -> Retained<WKUserContentController>;
2412}
2413
2414#[cfg(target_os = "ios")]
2415impl WebViewExtIOS for WebView {
2416  fn webview(&self) -> Retained<WryWebView> {
2417    self.webview.webview.clone()
2418  }
2419
2420  fn manager(&self) -> Retained<WKUserContentController> {
2421    self.webview.manager.clone()
2422  }
2423}
2424
2425#[cfg(target_os = "android")]
2426/// Additional methods on `WebView` that are specific to Android
2427pub trait WebViewExtAndroid {
2428  fn handle(&self) -> JniHandle;
2429}
2430
2431#[cfg(target_os = "android")]
2432impl WebViewExtAndroid for WebView {
2433  fn handle(&self) -> JniHandle {
2434    JniHandle
2435  }
2436}
2437
2438/// WebView theme.
2439#[derive(Debug, Clone, Copy)]
2440pub enum Theme {
2441  /// Dark
2442  Dark,
2443  /// Light
2444  Light,
2445  /// System preference
2446  Auto,
2447}
2448
2449/// Type alias for a color in the RGBA format.
2450///
2451/// Each value can be 0..255 inclusive.
2452pub type RGBA = (u8, u8, u8, u8);
2453
2454/// Type of of page loading event
2455pub enum PageLoadEvent {
2456  /// Indicates that the content of the page has started loading
2457  Started,
2458  /// Indicates that the page content has finished loading
2459  Finished,
2460}
2461
2462/// Background throttling policy
2463#[derive(Debug, Clone)]
2464pub enum BackgroundThrottlingPolicy {
2465  /// A policy where background throttling is disabled
2466  Disabled,
2467  /// A policy where a web view that's not in a window fully suspends tasks.
2468  Suspend,
2469  /// A policy where a web view that's not in a window limits processing, but does not fully suspend tasks.
2470  Throttle,
2471}
2472
2473/// An initialization script
2474#[derive(Debug, Clone)]
2475pub struct InitializationScript {
2476  /// The script to run
2477  pub script: String,
2478  /// Whether the script should be injected to main frame only.
2479  ///
2480  /// When set to false, the script is also injected to subframes.
2481  ///
2482  /// ## Platform-specific
2483  ///
2484  /// - **Windows**: scripts are always injected into subframes regardless of this option.
2485  ///   This will be the case until Webview2 implements a proper API to inject a script only on the main frame.
2486  /// - **Android**: When [addDocumentStartJavaScript] is not supported, scripts are always injected into main frame only.
2487  ///
2488  /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
2489  pub for_main_frame_only: bool,
2490}
2491
2492#[cfg(test)]
2493mod tests {
2494  use super::*;
2495
2496  #[test]
2497  #[cfg_attr(miri, ignore)]
2498  fn should_get_webview_version() {
2499    if let Err(error) = webview_version() {
2500      panic!("{}", error);
2501    }
2502  }
2503}