snapshot of https://github.com/tauri-apps/tauri.git (dev, 2026-09-23; blobs > 131072B omitted)
Some checks failed
Audit / audit-js (push) Failing after 0s
bench / bench (map[os:ubuntu-latest runner:xvfb-run --auto-servernum target:x86_64-unknown-linux-gnu], nightly) (push) Failing after 0s
covector version or publish / run-integration-tests (ubuntu-latest) (push) Failing after 0s
Audit / audit-rust (push) Failing after 0s
test `@tauri-apps/cli` / test (ubuntu-latest) (push) Failing after 0s
test `tauri-cli` / test (map[os:ubuntu-latest target:x86_64-unknown-linux-gnu]) (push) Failing after 0s
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:ubuntu-latest target:x86_64-unknown-linux-gnu toolchain:1.90]) (push) Failing after 0s
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:ubuntu-latest target:x86_64-unknown-linux-gnu toolchain:1.90]) (push) Failing after 0s
test core / test (map[args:--no-default-features key:no-default], map[cargo:cross command:build os:ubuntu-latest target:aarch64-linux-android toolchain:1.90]) (push) Failing after 0s
deploy schema worker / deploy (push) Failing after 0s
lint rust / clippy (map[cargo:cargo include: os:ubuntu-latest target:x86_64-unknown-linux-gnu]) (push) Failing after 0s
lint rust / clippy (map[cargo:cross include:--package api os:ubuntu-latest target:aarch64-linux-android]) (push) Failing after 0s
supply chain health status / check rust dependencies with cargo vet (push) Failing after 0s
test `@tauri-apps/api` e2e (mobile) / android (push) Failing after 0s
test `@tauri-apps/api` e2e / test (map[name:Linux os:ubuntu-latest]) (push) Failing after 0s
test core / test (map[args:--all-features key:all], map[cargo:cross command:build os:ubuntu-latest target:aarch64-linux-android toolchain:1.90]) (push) Failing after 0s
Udeps / changes (push) Failing after 0s
Udeps / setup (push) Has been skipped
Udeps / udeps (push) Has been skipped
bench / bench (map[os:macos-latest runner: target:aarch64-apple-darwin], nightly) (push) Has been cancelled
bench / bench (map[os:windows-latest runner: target:x86_64-pc-windows-msvc], nightly) (push) Has been cancelled
covector version or publish / run-integration-tests (macos-latest) (push) Has been cancelled
covector version or publish / run-integration-tests (windows-latest) (push) Has been cancelled
covector version or publish / version-or-publish (push) Has been cancelled
test `@tauri-apps/cli` / test (macos-latest) (push) Has been cancelled
test `tauri-cli` / test (map[args:--no-default-features --features native-tls-vendored os:windows-latest restore-only:true target:aarch64-pc-windows-msvc]) (push) Has been cancelled
test `tauri-cli` / test (map[os:macos-latest target:x86_64-apple-darwin]) (push) Has been cancelled
test `tauri-cli` / test (map[os:windows-latest target:x86_64-pc-windows-msvc]) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:build os:macos-latest target:aarch64-apple-ios toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:macos-14 target:aarch64-apple-darwin toolchain:1.90]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include: os:macos-latest target:aarch64-apple-darwin]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include: os:windows-latest target:x86_64-pc-windows-msvc]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include:--package api os:macos-latest target:aarch64-apple-ios]) (push) Has been cancelled
test `@tauri-apps/api` e2e (mobile) / ios (push) Has been cancelled
test `@tauri-apps/api` e2e / test (map[name:Windows os:windows-latest]) (push) Has been cancelled
test `@tauri-apps/api` e2e / test (map[name:macOS os:macos-latest]) (push) Has been cancelled
test `@tauri-apps/cli` / test (windows-latest) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:windows-latest target:x86_64-pc-windows-msvc toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:build os:macos-latest target:aarch64-apple-ios toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:macos-14 target:aarch64-apple-darwin toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:windows-latest target:x86_64-pc-windows-msvc toolchain:1.90]) (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-23 17:00:42 +05:00
commit feda81bf2f
1178 changed files with 156404 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
pub use dpi::*;
use serde::Serialize;
/// A rectangular region.
#[derive(Clone, Copy, Debug, Serialize)]
pub struct Rect {
/// Rect position.
pub position: dpi::Position,
/// Rect size.
pub size: dpi::Size,
}
impl Default for Rect {
fn default() -> Self {
Self {
position: Position::Logical((0, 0).into()),
size: Size::Logical((0, 0).into()),
}
}
}
/// A rectangular region in physical pixels.
#[derive(Clone, Copy, Debug, Serialize)]
pub struct PhysicalRect<P: dpi::Pixel, S: dpi::Pixel> {
/// Rect position.
pub position: dpi::PhysicalPosition<P>,
/// Rect size.
pub size: dpi::PhysicalSize<S>,
}
impl<P: dpi::Pixel, S: dpi::Pixel> Default for PhysicalRect<P, S> {
fn default() -> Self {
Self {
position: (0, 0).into(),
size: (0, 0).into(),
}
}
}
/// A rectangular region in logical pixels.
#[derive(Clone, Copy, Debug, Serialize)]
pub struct LogicalRect<P: dpi::Pixel, S: dpi::Pixel> {
/// Rect position.
pub position: dpi::LogicalPosition<P>,
/// Rect size.
pub size: dpi::LogicalSize<S>,
}
impl<P: dpi::Pixel, S: dpi::Pixel> Default for LogicalRect<P, S> {
fn default() -> Self {
Self {
position: (0, 0).into(),
size: (0, 0).into(),
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use crate::dpi::{PhysicalPosition, PhysicalRect, PhysicalSize};
/// Monitor descriptor.
#[derive(Debug, Clone)]
pub struct Monitor {
/// A human-readable name of the monitor.
/// `None` if the monitor doesn't exist anymore.
pub name: Option<String>,
/// The monitor's resolution.
pub size: PhysicalSize<u32>,
/// The top-left corner position of the monitor relative to the larger full screen area.
pub position: PhysicalPosition<i32>,
/// The monitor's work_area.
pub work_area: PhysicalRect<i32, u32>,
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
pub scale_factor: f64,
}

View File

@@ -0,0 +1,937 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! A layer between raw [`Runtime`] webviews and Tauri.
//!
pub use crate::webview_permissions::{PermissionKind, PermissionResponse};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::window::WindowId;
use crate::{Rect, Runtime, UserEvent, window::is_label_valid};
use http::Request;
use tauri_utils::config::{
BackgroundThrottlingPolicy, Color, ScrollBarStyle as ConfigScrollBarStyle, WebviewUrl,
WindowConfig, WindowEffectsConfig,
};
use url::Url;
use std::{
borrow::Cow,
collections::HashMap,
hash::{Hash, Hasher},
path::PathBuf,
sync::Arc,
};
type UriSchemeProtocolHandler = dyn Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
+ Send
+ Sync
+ 'static;
type WebResourceRequestHandler =
dyn Fn(http::Request<Vec<u8>>, &mut http::Response<Cow<'static, [u8]>>) + Send + Sync;
type NavigationHandler = dyn Fn(&Url) -> bool + Send;
type NewWindowHandler = dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send;
type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send;
type DocumentTitleChangedHandler = dyn Fn(String) + Send + 'static;
type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync;
type PermissionRequestHandler = dyn Fn(PermissionKind) -> PermissionResponse + Send + Sync;
#[cfg(any(target_os = "macos", target_os = "ios"))]
type OnWebContentProcessTerminateHandler = dyn Fn() + Send;
#[cfg(target_os = "ios")]
type InputAccessoryViewBuilderFn = dyn Fn(&objc2_ui_kit::UIView) -> Option<objc2::rc::Retained<objc2_ui_kit::UIView>>
+ Send
+ Sync
+ 'static;
/// Download event.
pub enum DownloadEvent<'a> {
/// Download requested.
Requested {
/// The url being downloaded.
url: Url,
/// Represents where the file will be downloaded to.
/// Can be used to set the download location by assigning a new path to it.
/// The assigned path _must_ be absolute.
destination: &'a mut PathBuf,
},
/// Download finished.
Finished {
/// The URL of the original download request.
url: Url,
/// Potentially representing the filesystem path the file was downloaded to.
path: Option<PathBuf>,
/// Indicates if the download succeeded or not.
success: bool,
},
}
#[cfg(target_os = "android")]
pub struct CreationContext<'a, 'b> {
pub env: &'a mut jni::JNIEnv<'b>,
pub activity: &'a jni::objects::JObject<'b>,
pub webview: &'a jni::objects::JObject<'b>,
}
/// Kind of event for the page load handler.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PageLoadEvent {
/// Page started to load.
Started,
/// Page finished loading.
Finished,
}
/// Information about the webview that initiated a new window request.
#[derive(Debug)]
pub struct NewWindowOpener {
/// The instance of the webview that initiated the new window request.
///
/// This must be set as the related view of the new webview. See [`WebviewAttributes::related_view`].
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
pub webview: webkit2gtk::WebView,
/// The instance of the webview that initiated the new window request.
///
/// The target webview environment **MUST** match the environment of the opener webview. See [`WebviewAttributes::with_environment`].
#[cfg(windows)]
pub webview: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2,
#[cfg(windows)]
pub environment: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment,
/// The instance of the webview that initiated the new window request.
#[cfg(target_os = "macos")]
pub webview: objc2::rc::Retained<objc2_web_kit::WKWebView>,
/// Configuration of the target webview.
///
/// This **MUST** be used when creating the target webview. See [`WebviewAttributes::webview_configuration`].
#[cfg(target_os = "macos")]
pub target_configuration: objc2::rc::Retained<objc2_web_kit::WKWebViewConfiguration>,
}
/// Window features of a window requested to open.
#[derive(Debug)]
pub struct NewWindowFeatures {
pub(crate) size: Option<crate::dpi::LogicalSize<f64>>,
pub(crate) position: Option<crate::dpi::LogicalPosition<f64>>,
pub(crate) opener: NewWindowOpener,
}
impl NewWindowFeatures {
pub fn new(
size: Option<crate::dpi::LogicalSize<f64>>,
position: Option<crate::dpi::LogicalPosition<f64>>,
opener: NewWindowOpener,
) -> Self {
Self {
size,
position,
opener,
}
}
/// Specifies the size of the content area
/// as defined by the user's operating system where the new window will be generated.
pub fn size(&self) -> Option<crate::dpi::LogicalSize<f64>> {
self.size
}
/// Specifies the position of the window relative to the work area
/// as defined by the user's operating system where the new window will be generated.
pub fn position(&self) -> Option<crate::dpi::LogicalPosition<f64>> {
self.position
}
/// Returns information about the webview that initiated a new window request.
pub fn opener(&self) -> &NewWindowOpener {
&self.opener
}
}
/// Response for the new window request handler.
pub enum NewWindowResponse {
/// Allow the window to be opened with the default implementation.
Allow,
/// Allow the window to be opened, with the given window.
///
/// ## Platform-specific:
///
/// **Linux**: The webview must be related to the caller webview. See [`WebviewAttributes::related_view`].
/// **Windows**: The webview must use the same environment as the caller webview. See [`WebviewAttributes::with_environment`].
#[cfg(not(any(target_os = "android", target_os = "ios")))]
Create { window_id: WindowId },
/// Deny the window from being opened.
Deny,
}
/// The scrollbar style to use in the webview.
///
/// ## Platform-specific
///
/// - **Windows**: This option must be given the same value for all webviews that target the same data directory.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Default)]
pub enum ScrollBarStyle {
#[default]
/// The default scrollbar style for the webview.
Default,
#[cfg(windows)]
/// Fluent UI style overlay scrollbars. **Windows Only**
///
/// Requires WebView2 Runtime version 125.0.2535.41 or higher, does nothing on older versions,
/// see <https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/?tabs=dotnetcsharp#10253541>
FluentOverlay,
}
/// A webview that has yet to be built.
pub struct PendingWebview<T: UserEvent, R: Runtime<T>> {
/// The label that the webview will be named.
pub label: String,
/// The [`WebviewAttributes`] that the webview will be created with.
pub webview_attributes: WebviewAttributes,
/// Custom protocols to register on the webview
pub uri_scheme_protocols: HashMap<String, Box<UriSchemeProtocolHandler>>,
/// How to handle IPC calls on the webview.
pub ipc_handler: Option<WebviewIpcHandler<T, R>>,
/// A handler to decide if incoming url is allowed to navigate.
pub navigation_handler: Option<Box<NavigationHandler>>,
pub new_window_handler: Option<Box<NewWindowHandler>>,
pub document_title_changed_handler: Option<Box<DocumentTitleChangedHandler>>,
/// The resolved URL to load on the webview.
pub url: String,
#[cfg(target_os = "android")]
#[allow(clippy::type_complexity)]
pub on_webview_created:
Option<Box<dyn Fn(CreationContext<'_, '_>) -> Result<(), jni::errors::Error> + Send + Sync>>,
pub web_resource_request_handler: Option<Box<WebResourceRequestHandler>>,
pub on_page_load_handler: Option<Box<OnPageLoadHandler>>,
pub download_handler: Option<Arc<DownloadHandler>>,
pub permission_request_handler: Option<Box<PermissionRequestHandler>>,
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub on_web_content_process_terminate_handler: Option<Box<OnWebContentProcessTerminateHandler>>,
}
impl<T: UserEvent, R: Runtime<T>> PendingWebview<T, R> {
/// Create a new [`PendingWebview`] with a label from the given [`WebviewAttributes`].
pub fn new(
webview_attributes: WebviewAttributes,
label: impl Into<String>,
) -> crate::Result<Self> {
let label = label.into();
if !is_label_valid(&label) {
Err(crate::Error::InvalidWindowLabel)
} else {
Ok(Self {
webview_attributes,
uri_scheme_protocols: Default::default(),
label,
ipc_handler: None,
navigation_handler: None,
new_window_handler: None,
document_title_changed_handler: None,
url: "tauri://localhost".to_string(),
#[cfg(target_os = "android")]
on_webview_created: None,
web_resource_request_handler: None,
on_page_load_handler: None,
download_handler: None,
permission_request_handler: None,
#[cfg(any(target_os = "macos", target_os = "ios"))]
on_web_content_process_terminate_handler: None,
})
}
}
pub fn register_uri_scheme_protocol<
N: Into<String>,
H: Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
+ Send
+ Sync
+ 'static,
>(
&mut self,
uri_scheme: N,
protocol_handler: H,
) {
let uri_scheme = uri_scheme.into();
self
.uri_scheme_protocols
.insert(uri_scheme, Box::new(protocol_handler));
}
#[cfg(target_os = "android")]
pub fn on_webview_created<
F: Fn(CreationContext<'_, '_>) -> Result<(), jni::errors::Error> + Send + Sync + 'static,
>(
mut self,
f: F,
) -> Self {
self.on_webview_created.replace(Box::new(f));
self
}
}
/// A webview that is not yet managed by Tauri.
#[derive(Debug)]
pub struct DetachedWebview<T: UserEvent, R: Runtime<T>> {
/// Name of the window
pub label: String,
/// The [`crate::WebviewDispatch`] associated with the window.
pub dispatcher: R::WebviewDispatcher,
}
impl<T: UserEvent, R: Runtime<T>> Clone for DetachedWebview<T, R> {
fn clone(&self) -> Self {
Self {
label: self.label.clone(),
dispatcher: self.dispatcher.clone(),
}
}
}
impl<T: UserEvent, R: Runtime<T>> Hash for DetachedWebview<T, R> {
/// Only use the [`DetachedWebview`]'s label to represent its hash.
fn hash<H: Hasher>(&self, state: &mut H) {
self.label.hash(state)
}
}
impl<T: UserEvent, R: Runtime<T>> Eq for DetachedWebview<T, R> {}
impl<T: UserEvent, R: Runtime<T>> PartialEq for DetachedWebview<T, R> {
/// Only use the [`DetachedWebview`]'s label to compare equality.
fn eq(&self, other: &Self) -> bool {
self.label.eq(&other.label)
}
}
/// The attributes used to create an webview.
#[derive(Debug)]
pub struct WebviewAttributes {
pub url: WebviewUrl,
pub user_agent: Option<String>,
/// A list of initialization javascript scripts to run when loading new pages.
/// When webview load a new page, this initialization code will be executed.
/// It is guaranteed that code is executed before `window.onload`.
///
/// ## Platform-specific
///
/// - **Windows:** scripts are always added to subframes.
/// - **Android:** When [addDocumentStartJavaScript] is not supported,
/// we prepend initialization scripts to each HTML head (implementation only supported on custom protocol URLs).
/// For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
///
/// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
/// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
pub initialization_scripts: Vec<InitializationScript>,
pub data_directory: Option<PathBuf>,
pub drag_drop_handler_enabled: bool,
pub clipboard: bool,
pub accept_first_mouse: bool,
pub additional_browser_args: Option<String>,
pub window_effects: Option<WindowEffectsConfig>,
pub incognito: bool,
pub transparent: bool,
pub focus: bool,
pub bounds: Option<Rect>,
pub auto_resize: bool,
pub proxy_url: Option<Url>,
pub zoom_hotkeys_enabled: bool,
pub browser_extensions_enabled: bool,
pub extensions_path: Option<PathBuf>,
pub data_store_identifier: Option<[u8; 16]>,
pub use_https_scheme: bool,
pub devtools: Option<bool>,
pub background_color: Option<Color>,
pub traffic_light_position: Option<dpi::Position>,
pub background_throttling: Option<BackgroundThrottlingPolicy>,
pub javascript_disabled: bool,
/// on macOS and iOS there is a link preview on long pressing links, this is enabled by default.
/// see https://docs.rs/objc2-web-kit/latest/objc2_web_kit/struct.WKWebView.html#method.allowsLinkPreview
pub allow_link_preview: bool,
pub scroll_bar_style: ScrollBarStyle,
/// Controls the WebView's browser-level general autofill behavior.
///
/// **This option does not disable password or credit card autofill.**
///
/// When set to `false`, the WebView will not automatically populate
/// general form fields using previously stored data such as addresses
/// or contact information.
///
/// If not specified, this is `true` by default.
///
/// ## Platform-specific
///
/// - **Windows**: Supported. WebView2's autofill feature (called
/// "Suggestions") may not honor `autocomplete="off"` on input
/// elements in some cases.
/// - **Linux / Android / iOS / macOS**: Unsupported and performs no
/// operation.
pub general_autofill_enabled: bool,
/// Allows overriding the keyboard accessory view on iOS.
/// Returning `None` effectively removes the view.
///
/// The closure parameter is the webview instance.
///
/// The accessory view is the view that appears above the keyboard when a text input element is focused.
/// It usually displays a view with "Done", "Next" buttons.
///
/// # Stability
///
/// This relies on [`objc2_ui_kit`] which does not provide a stable API yet, so it can receive breaking changes in minor releases.
#[cfg(target_os = "ios")]
pub input_accessory_view_builder: Option<InputAccessoryViewBuilder>,
#[cfg(target_os = "ios")]
pub limit_navigations_to_app_bound_domains: bool,
/// Set the environment for the webview.
/// Useful if you need to share the same environment, for instance when using the [`PendingWebview::new_window_handler`].
#[cfg(windows)]
pub environment: Option<webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment>,
/// Creates a new webview sharing the same web process with the provided webview.
/// Useful if you need to link a webview to another, for instance when using the [`PendingWebview::new_window_handler`].
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
pub related_view: Option<webkit2gtk::WebView>,
#[cfg(target_os = "macos")]
pub webview_configuration: Option<objc2::rc::Retained<objc2_web_kit::WKWebViewConfiguration>>,
}
unsafe impl Send for WebviewAttributes {}
unsafe impl Sync for WebviewAttributes {}
#[cfg(target_os = "ios")]
#[non_exhaustive]
pub struct InputAccessoryViewBuilder(pub Box<InputAccessoryViewBuilderFn>);
#[cfg(target_os = "ios")]
impl std::fmt::Debug for InputAccessoryViewBuilder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
f.debug_struct("InputAccessoryViewBuilder").finish()
}
}
#[cfg(target_os = "ios")]
impl InputAccessoryViewBuilder {
pub fn new(builder: Box<InputAccessoryViewBuilderFn>) -> Self {
Self(builder)
}
}
impl From<&WindowConfig> for WebviewAttributes {
fn from(config: &WindowConfig) -> Self {
let mut builder = Self::new(config.url.clone())
.incognito(config.incognito)
.focused(config.focus)
.zoom_hotkeys_enabled(config.zoom_hotkeys_enabled)
.use_https_scheme(config.use_https_scheme)
.browser_extensions_enabled(config.browser_extensions_enabled)
.background_throttling(config.background_throttling.clone())
.devtools(config.devtools)
.scroll_bar_style(match config.scroll_bar_style {
ConfigScrollBarStyle::Default => ScrollBarStyle::Default,
#[cfg(windows)]
ConfigScrollBarStyle::FluentOverlay => ScrollBarStyle::FluentOverlay,
_ => ScrollBarStyle::Default,
})
.limit_navigations_to_app_bound_domains(config.limit_navigations_to_app_bound_domains)
.general_autofill_enabled(config.general_autofill_enabled);
#[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
{
builder = builder.transparent(config.transparent);
}
#[cfg(target_os = "macos")]
{
if let Some(position) = &config.traffic_light_position {
builder =
builder.traffic_light_position(dpi::LogicalPosition::new(position.x, position.y).into());
}
}
builder = builder.accept_first_mouse(config.accept_first_mouse);
if !config.drag_drop_enabled {
builder = builder.disable_drag_drop_handler();
}
if let Some(user_agent) = &config.user_agent {
builder = builder.user_agent(user_agent);
}
if let Some(additional_browser_args) = &config.additional_browser_args {
builder = builder.additional_browser_args(additional_browser_args);
}
if let Some(effects) = &config.window_effects {
builder = builder.window_effects(effects.clone());
}
if let Some(url) = &config.proxy_url {
builder = builder.proxy_url(url.to_owned());
}
if let Some(color) = config.background_color {
builder = builder.background_color(color);
}
builder.javascript_disabled = config.javascript_disabled;
builder.allow_link_preview = config.allow_link_preview;
#[cfg(target_os = "ios")]
if config.disable_input_accessory_view {
builder
.input_accessory_view_builder
.replace(InputAccessoryViewBuilder::new(Box::new(|_webview| None)));
}
builder
}
}
impl WebviewAttributes {
/// Initializes the default attributes for a webview.
pub fn new(url: WebviewUrl) -> Self {
Self {
url,
user_agent: None,
initialization_scripts: Vec::new(),
data_directory: None,
drag_drop_handler_enabled: true,
clipboard: false,
accept_first_mouse: false,
additional_browser_args: None,
window_effects: None,
incognito: false,
transparent: false,
focus: true,
bounds: None,
auto_resize: false,
proxy_url: None,
zoom_hotkeys_enabled: false,
browser_extensions_enabled: false,
data_store_identifier: None,
extensions_path: None,
use_https_scheme: false,
devtools: None,
background_color: None,
traffic_light_position: None,
background_throttling: None,
javascript_disabled: false,
allow_link_preview: true,
scroll_bar_style: ScrollBarStyle::Default,
general_autofill_enabled: true,
#[cfg(target_os = "ios")]
input_accessory_view_builder: None,
#[cfg(target_os = "ios")]
limit_navigations_to_app_bound_domains: false,
#[cfg(windows)]
environment: None,
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
related_view: None,
#[cfg(target_os = "macos")]
webview_configuration: None,
}
}
/// Sets the user agent
#[must_use]
pub fn user_agent(mut self, user_agent: &str) -> Self {
self.user_agent = Some(user_agent.to_string());
self
}
/// Adds an init script for the main frame.
///
/// When webview load a new page, this initialization code will be executed.
/// It is guaranteed that code is executed before `window.onload`.
///
/// This is executed only on the main frame.
/// If you only want to run it in all frames, use [`Self::initialization_script_on_all_frames`] instead.
///
/// ## Platform-specific
///
/// - **Windows:** scripts are always added to subframes.
/// - **Android:** When [addDocumentStartJavaScript] is not supported,
/// we prepend initialization scripts to each HTML head (implementation only supported on custom protocol URLs).
/// For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
///
/// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
/// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
#[must_use]
pub fn initialization_script(mut self, script: impl Into<String>) -> Self {
self.initialization_scripts.push(InitializationScript {
script: script.into(),
for_main_frame_only: true,
});
self
}
/// Adds an init script for all frames.
///
/// When webview load a new page, this initialization code will be executed.
/// It is guaranteed that code is executed before `window.onload`.
///
/// This is executed on all frames, main frame and also sub frames.
/// If you only want to run it in the main frame, use [`Self::initialization_script`] instead.
///
/// ## Platform-specific
///
/// - **Windows:** scripts are always added to subframes.
/// - **Android:** When [addDocumentStartJavaScript] is not supported,
/// we prepend initialization scripts to each HTML head (implementation only supported on custom protocol URLs).
/// For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
///
/// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
/// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
#[must_use]
pub fn initialization_script_on_all_frames(mut self, script: impl Into<String>) -> Self {
self.initialization_scripts.push(InitializationScript {
script: script.into(),
for_main_frame_only: false,
});
self
}
/// Data directory for the webview.
#[must_use]
pub fn data_directory(mut self, data_directory: PathBuf) -> Self {
self.data_directory.replace(data_directory);
self
}
/// Disables the drag and drop handler used internally to generate [`DragDropEvent`](crate::window::DragDropEvent)s.
///
/// This is required to use HTML5 drag and drop APIs on the frontend on Windows since we replace the drag drop handler of WebView2.
#[must_use]
pub fn disable_drag_drop_handler(mut self) -> Self {
self.drag_drop_handler_enabled = false;
self
}
/// Enables clipboard access for the page rendered on **Linux** and **Windows**.
///
/// **macOS** doesn't provide such method and is always enabled by default,
/// but you still need to add menu item accelerators to use shortcuts.
#[must_use]
pub fn enable_clipboard_access(mut self) -> Self {
self.clipboard = true;
self
}
/// Sets whether clicking an inactive window also clicks through to the webview.
#[must_use]
pub fn accept_first_mouse(mut self, accept: bool) -> Self {
self.accept_first_mouse = accept;
self
}
/// Sets additional browser arguments. **Windows Only**
#[must_use]
pub fn additional_browser_args(mut self, additional_args: &str) -> Self {
self.additional_browser_args = Some(additional_args.to_string());
self
}
/// Sets window effects
#[must_use]
pub fn window_effects(mut self, effects: WindowEffectsConfig) -> Self {
self.window_effects = Some(effects);
self
}
/// Enable or disable incognito mode for the WebView.
#[must_use]
pub fn incognito(mut self, incognito: bool) -> Self {
self.incognito = incognito;
self
}
/// Enable or disable transparency for the WebView.
#[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
#[must_use]
pub fn transparent(mut self, transparent: bool) -> Self {
self.transparent = transparent;
self
}
/// Whether the webview should be focused or not.
#[must_use]
pub fn focused(mut self, focus: bool) -> Self {
self.focus = focus;
self
}
/// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
#[must_use]
pub fn auto_resize(mut self) -> Self {
self.auto_resize = true;
self
}
/// Enable proxy for the WebView
#[must_use]
pub fn proxy_url(mut self, url: Url) -> Self {
self.proxy_url = Some(url);
self
}
/// Whether page zooming by hotkeys is enabled
///
/// ## Platform-specific:
///
/// - **Windows**: Controls WebView2's [`IsZoomControlEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings?view=webview2-winrt-1.0.2420.47#iszoomcontrolenabled) setting.
/// - **MacOS / Linux**: Injects a polyfill that zooms in and out with `ctrl/command` + `-/=`,
/// 20% in each step, ranging from 20% to 1000%. Requires `webview:allow-set-webview-zoom` permission
///
/// - **Android / iOS**: Unsupported.
#[must_use]
pub fn zoom_hotkeys_enabled(mut self, enabled: bool) -> Self {
self.zoom_hotkeys_enabled = enabled;
self
}
/// Whether browser extensions can be installed for the webview process
///
/// ## Platform-specific:
///
/// - **Windows**: Enables the WebView2 environment's [`AreBrowserExtensionsEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2environmentoptions?view=webview2-winrt-1.0.2739.15#arebrowserextensionsenabled)
/// - **MacOS / Linux / iOS / Android** - Unsupported.
#[must_use]
pub fn browser_extensions_enabled(mut self, enabled: bool) -> Self {
self.browser_extensions_enabled = enabled;
self
}
/// Sets whether the custom protocols should use `https://<scheme>.localhost` instead of the default `http://<scheme>.localhost` on Windows and Android. Defaults to `false`.
///
/// ## Note
///
/// Using a `https` scheme will NOT allow mixed content when trying to fetch `http` endpoints and therefore will not match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.
///
/// ## Warning
///
/// Changing this value between releases will change the IndexedDB, cookies and localstorage location and your app will not be able to access the old data.
#[must_use]
pub fn use_https_scheme(mut self, enabled: bool) -> Self {
self.use_https_scheme = enabled;
self
}
/// Whether web inspector, which is usually called browser devtools, is enabled or not. Enabled by default.
///
/// This API works in **debug** builds, but requires `devtools` feature flag to enable it in **release** builds.
///
/// ## Platform-specific
///
/// - macOS: This will call private functions on **macOS**.
/// - Android: Open `chrome://inspect/#devices` in Chrome to get the devtools window. Wry's `WebView` devtools API isn't supported on Android.
/// - iOS: Open Safari > Develop > [Your Device Name] > [Your WebView] to get the devtools window.
#[must_use]
pub fn devtools(mut self, enabled: Option<bool>) -> Self {
self.devtools = enabled;
self
}
/// Set the window and webview background color.
/// ## Platform-specific:
///
/// - **Windows**: On Windows 7, alpha channel is ignored for the webview layer.
/// - **Windows**: On Windows 8 and newer, if alpha channel is not `0`, it will be ignored.
#[must_use]
pub fn background_color(mut self, color: Color) -> Self {
self.background_color = Some(color);
self
}
/// Change the position of the window controls. Available on macOS only.
///
/// Requires titleBarStyle: Overlay and decorations: true.
///
/// ## Platform-specific
///
/// - **Linux / Windows / iOS / Android:** Unsupported.
#[must_use]
pub fn traffic_light_position(mut self, position: dpi::Position) -> Self {
self.traffic_light_position = Some(position);
self
}
/// Whether to show a link preview when long pressing on links. Available on macOS and iOS only.
///
/// Default is true.
///
/// See https://docs.rs/objc2-web-kit/latest/objc2_web_kit/struct.WKWebView.html#method.allowsLinkPreview
///
/// ## Platform-specific
///
/// - **Linux / Windows / Android:** Unsupported.
#[must_use]
pub fn allow_link_preview(mut self, allow_link_preview: bool) -> Self {
self.allow_link_preview = allow_link_preview;
self
}
/// Whether to limit navigations to App-Bound Domains. This is necessary to
/// enable Service Workers on iOS according to
/// [StackOverflow](https://stackoverflow.com/questions/49673399/service-workers-unavailable-in-wkwebview-in-ios-11-3/64155509#64155509).
///
/// Default is false.
///
/// Note: If you pass in `true` make sure to add localhost and any [`registrable
/// domains`](https://developer.mozilla.org/en-US/docs/Glossary/Registrable_domain)
/// used in this webview to tauri-src/Info.ios.plist:
///
/// ```xml
/// <plist>
/// <dict>
/// <key>WKAppBoundDomains</key>
/// <array>
/// <string>localhost</string>
/// <string>aregistrabledomain.example</string>
/// </array>
/// </dict>
/// </plist>
/// ```
///
/// You must add `localhost` if any webview with this set to true opens a
/// local webpage, makes any localhost calls, or uses the isolation pattern
/// because Tauri uses the `localhost` domain for hosting the application
/// webpage, the IPC protocol, and the isolation pattern's iframe.
///
/// Requests served through custom uri schemes are allowed so long as they use
/// a registrable domain specified in the `WKAppBoundDomains` array for all the
/// requests from the app, including requests for the `localhost` domain.
///
/// In theory, you can whitelist an entire uri scheme by including the
/// protocol name followed by a colon. For example, to allow all requests
/// using a custom "stream" uri scheme (see [this tauri
/// example](https://github.com/tauri-apps/tauri/blob/dev/examples/streaming/main.rs)),
/// you could add `stream:` to the AppBoundDomains array. That said, I'm not
/// sure whether Apple would let your app through app review if you do
/// whitelist an entire protocol because this feature is not mentioned in
/// [their blog post on App-Bound
/// Domains](https://webkit.org/blog/10882/app-bound-domains/).
///
/// See https://webkit.org/blog/10882/app-bound-domains/ and
/// https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/limitsnavigationstoappbounddomains
/// for the official documentation on App-Bound Domains.
///
/// ## Platform-specific
///
/// - **iOS**: Supported since version 14.0+.
/// - **Linux / Windows / Android / MacOS:** Unsupported.
#[must_use]
#[allow(unused_variables, unused_mut)]
pub fn limit_navigations_to_app_bound_domains(mut self, limit_navigations: bool) -> Self {
#[cfg(target_os = "ios")]
{
self.limit_navigations_to_app_bound_domains = limit_navigations;
}
self
}
/// Change the default background throttling behavior.
///
/// By default, browsers use a suspend policy that will throttle timers and even unload
/// the whole tab (view) to free resources after roughly 5 minutes when a view became
/// minimized or hidden. This will pause all tasks until the documents visibility state
/// changes back from hidden to visible by bringing the view back to the foreground.
///
/// ## Platform-specific
///
/// - **Linux / Windows / Android**: Unsupported. Workarounds like a pending WebLock transaction might suffice.
/// - **iOS**: Supported since version 17.0+.
/// - **macOS**: Supported since version 14.0+.
///
/// see <https://github.com/tauri-apps/tauri/issues/5250#issuecomment-2569380578>
#[must_use]
pub fn background_throttling(mut self, policy: Option<BackgroundThrottlingPolicy>) -> Self {
self.background_throttling = policy;
self
}
/// Specifies the native scrollbar style to use with the webview.
/// CSS styles that modify the scrollbar are applied on top of the native appearance configured here.
///
/// Defaults to [`ScrollBarStyle::Default`], which is the browser default.
///
/// ## Platform-specific
///
/// - **Windows**:
/// - [`ScrollBarStyle::FluentOverlay`] requires WebView2 Runtime version 125.0.2535.41 or higher,
/// and does nothing on older versions.
/// - This option must be given the same value for all webviews that target the same data directory. Use
/// [`WebviewAttributes::data_directory`] to change data directories if needed.
/// - **Linux / Android / iOS / macOS**: Unsupported. Only supports `Default` and performs no operation.
#[must_use]
pub fn scroll_bar_style(mut self, style: ScrollBarStyle) -> Self {
self.scroll_bar_style = style;
self
}
/// Controls the WebView's browser-level general autofill behavior.
///
/// **This option does not disable password or credit card autofill.**
///
/// When set to `false`, the WebView will not automatically populate
/// general form fields using previously stored data such as addresses
/// or contact information.
///
/// By default, this is `true`.
///
/// ## Platform-specific
///
/// - **Windows**: Supported. WebView2's autofill feature (called
/// "Suggestions") may not honor `autocomplete="off"` on input
/// elements in some cases.
/// - **Linux / Android / iOS / macOS**: Unsupported and performs no
/// operation.
#[must_use]
pub fn general_autofill_enabled(mut self, enabled: bool) -> Self {
self.general_autofill_enabled = enabled;
self
}
}
/// IPC handler.
pub type WebviewIpcHandler<T, R> = Box<dyn Fn(DetachedWebview<T, R>, Request<String>) + Send>;
/// An initialization script
#[derive(Debug, Clone)]
pub struct InitializationScript {
/// The script to run
pub script: String,
/// Whether the script should be injected to main frame only
pub for_main_frame_only: bool,
}

View File

@@ -0,0 +1,161 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/// Permission types that can be requested by the webview.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum PermissionKind {
/// Microphone access permission.
Microphone,
/// Camera access permission.
Camera,
/// Geolocation access permission.
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION`.
/// - **Linux**: Supported via `GeolocationPermissionRequest`.
/// - **Android**: Supported via `WebChromeClient.onGeolocationPermissionsShowPrompt`.
/// - **macOS / iOS**: Not yet supported by platform backends.
Geolocation,
/// Notifications permission.
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS`.
/// - **Linux**: Supported via `NotificationPermissionRequest`.
/// - **macOS / Android / iOS**: Not yet supported by platform backends.
Notifications,
/// Clipboard read permission.
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
ClipboardRead,
/// Display capture permission (for getDisplayMedia).
DisplayCapture,
/// Midi access permission.
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_MIDI_SYSTEM_EXCLUSIVE_MESSAGES`.
/// - **Android**: Supported via `android.webkit.resource.MIDI_SYSEX`.
/// - **macOS / Linux / iOS**: Not yet supported by platform backends.
Midi,
/// Sensors (accelerometer, gyroscope, etc.) access permission.
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
Sensors,
/// Media key system access permission.
///
/// ## Platform-specific
///
/// - **Android**: Supported via `android.webkit.resource.PROTECTED_MEDIA_ID`.
/// - **Windows / macOS / Linux / iOS**: Not yet supported by platform backends.
MediaKeySystemAccess,
/// Local fonts access permission.
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_LOCAL_FONTS`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
LocalFonts,
/// Window management permission.
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_WINDOW_MANAGEMENT`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
WindowManagement,
/// Pointer lock permission.
///
/// ## Platform-specific
///
/// - **Linux**: Supported via `PointerLockPermissionRequest`.
/// - **Windows / macOS / Android / iOS**: Not yet supported by platform backends.
PointerLock,
/// Automatic downloads permission (multiple downloads without user interaction).
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_MULTIPLE_AUTOMATIC_DOWNLOADS`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
AutomaticDownloads,
/// File system access permission (read/write via File System Access API).
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_FILE_READ_WRITE`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
FileSystemAccess,
/// Media autoplay permission.
///
/// ## Platform-specific
///
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_AUTOPLAY`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
Autoplay,
/// Other unrecognized permission type.
Other,
}
impl std::fmt::Display for PermissionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Microphone => write!(f, "microphone"),
Self::Camera => write!(f, "camera"),
Self::Geolocation => write!(f, "geolocation"),
Self::Notifications => write!(f, "notifications"),
Self::ClipboardRead => write!(f, "clipboard-read"),
Self::DisplayCapture => write!(f, "display-capture"),
Self::Midi => write!(f, "midi"),
Self::Sensors => write!(f, "sensors"),
Self::MediaKeySystemAccess => write!(f, "media-key-system-access"),
Self::LocalFonts => write!(f, "local-fonts"),
Self::WindowManagement => write!(f, "window-management"),
Self::PointerLock => write!(f, "pointer-lock"),
Self::AutomaticDownloads => write!(f, "automatic-downloads"),
Self::FileSystemAccess => write!(f, "file-system-access"),
Self::Autoplay => write!(f, "autoplay"),
Self::Other => write!(f, "other"),
}
}
}
/// Response for permission requests.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum PermissionResponse {
/// Grant the permission.
///
/// ## Platform-specific
///
/// - **Android**: Not supported for runtime permissions; the normal Android
/// permission flow is used instead.
Allow,
/// Deny the permission.
Deny,
/// Use the platform or browser default behavior.
///
/// ## Platform-specific
///
/// - **Windows / macOS / Android**: The default behavior is to continue the
/// platform or browser permission flow.
/// - **Linux**: The default behavior is [`Self::Deny`]
#[default]
Default,
}
impl std::fmt::Display for PermissionResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Allow => write!(f, "allow"),
Self::Deny => write!(f, "deny"),
Self::Default => write!(f, "default"),
}
}
}

View File

@@ -0,0 +1,670 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! A layer between raw [`Runtime`] windows and Tauri.
use crate::{
Icon, Runtime, UserEvent, WindowDispatch,
webview::{DetachedWebview, PendingWebview},
};
use dpi::PixelUnit;
use serde::{Deserialize, Deserializer, Serialize};
use tauri_utils::{
Theme,
config::{Color, WindowConfig},
};
#[cfg(windows)]
use windows::Win32::Foundation::HWND;
use std::{
hash::{Hash, Hasher},
marker::PhantomData,
path::PathBuf,
sync::mpsc::Sender,
};
/// An event from a window.
#[derive(Debug, Clone)]
pub enum WindowEvent {
/// The size of the window has changed. Contains the client area's new dimensions.
Resized(dpi::PhysicalSize<u32>),
/// The position of the window has changed. Contains the window's new position.
Moved(dpi::PhysicalPosition<i32>),
/// The window has been requested to close.
CloseRequested {
/// A signal sender. If a `true` value is emitted, the window won't be closed.
signal_tx: Sender<bool>,
},
/// The window has been destroyed.
Destroyed,
/// The window gained or lost focus.
///
/// The parameter is true if the window has gained focus, and false if it has lost focus.
Focused(bool),
/// The window's scale factor has changed.
///
/// The following user actions can cause DPI changes:
///
/// - Changing the display's resolution.
/// - Changing the display's scale factor (e.g. in Control Panel on Windows).
/// - Moving the window to a display with a different scale factor.
ScaleFactorChanged {
/// The new scale factor.
scale_factor: f64,
/// The window inner size.
new_inner_size: dpi::PhysicalSize<u32>,
},
/// An event associated with the drag and drop action.
DragDrop(DragDropEvent),
/// The system window theme has changed.
///
/// Applications might wish to react to this to change the theme of the content of the window when the system changes the window theme.
ThemeChanged(Theme),
/// Emitted when the application has been suspended.
///
/// ## Platform-specific
///
/// - **Android**: This is triggered by `onPause` method of the Activity.
/// - **iOS**: This is triggered by `applicationWillResignActive` method of the UIApplicationDelegate.
/// - **Linux / macOS / Windows**: Unsupported.
#[cfg(mobile)]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "android", target_os = "ios"))))]
Suspended,
/// Emitted when the application has been resumed.
///
/// ## Platform-specific
///
/// - **Android**: This is triggered by `onResume` method of the Activity. The first onResume() is ignored to match the iOS implementation, since that is called on activity creation.
/// - **iOS**: This is triggered by `applicationWillEnterForeground` method of the UIApplicationDelegate.
/// - **Linux / macOS / Windows**: Unsupported.
#[cfg(mobile)]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "android", target_os = "ios"))))]
Resumed,
}
/// An event from a window.
#[derive(Debug, Clone)]
pub enum WebviewEvent {
/// An event associated with the drag and drop action.
DragDrop(DragDropEvent),
}
/// The drag drop event payload.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum DragDropEvent {
/// A drag operation has entered the webview.
Enter {
/// List of paths that are being dragged onto the webview.
paths: Vec<PathBuf>,
/// The position of the mouse cursor.
position: dpi::PhysicalPosition<f64>,
},
/// A drag operation is moving over the webview.
Over {
/// The position of the mouse cursor.
position: dpi::PhysicalPosition<f64>,
},
/// The file(s) have been dropped onto the webview.
Drop {
/// List of paths that are being dropped onto the window.
paths: Vec<PathBuf>,
/// The position of the mouse cursor.
position: dpi::PhysicalPosition<f64>,
},
/// The drag operation has been cancelled or left the window.
Leave,
}
/// Describes the appearance of the mouse cursor.
#[non_exhaustive]
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
pub enum CursorIcon {
/// The platform-dependent default cursor.
#[default]
Default,
/// A simple crosshair.
Crosshair,
/// A hand (often used to indicate links in web browsers).
Hand,
/// Self explanatory.
Arrow,
/// Indicates something is to be moved.
Move,
/// Indicates text that may be selected or edited.
Text,
/// Program busy indicator.
Wait,
/// Help indicator (often rendered as a "?")
Help,
/// Progress indicator. Shows that processing is being done. But in contrast
/// with "Wait" the user may still interact with the program. Often rendered
/// as a spinning beach ball, or an arrow with a watch or hourglass.
Progress,
/// Cursor showing that something cannot be done.
NotAllowed,
ContextMenu,
Cell,
VerticalText,
Alias,
Copy,
NoDrop,
/// Indicates something can be grabbed.
Grab,
/// Indicates something is grabbed.
Grabbing,
AllScroll,
ZoomIn,
ZoomOut,
/// Indicate that some edge is to be moved. For example, the 'SeResize' cursor
/// is used when the movement starts from the south-east corner of the box.
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
}
impl<'de> Deserialize<'de> for CursorIcon {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(match s.to_lowercase().as_str() {
"default" => CursorIcon::Default,
"crosshair" => CursorIcon::Crosshair,
"hand" => CursorIcon::Hand,
"arrow" => CursorIcon::Arrow,
"move" => CursorIcon::Move,
"text" => CursorIcon::Text,
"wait" => CursorIcon::Wait,
"help" => CursorIcon::Help,
"progress" => CursorIcon::Progress,
"notallowed" => CursorIcon::NotAllowed,
"contextmenu" => CursorIcon::ContextMenu,
"cell" => CursorIcon::Cell,
"verticaltext" => CursorIcon::VerticalText,
"alias" => CursorIcon::Alias,
"copy" => CursorIcon::Copy,
"nodrop" => CursorIcon::NoDrop,
"grab" => CursorIcon::Grab,
"grabbing" => CursorIcon::Grabbing,
"allscroll" => CursorIcon::AllScroll,
"zoomin" => CursorIcon::ZoomIn,
"zoomout" => CursorIcon::ZoomOut,
"eresize" => CursorIcon::EResize,
"nresize" => CursorIcon::NResize,
"neresize" => CursorIcon::NeResize,
"nwresize" => CursorIcon::NwResize,
"sresize" => CursorIcon::SResize,
"seresize" => CursorIcon::SeResize,
"swresize" => CursorIcon::SwResize,
"wresize" => CursorIcon::WResize,
"ewresize" => CursorIcon::EwResize,
"nsresize" => CursorIcon::NsResize,
"neswresize" => CursorIcon::NeswResize,
"nwseresize" => CursorIcon::NwseResize,
"colresize" => CursorIcon::ColResize,
"rowresize" => CursorIcon::RowResize,
_ => CursorIcon::Default,
})
}
}
/// Window size constraints
#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WindowSizeConstraints {
/// The minimum width a window can be, If this is `None`, the window will have no minimum width.
///
/// The default is `None`.
pub min_width: Option<PixelUnit>,
/// The minimum height a window can be, If this is `None`, the window will have no minimum height.
///
/// The default is `None`.
pub min_height: Option<PixelUnit>,
/// The maximum width a window can be, If this is `None`, the window will have no maximum width.
///
/// The default is `None`.
pub max_width: Option<PixelUnit>,
/// The maximum height a window can be, If this is `None`, the window will have no maximum height.
///
/// The default is `None`.
pub max_height: Option<PixelUnit>,
}
/// Do **NOT** implement this trait except for use in a custom [`Runtime`]
///
/// This trait is separate from [`WindowBuilder`] to prevent "accidental" implementation.
pub trait WindowBuilderBase: std::fmt::Debug + Clone + Sized {}
/// A builder for all attributes related to a single window.
///
/// This trait is only meant to be implemented by a custom [`Runtime`]
/// and not by applications.
pub trait WindowBuilder: WindowBuilderBase {
/// Initializes a new window attributes builder.
fn new() -> Self;
/// Initializes a new window builder from a [`WindowConfig`]
fn with_config(config: &WindowConfig) -> Self;
/// Show window in the center of the screen.
#[must_use]
fn center(self) -> Self;
/// The initial position of the window in logical pixels.
#[must_use]
fn position(self, x: f64, y: f64) -> Self;
/// Window size in logical pixels.
#[must_use]
fn inner_size(self, width: f64, height: f64) -> Self;
/// Window min inner size in logical pixels.
#[must_use]
fn min_inner_size(self, min_width: f64, min_height: f64) -> Self;
/// Window max inner size in logical pixels.
#[must_use]
fn max_inner_size(self, max_width: f64, max_height: f64) -> Self;
/// Window inner size constraints.
#[must_use]
fn inner_size_constraints(self, constraints: WindowSizeConstraints) -> Self;
/// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) on creation
///
/// ## Platform-specific
///
/// - **iOS / Android:** Unsupported.
#[must_use]
fn prevent_overflow(self) -> Self;
/// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size)
/// on creation with a margin
///
/// ## Platform-specific
///
/// - **iOS / Android:** Unsupported.
#[must_use]
fn prevent_overflow_with_margin(self, margin: dpi::Size) -> Self;
/// Whether the window is resizable or not.
/// When resizable is set to false, native window's maximize button is automatically disabled.
#[must_use]
fn resizable(self, resizable: bool) -> Self;
/// Whether the window's native maximize button is enabled or not.
/// If resizable is set to false, this setting is ignored.
///
/// ## Platform-specific
///
/// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode.
/// - **Linux / iOS / Android:** Unsupported.
#[must_use]
fn maximizable(self, maximizable: bool) -> Self;
/// Whether the window's native minimize button is enabled or not.
///
/// ## Platform-specific
///
/// - **Linux / iOS / Android:** Unsupported.
#[must_use]
fn minimizable(self, minimizable: bool) -> Self;
/// Whether the window's native close button is enabled or not.
///
/// ## Platform-specific
///
/// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button.
/// Depending on the system, this function may not have any effect when called on a window that is already visible"
/// - **iOS / Android:** Unsupported.
#[must_use]
fn closable(self, closable: bool) -> Self;
/// The title of the window in the title bar.
#[must_use]
fn title<S: Into<String>>(self, title: S) -> Self;
/// Whether to start the window in fullscreen or not.
#[must_use]
fn fullscreen(self, fullscreen: bool) -> Self;
/// Whether the window will be initially focused or not.
#[must_use]
fn focused(self, focused: bool) -> Self;
/// Whether the window will be focusable or not.
#[must_use]
fn focusable(self, focusable: bool) -> Self;
/// Whether the window should be maximized upon creation.
#[must_use]
fn maximized(self, maximized: bool) -> Self;
/// Whether the window should be immediately visible upon creation.
#[must_use]
fn visible(self, visible: bool) -> Self;
/// Whether the window should be transparent. If this is true, writing colors
/// with alpha values different than `1.0` will produce a transparent window.
///
/// On Windows, using `no_redirection_bitmap` can help avoid a white flash when
/// creating a transparent window.
#[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
#[cfg_attr(
docsrs,
doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
)]
#[must_use]
fn transparent(self, transparent: bool) -> Self;
/// Whether the window should have borders and bars.
#[must_use]
fn decorations(self, decorations: bool) -> Self;
/// Whether the window should always be below other windows.
#[must_use]
fn always_on_bottom(self, always_on_bottom: bool) -> Self;
/// Whether the window should always be on top of other windows.
#[must_use]
fn always_on_top(self, always_on_top: bool) -> Self;
/// Whether the window should be visible on all workspaces or virtual desktops.
#[must_use]
fn visible_on_all_workspaces(self, visible_on_all_workspaces: bool) -> Self;
/// Prevents the window contents from being captured by other apps.
#[must_use]
fn content_protected(self, protected: bool) -> Self;
/// Sets the window icon.
fn icon(self, icon: Icon) -> crate::Result<Self>;
/// Sets whether or not the window icon should be added to the taskbar.
#[must_use]
fn skip_taskbar(self, skip: bool) -> Self;
/// Set the window background color.
#[must_use]
fn background_color(self, color: Color) -> Self;
/// Sets whether or not the window has shadow.
///
/// ## Platform-specific
///
/// - **Windows:**
/// - `false` has no effect on decorated window, shadows are always ON.
/// - `true` will make undecorated window have a 1px white border,
/// and on Windows 11, it will have a rounded corners.
/// - **Linux:** Unsupported.
#[must_use]
fn shadow(self, enable: bool) -> Self;
/// Set an owner to the window to be created.
///
/// From MSDN:
/// - An owned window is always above its owner in the z-order.
/// - The system automatically destroys an owned window when its owner is destroyed.
/// - An owned window is hidden when its owner is minimized.
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
#[cfg(windows)]
#[must_use]
fn owner(self, owner: HWND) -> Self;
/// Sets a parent to the window to be created.
///
/// A child window has the WS_CHILD style and is confined to the client area of its parent window.
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
#[cfg(windows)]
#[must_use]
fn parent(self, parent: HWND) -> Self;
/// Sets a parent to the window to be created.
///
/// See <https://developer.apple.com/documentation/appkit/nswindow/1419152-addchildwindow?language=objc>
#[cfg(target_os = "macos")]
#[must_use]
fn parent(self, parent: *mut std::ffi::c_void) -> Self;
/// Sets the window to be created transient for parent.
///
/// See <https://docs.gtk.org/gtk3/method.Window.set_transient_for.html>
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
fn transient_for(self, parent: &impl gtk::glib::IsA<gtk::Window>) -> Self;
/// Enables or disables drag and drop support.
#[cfg(windows)]
#[must_use]
fn drag_and_drop(self, enabled: bool) -> Self;
/// Hide the titlebar. Titlebar buttons will still be visible.
#[cfg(target_os = "macos")]
#[must_use]
fn title_bar_style(self, style: tauri_utils::TitleBarStyle) -> Self;
/// Change the position of the window controls on macOS.
///
/// Requires titleBarStyle: Overlay and decorations: true.
#[cfg(target_os = "macos")]
#[must_use]
fn traffic_light_position<P: Into<dpi::Position>>(self, position: P) -> Self;
/// Hide the window title.
#[cfg(target_os = "macos")]
#[must_use]
fn hidden_title(self, hidden: bool) -> Self;
/// Defines the window [tabbing identifier] for macOS.
///
/// Windows with matching tabbing identifiers will be grouped together.
/// If the tabbing identifier is not set, automatic tabbing will be disabled.
///
/// [tabbing identifier]: <https://developer.apple.com/documentation/appkit/nswindow/1644704-tabbingidentifier>
#[cfg(target_os = "macos")]
#[must_use]
fn tabbing_identifier(self, identifier: &str) -> Self;
/// Forces a theme or uses the system settings if None was provided.
fn theme(self, theme: Option<Theme>) -> Self;
/// Whether the icon was set or not.
fn has_icon(&self) -> bool;
fn get_theme(&self) -> Option<Theme>;
/// Sets custom name for Windows' window class. **Windows only**.
#[must_use]
fn window_classname<S: Into<String>>(self, window_classname: S) -> Self;
/// This sets `WS_EX_NOREDIRECTIONBITMAP`.
///
/// This can avoid the white flash that may appear before the webview content is rendered
/// when using a transparent window. **Windows only**.
#[must_use]
fn no_redirection_bitmap(self, enable: bool) -> Self;
/// The name of the activity to create for this webview window.
#[cfg(target_os = "android")]
fn activity_name<S: Into<String>>(self, class_name: S) -> Self;
/// Sets the name of the activity that is creating this webview window.
///
/// This is important to determine which stack the activity will belong to.
#[cfg(target_os = "android")]
fn created_by_activity_name<S: Into<String>>(self, class_name: S) -> Self;
/// Sets the identifier of the UIScene that is requesting the creation of this new scene,
/// establishing a relationship between the two scenes.
///
/// By default the system uses the foreground scene.
#[cfg(target_os = "ios")]
fn requested_by_scene_identifier<S: Into<String>>(self, identifier: S) -> Self;
}
/// A window that has yet to be built.
pub struct PendingWindow<T: UserEvent, R: Runtime<T>> {
/// The label that the window will be named.
pub label: String,
/// The [`WindowBuilder`] that the window will be created with.
pub window_builder: <R::WindowDispatcher as WindowDispatch<T>>::WindowBuilder,
/// The webview that gets added to the window. Optional in case you want to use child webviews or other window content instead.
pub webview: Option<PendingWebview<T, R>>,
}
pub fn is_label_valid(label: &str) -> bool {
label
.chars()
.all(|c| char::is_alphanumeric(c) || c == '-' || c == '/' || c == ':' || c == '_')
}
pub fn assert_label_is_valid(label: &str) {
assert!(
is_label_valid(label),
"Window label must include only alphanumeric characters, `-`, `/`, `:` and `_`."
);
}
impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
/// Create a new [`PendingWindow`] with a label from the given [`WindowBuilder`].
pub fn new(
window_builder: <R::WindowDispatcher as WindowDispatch<T>>::WindowBuilder,
label: impl Into<String>,
) -> crate::Result<Self> {
let label = label.into();
if !is_label_valid(&label) {
Err(crate::Error::InvalidWindowLabel)
} else {
Ok(Self {
window_builder,
label,
webview: None,
})
}
}
/// Sets a webview to be created on the window.
pub fn set_webview(&mut self, webview: PendingWebview<T, R>) -> &mut Self {
self.webview.replace(webview);
self
}
}
/// Identifier of a window.
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct WindowId(u32);
impl From<u32> for WindowId {
fn from(value: u32) -> Self {
Self(value)
}
}
/// A window that is not yet managed by Tauri.
#[derive(Debug)]
pub struct DetachedWindow<T: UserEvent, R: Runtime<T>> {
/// The identifier of the window.
pub id: WindowId,
/// Name of the window
pub label: String,
/// The [`WindowDispatch`] associated with the window.
pub dispatcher: R::WindowDispatcher,
/// The webview dispatcher in case this window has an attached webview.
pub webview: Option<DetachedWindowWebview<T, R>>,
}
/// A detached webview associated with a window.
#[derive(Debug)]
pub struct DetachedWindowWebview<T: UserEvent, R: Runtime<T>> {
pub webview: DetachedWebview<T, R>,
pub use_https_scheme: bool,
}
impl<T: UserEvent, R: Runtime<T>> Clone for DetachedWindowWebview<T, R> {
fn clone(&self) -> Self {
Self {
webview: self.webview.clone(),
use_https_scheme: self.use_https_scheme,
}
}
}
impl<T: UserEvent, R: Runtime<T>> Clone for DetachedWindow<T, R> {
fn clone(&self) -> Self {
Self {
id: self.id,
label: self.label.clone(),
dispatcher: self.dispatcher.clone(),
webview: self.webview.clone(),
}
}
}
impl<T: UserEvent, R: Runtime<T>> Hash for DetachedWindow<T, R> {
/// Only use the [`DetachedWindow`]'s label to represent its hash.
fn hash<H: Hasher>(&self, state: &mut H) {
self.label.hash(state)
}
}
impl<T: UserEvent, R: Runtime<T>> Eq for DetachedWindow<T, R> {}
impl<T: UserEvent, R: Runtime<T>> PartialEq for DetachedWindow<T, R> {
/// Only use the [`DetachedWindow`]'s label to compare equality.
fn eq(&self, other: &Self) -> bool {
self.label.eq(&other.label)
}
}
/// A raw window type that contains fields to access
/// the HWND on Windows, gtk::ApplicationWindow on Linux
pub struct RawWindow<'a> {
#[cfg(windows)]
pub hwnd: isize,
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
pub gtk_window: &'a gtk::ApplicationWindow,
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
pub default_vbox: Option<&'a gtk::Box>,
pub _marker: &'a PhantomData<()>,
}