/
githubmirror
/
tauri
Обзор
Документация
Войти
/
githubmirror
/
tauri
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
crates/tauri-runtime/src/window.rs
668 строк
21 KB
zetaloop
feat(core): add no_redirection_bitmap API on Windows (#15410)
03 июл 2026, 05:56
Не верифицирован
03 июл 2026, 05:56
2926555
Код
Авторство
О чём код?
// 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::{ webview::{DetachedWebview, PendingWebview}, Icon, Runtime, UserEvent, WindowDispatch, }; use dpi::PixelUnit; use serde::{Deserialize, Deserializer, Serialize}; use tauri_utils::{ config::{Color, WindowConfig}, Theme, }; #[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. /// /// 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<()>, }