(chore): update codebase

This commit is contained in:
Alois 2026-05-01 19:57:03 +02:00
commit 4e8d46b20e
106 changed files with 29936 additions and 1023 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
[package]
name = "tauri-runtime"
version = "2.11.0"
description = "Runtime for Tauri applications"
exclude = ["CHANGELOG.md", "/target"]
readme = "README.md"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
categories.workspace = true
license.workspace = true
edition.workspace = true
rust-version.workspace = true
[package.metadata.docs.rs]
all-features = true
default-target = "x86_64-unknown-linux-gnu"
targets = [
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
"x86_64-apple-darwin",
"x86_64-linux-android",
"x86_64-apple-ios",
]
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
tauri-utils = { version = "2.9.0", path = "../tauri-utils" }
http = "1"
raw-window-handle = "0.6"
url = { version = "2" }
dpi = { version = "0.1", features = ["serde"] }
# WARNING: cookie::Cookie is re-exported so bumping this is a breaking change, documented to be done as a minor bump
cookie = "0.18"
[target."cfg(windows)".dependencies.windows]
version = "0.61"
features = ["Win32_Foundation", "Win32_System_WinRT"]
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
gtk = { version = "0.18", features = ["v3_24"] }
[target."cfg(target_os = \"android\")".dependencies]
jni = "0.21"
[target.'cfg(all(target_vendor = "apple", not(target_os = "macos")))'.dependencies]
objc2 = "0.6"
objc2-ui-kit = { version = "0.3.0", default-features = false, features = [
"UIView",
"UIResponder",
"UIScene",
"UISceneOptions",
] }
[target."cfg(target_os = \"macos\")".dependencies]
url = "2"
objc2 = "0.6"
[features]
devtools = []
macos-private-api = []

View file

@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 - Present Tauri Apps Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,44 @@
# tauri-runtime
<img align="right" src="https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" height="128" width="128">
[![status](https://img.shields.io/badge/Status-Beta-green.svg)](https://github.com/tauri-apps/tauri)
[![Chat Server](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/SpmNs4S)
[![test core](https://img.shields.io/github/actions/workflow/status/tauri-apps/tauri/test-core.yml?label=test%20core&logo=github)](https://github.com/tauri-apps/tauri/actions/workflows/test-core.yml)
[![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app)
[![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)
[![support](https://img.shields.io/badge/sponsor-Opencollective-blue.svg)](https://opencollective.com/tauri)
| Component | Version |
| ------------- | -------------------------------------------------------------------------------------------------------------- |
| tauri-runtime | [![](https://img.shields.io/crates/v/tauri-runtime?style=flat-square)](https://crates.io/crates/tauri-runtime) |
## About Tauri
Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily.
Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task.
## This module
This is the glue layer between tauri itself and lower level webview libraries.
None of the exposed API of this crate is stable, and it may break semver
compatibility in the future. The major version only signifies the intended Tauri version.
To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document.
## Semver
**tauri** is following [Semantic Versioning 2.0](https://semver.org/).
## Licenses
Code: (c) 2021 - The Tauri Programme within The Commons Conservancy.
MIT or MIT/Apache 2.0 where applicable.
Logo: CC-BY-NC-ND
- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum)

View file

@ -0,0 +1,19 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
// creates a cfg alias if `has_feature` is true.
// `alias` must be a snake case string.
fn alias(alias: &str, has_feature: bool) {
println!("cargo:rustc-check-cfg=cfg({alias})");
if has_feature {
println!("cargo:rustc-cfg={alias}");
}
}
fn main() {
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
let mobile = target_os == "ios" || target_os == "android";
alias("desktop", !mobile);
alias("mobile", mobile);
}

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,820 @@
// 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.
//!
#[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,
};
pub type UriSchemeProtocolHandler = dyn Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
+ Send
+ Sync
+ 'static;
pub type WebResourceRequestHandler =
dyn Fn(http::Request<Vec<u8>>, &mut http::Response<Cow<'static, [u8]>>) + Send + Sync;
pub type NavigationHandler = dyn Fn(&Url) -> bool + Send;
pub type NewWindowHandler<T, R> =
dyn Fn(Url, NewWindowFeatures<T, R>) -> NewWindowResponse + Send + Sync;
pub type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send;
pub type DocumentTitleChangedHandler = dyn Fn(String) + Send + 'static;
pub type AddressChangedHandler = dyn Fn(&Url) + Send + Sync + 'static;
pub type DownloadHandler = dyn Fn(DownloadEvent) -> bool + 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,
}
/// Window features of a window requested to open.
#[derive(Debug)]
pub struct NewWindowFeatures<T: UserEvent, R: Runtime<T>> {
pub(crate) size: Option<crate::dpi::LogicalSize<f64>>,
pub(crate) position: Option<crate::dpi::LogicalPosition<f64>>,
pub(crate) opener: R::WindowOpener,
}
impl<T: UserEvent, R: Runtime<T>> NewWindowFeatures<T, R> {
pub fn new(
size: Option<crate::dpi::LogicalSize<f64>>,
position: Option<crate::dpi::LogicalPosition<f64>>,
opener: R::WindowOpener,
) -> 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) -> &R::WindowOpener {
&self.opener
}
/// Returns information about the webview that initiated a new window request.
pub fn into_opener(self) -> R::WindowOpener {
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.
///
/// The window must be created referencing the opener window so it can inherit the appropriate attributes.
#[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,
/// Information about the webview that initiated a new window request.
pub opener: Option<R::WindowOpener>,
/// Runtime specific attributes.
pub platform_specific_attributes: Vec<R::PlatformSpecificWebviewAttribute>,
/// 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<T, R>>>,
pub document_title_changed_handler: Option<Box<DocumentTitleChangedHandler>>,
pub address_changed_handler: Option<Box<AddressChangedHandler>>,
/// 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>>,
#[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,
platform_specific_attributes: Vec<R::PlatformSpecificWebviewAttribute>,
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,
opener: None,
platform_specific_attributes,
uri_scheme_protocols: Default::default(),
label,
ipc_handler: None,
navigation_handler: None,
new_window_handler: None,
document_title_changed_handler: None,
address_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,
#[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>,
}
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,
})
.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,
}
}
/// 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. This is required to use HTML5 drag and drop APIs on the frontend on Windows.
#[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
}
/// 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,661 @@
// 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)]
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)]
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.
#[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;
/// 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,
/// Whether devtools was enabled in [`crate::webview::WebviewAttributes`]. `Some(false)` disables the inspector.
pub devtools: Option<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,
devtools: self.devtools,
}
}
}
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<()>,
}