mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 13:37:09 +00:00
feat: add window effects api (#6442)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio> Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
parent
7e5905ae1d
commit
e0f0dce220
5
.changes/window-effects-api.md
Normal file
5
.changes/window-effects-api.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'api': minor
|
||||
---
|
||||
|
||||
Added the `windowEffects` option when creating a window and `setWindowEffects` method to change it at runtime.
|
||||
5
.changes/window-effects-config.md
Normal file
5
.changes/window-effects-config.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'tauri-utils': minor
|
||||
---
|
||||
|
||||
Added the `window_effects` option to the window configuration.
|
||||
7
.changes/window-effects.md
Normal file
7
.changes/window-effects.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
'tauri': minor
|
||||
'tauri-runtime-wry': minor
|
||||
'tauri-runtime': minor
|
||||
---
|
||||
|
||||
Added the `window_effects` option when creating a window and `Window::set_effects` to change it at runtime.
|
||||
@ -488,6 +488,17 @@
|
||||
"description": "Whether or not the window has shadow.\n\n## Platform-specific\n\n- **Windows:** - `false` has no effect on decorated window, shadow are always ON. - `true` will make ndecorated window have a 1px white border, and on Windows 11, it will have a rounded corners. - **Linux:** Unsupported.",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"windowEffects": {
|
||||
"description": "Window effects.\n\nRequires the window to be transparent.\n\n## Platform-specific:\n\n- **Windows**: If using decorations or shadows, you may want to try this workaround https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891 - **Linux**: Unsupported",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WindowEffectsConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@ -551,6 +562,271 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"WindowEffectsConfig": {
|
||||
"description": "The window effects configuration object",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"effects"
|
||||
],
|
||||
"properties": {
|
||||
"effects": {
|
||||
"description": "List of Window effects to apply to the Window. Conflicting effects will apply the first one and ignore the rest.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/WindowEffect"
|
||||
}
|
||||
},
|
||||
"state": {
|
||||
"description": "Window effect state **macOS Only**",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WindowEffectState"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"radius": {
|
||||
"description": "Window effect corner radius **macOS Only**",
|
||||
"type": [
|
||||
"number",
|
||||
"null"
|
||||
],
|
||||
"format": "double"
|
||||
},
|
||||
"color": {
|
||||
"description": "Window effect color. Affects [`WindowEffects::Blur`] and [`WindowEffects::Acrylic`] only on Windows 10 v1903+. Doesn't have any effect on Windows 7 or Windows 11.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Color"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"WindowEffect": {
|
||||
"description": "Platform-specific window effects",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "A default material appropriate for the view's effectiveAppearance. **macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"appearanceBased"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"light"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"dark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mediumLight"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ultraDark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.10+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"titlebar"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.10+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"selection"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.11+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"menu"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.11+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"popover"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.11+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"sidebar"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"headerView"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"sheet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"windowBackground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"hudWindow"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"fullScreenUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tooltip"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"contentBackground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"underWindowBackground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"underPageBackground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*Windows 11 Only**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "**Windows 7/10/11(22H1) Only**\n\n## Notes\n\nThis effect has bad performance when resizing/dragging the window on Windows 11 build 22621.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"blur"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "**Windows 10/11 Only**\n\n## Notes\n\nThis effect has bad performance when resizing/dragging the window on Windows 10 v1903+ and Windows 11 build 22000.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"acrylic"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"WindowEffectState": {
|
||||
"description": "Window effect state **macOS only**\n\n<https://developer.apple.com/documentation/appkit/nsvisualeffectview/state>",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Make window effect state follow the window's active state",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"followsWindowActiveState"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Make window effect state always active",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"active"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Make window effect state always inactive",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"inactive"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"Color": {
|
||||
"description": "a tuple struct of RGBA colors. Each value has minimum of 0 and maximum of 255.",
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
}
|
||||
],
|
||||
"maxItems": 4,
|
||||
"minItems": 4
|
||||
},
|
||||
"BundleConfig": {
|
||||
"description": "Configuration for tauri-bundler.\n\nSee more: https://tauri.app/v1/api/config#bundleconfig",
|
||||
"type": "object",
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::{menu::Menu, window::DetachedWindow, Icon};
|
||||
#[cfg(target_os = "macos")]
|
||||
use tauri_utils::TitleBarStyle;
|
||||
use tauri_utils::{
|
||||
config::{WindowConfig, WindowUrl},
|
||||
config::{WindowConfig, WindowEffectsConfig, WindowUrl},
|
||||
Theme,
|
||||
};
|
||||
|
||||
@ -29,6 +29,7 @@ pub struct WebviewAttributes {
|
||||
pub clipboard: bool,
|
||||
pub accept_first_mouse: bool,
|
||||
pub additional_browser_args: Option<String>,
|
||||
pub window_effects: Option<WindowEffectsConfig>,
|
||||
}
|
||||
|
||||
impl WebviewAttributes {
|
||||
@ -43,6 +44,7 @@ impl WebviewAttributes {
|
||||
clipboard: false,
|
||||
accept_first_mouse: false,
|
||||
additional_browser_args: None,
|
||||
window_effects: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,6 +99,13 @@ impl WebviewAttributes {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// Do **NOT** implement this trait except for use in a custom [`Runtime`](crate::Runtime).
|
||||
|
||||
@ -34,7 +34,7 @@ use std::{
|
||||
/// Items to help with parsing content into a [`Config`].
|
||||
pub mod parse;
|
||||
|
||||
use crate::TitleBarStyle;
|
||||
use crate::{TitleBarStyle, WindowEffect, WindowEffectState};
|
||||
|
||||
pub use self::parse::parse;
|
||||
|
||||
@ -747,6 +747,30 @@ pub struct BundleConfig {
|
||||
pub updater: UpdaterConfig,
|
||||
}
|
||||
|
||||
/// a tuple struct of RGBA colors. Each value has minimum of 0 and maximum of 255.
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize, Default)]
|
||||
#[cfg_attr(feature = "schema", derive(JsonSchema))]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
pub struct Color(pub u8, pub u8, pub u8, pub u8);
|
||||
|
||||
/// The window effects configuration object
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize, Default)]
|
||||
#[cfg_attr(feature = "schema", derive(JsonSchema))]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
pub struct WindowEffectsConfig {
|
||||
/// List of Window effects to apply to the Window.
|
||||
/// Conflicting effects will apply the first one and ignore the rest.
|
||||
pub effects: Vec<WindowEffect>,
|
||||
/// Window effect state **macOS Only**
|
||||
pub state: Option<WindowEffectState>,
|
||||
/// Window effect corner radius **macOS Only**
|
||||
pub radius: Option<f64>,
|
||||
/// Window effect color. Affects [`WindowEffects::Blur`] and [`WindowEffects::Acrylic`] only
|
||||
/// on Windows 10 v1903+. Doesn't have any effect on Windows 7 or Windows 11.
|
||||
pub color: Option<Color>,
|
||||
}
|
||||
|
||||
/// The window configuration object.
|
||||
///
|
||||
/// See more: https://tauri.app/v1/api/config#windowconfig
|
||||
@ -864,6 +888,16 @@ pub struct WindowConfig {
|
||||
/// - **Linux:** Unsupported.
|
||||
#[serde(default = "default_true")]
|
||||
pub shadow: bool,
|
||||
/// Window effects.
|
||||
///
|
||||
/// Requires the window to be transparent.
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Windows**: If using decorations or shadows, you may want to try this workaround https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891
|
||||
/// - **Linux**: Unsupported
|
||||
#[serde(default, alias = "window-effects")]
|
||||
pub window_effects: Option<WindowEffectsConfig>,
|
||||
}
|
||||
|
||||
impl Default for WindowConfig {
|
||||
@ -900,6 +934,7 @@ impl Default for WindowConfig {
|
||||
tabbing_identifier: None,
|
||||
additional_browser_args: None,
|
||||
shadow: true,
|
||||
window_effects: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1924,7 +1959,7 @@ mod build {
|
||||
::tauri::utils::config::$struct {
|
||||
$($field: #$field),+
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
@ -1956,6 +1991,23 @@ mod build {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Color {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Color(r, g, b, a) = self;
|
||||
tokens.append_all(quote! {::tauri::utils::Color(#r,#g,#b,#a)});
|
||||
}
|
||||
}
|
||||
impl ToTokens for WindowEffectsConfig {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let effects = vec_lit(self.effects.clone(), |d| d);
|
||||
let state = opt_lit(self.state.as_ref());
|
||||
let radius = opt_lit(self.radius.as_ref());
|
||||
let color = opt_lit(self.color.as_ref());
|
||||
|
||||
literal_struct!(tokens, WindowEffectsConfig, effects, state, radius, color)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for crate::TitleBarStyle {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let prefix = quote! { ::tauri::utils::TitleBarStyle };
|
||||
@ -1968,6 +2020,51 @@ mod build {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for crate::WindowEffect {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let prefix = quote! { ::tauri::utils::WindowEffect };
|
||||
|
||||
#[allow(deprecated)]
|
||||
tokens.append_all(match self {
|
||||
WindowEffect::AppearanceBased => quote! { #prefix::AppearanceBased},
|
||||
WindowEffect::Light => quote! { #prefix::Light},
|
||||
WindowEffect::Dark => quote! { #prefix::Dark},
|
||||
WindowEffect::MediumLight => quote! { #prefix::MediumLight},
|
||||
WindowEffect::UltraDark => quote! { #prefix::UltraDark},
|
||||
WindowEffect::Titlebar => quote! { #prefix::Titlebar},
|
||||
WindowEffect::Selection => quote! { #prefix::Selection},
|
||||
WindowEffect::Menu => quote! { #prefix::Menu},
|
||||
WindowEffect::Popover => quote! { #prefix::Popover},
|
||||
WindowEffect::Sidebar => quote! { #prefix::Sidebar},
|
||||
WindowEffect::HeaderView => quote! { #prefix::HeaderView},
|
||||
WindowEffect::Sheet => quote! { #prefix::Sheet},
|
||||
WindowEffect::WindowBackground => quote! { #prefix::WindowBackground},
|
||||
WindowEffect::HudWindow => quote! { #prefix::HudWindow},
|
||||
WindowEffect::FullScreenUI => quote! { #prefix::FullScreenUI},
|
||||
WindowEffect::Tooltip => quote! { #prefix::Tooltip},
|
||||
WindowEffect::ContentBackground => quote! { #prefix::ContentBackground},
|
||||
WindowEffect::UnderWindowBackground => quote! { #prefix::UnderWindowBackground},
|
||||
WindowEffect::UnderPageBackground => quote! { #prefix::UnderPageBackground},
|
||||
WindowEffect::Mica => quote! { #prefix::Mica},
|
||||
WindowEffect::Blur => quote! { #prefix::Blur},
|
||||
WindowEffect::Acrylic => quote! { #prefix::Acrylic},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for crate::WindowEffectState {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let prefix = quote! { ::tauri::utils::WindowEffectState };
|
||||
|
||||
#[allow(deprecated)]
|
||||
tokens.append_all(match self {
|
||||
WindowEffectState::Active => quote! { #prefix::Active},
|
||||
WindowEffectState::FollowsWindowActiveState => quote! { #prefix::FollowsWindowActiveState},
|
||||
WindowEffectState::Inactive => quote! { #prefix::Inactive},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for WindowConfig {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let label = str_lit(&self.label);
|
||||
@ -2001,6 +2098,7 @@ mod build {
|
||||
let tabbing_identifier = opt_str_lit(self.tabbing_identifier.as_ref());
|
||||
let additional_browser_args = opt_str_lit(self.additional_browser_args.as_ref());
|
||||
let shadow = self.shadow;
|
||||
let window_effects = opt_lit(self.window_effects.as_ref());
|
||||
|
||||
literal_struct!(
|
||||
tokens,
|
||||
@ -2035,7 +2133,8 @@ mod build {
|
||||
accept_first_mouse,
|
||||
tabbing_identifier,
|
||||
additional_browser_args,
|
||||
shadow
|
||||
shadow,
|
||||
window_effects
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
//! Tauri utility helpers
|
||||
#![warn(missing_docs, rust_2018_idioms)]
|
||||
#![allow(clippy::deprecated_semver)]
|
||||
|
||||
use std::{
|
||||
fmt::Display,
|
||||
@ -55,6 +56,95 @@ impl PackageInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
mod window_effects {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
/// Platform-specific window effects
|
||||
pub enum WindowEffect {
|
||||
/// A default material appropriate for the view's effectiveAppearance. **macOS 10.14-**
|
||||
#[deprecated(
|
||||
since = "macOS 10.14",
|
||||
note = "You should instead choose an appropriate semantic material."
|
||||
)]
|
||||
AppearanceBased,
|
||||
/// **macOS 10.14-**
|
||||
#[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
|
||||
Light,
|
||||
/// **macOS 10.14-**
|
||||
#[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
|
||||
Dark,
|
||||
/// **macOS 10.14-**
|
||||
#[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
|
||||
MediumLight,
|
||||
/// **macOS 10.14-**
|
||||
#[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
|
||||
UltraDark,
|
||||
/// **macOS 10.10+**
|
||||
Titlebar,
|
||||
/// **macOS 10.10+**
|
||||
Selection,
|
||||
/// **macOS 10.11+**
|
||||
Menu,
|
||||
/// **macOS 10.11+**
|
||||
Popover,
|
||||
/// **macOS 10.11+**
|
||||
Sidebar,
|
||||
/// **macOS 10.14+**
|
||||
HeaderView,
|
||||
/// **macOS 10.14+**
|
||||
Sheet,
|
||||
/// **macOS 10.14+**
|
||||
WindowBackground,
|
||||
/// **macOS 10.14+**
|
||||
HudWindow,
|
||||
/// **macOS 10.14+**
|
||||
FullScreenUI,
|
||||
/// **macOS 10.14+**
|
||||
Tooltip,
|
||||
/// **macOS 10.14+**
|
||||
ContentBackground,
|
||||
/// **macOS 10.14+**
|
||||
UnderWindowBackground,
|
||||
/// **macOS 10.14+**
|
||||
UnderPageBackground,
|
||||
/// **Windows 11 Only**
|
||||
Mica,
|
||||
/// **Windows 7/10/11(22H1) Only**
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// This effect has bad performance when resizing/dragging the window on Windows 11 build 22621.
|
||||
Blur,
|
||||
/// **Windows 10/11 Only**
|
||||
///
|
||||
/// ## Notes
|
||||
///
|
||||
/// This effect has bad performance when resizing/dragging the window on Windows 10 v1903+ and Windows 11 build 22000.
|
||||
Acrylic,
|
||||
}
|
||||
|
||||
/// Window effect state **macOS only**
|
||||
///
|
||||
/// <https://developer.apple.com/documentation/appkit/nsvisualeffectview/state>
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum WindowEffectState {
|
||||
/// Make window effect state follow the window's active state
|
||||
FollowsWindowActiveState,
|
||||
/// Make window effect state always active
|
||||
Active,
|
||||
/// Make window effect state always inactive
|
||||
Inactive,
|
||||
}
|
||||
}
|
||||
|
||||
pub use window_effects::{WindowEffect, WindowEffectState};
|
||||
|
||||
/// How the window title bar should be displayed on macOS.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||
|
||||
@ -204,7 +204,7 @@ pub fn resource_dir(package_info: &PackageInfo, env: &Env) -> crate::Result<Path
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub use windows_platform::{is_windows_7, windows_version};
|
||||
pub use windows_platform::{get_function_impl, is_windows_7, windows_version};
|
||||
|
||||
#[cfg(windows)]
|
||||
mod windows_platform {
|
||||
@ -235,9 +235,9 @@ mod windows_platform {
|
||||
string.as_ref().encode_wide().chain(once(0)).collect()
|
||||
}
|
||||
|
||||
// Helper function to dynamically load function pointer.
|
||||
// `library` and `function` must be zero-terminated.
|
||||
fn get_function_impl(library: &str, function: &str) -> Option<FARPROC> {
|
||||
/// Helper function to dynamically load function pointer.
|
||||
/// `library` and `function` must be null-terminated.
|
||||
pub fn get_function_impl(library: &str, function: &str) -> Option<FARPROC> {
|
||||
let library = encode_wide(library);
|
||||
assert_eq!(function.chars().last(), Some('\0'));
|
||||
let function = PCSTR::from_raw(function.as_ptr());
|
||||
|
||||
@ -1289,6 +1289,7 @@ impl<R: Runtime> Builder<R> {
|
||||
for config in manager.config().tauri.windows.clone() {
|
||||
let url = config.url.clone();
|
||||
let label = config.label.clone();
|
||||
let window_effects = config.window_effects.clone();
|
||||
|
||||
let mut webview_attributes =
|
||||
WebviewAttributes::new(url).accept_first_mouse(config.accept_first_mouse);
|
||||
@ -1301,6 +1302,9 @@ impl<R: Runtime> Builder<R> {
|
||||
if !config.file_drop_enabled {
|
||||
webview_attributes = webview_attributes.disable_file_drop_handler();
|
||||
}
|
||||
if let Some(effects) = window_effects {
|
||||
webview_attributes = webview_attributes.window_effects(effects);
|
||||
}
|
||||
|
||||
self.pending_windows.push(PendingWindow::with_config(
|
||||
config,
|
||||
@ -1430,13 +1434,18 @@ fn setup<R: Runtime>(app: &mut App<R>) -> crate::Result<()> {
|
||||
app
|
||||
.manager
|
||||
.prepare_window(app.handle.clone(), pending, &window_labels, None)?;
|
||||
let window_effects = pending.webview_attributes.window_effects.clone();
|
||||
let detached = if let RuntimeOrDispatch::RuntimeHandle(runtime) = app.handle().runtime() {
|
||||
runtime.create_window(pending)?
|
||||
} else {
|
||||
// the AppHandle's runtime is always RuntimeOrDispatch::RuntimeHandle
|
||||
unreachable!()
|
||||
};
|
||||
let _window = app.manager.attach_window(app.handle(), detached);
|
||||
let window = app.manager.attach_window(app.handle(), detached);
|
||||
|
||||
if let Some(effects) = window_effects {
|
||||
crate::vibrancy::set_window_effects(&window, Some(effects))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -76,6 +76,7 @@ mod hooks;
|
||||
mod manager;
|
||||
mod pattern;
|
||||
pub mod plugin;
|
||||
mod vibrancy;
|
||||
pub mod window;
|
||||
use tauri_runtime as runtime;
|
||||
#[cfg(target_os = "ios")]
|
||||
|
||||
300
core/tauri/src/vibrancy/macos.rs
Normal file
300
core/tauri/src/vibrancy/macos.rs
Normal file
@ -0,0 +1,300 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#![cfg(target_os = "macos")]
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::utils::config::WindowEffectsConfig;
|
||||
use crate::window::{Effect, EffectState};
|
||||
use cocoa::{
|
||||
appkit::{
|
||||
NSAppKitVersionNumber, NSAppKitVersionNumber10_10, NSAppKitVersionNumber10_11,
|
||||
NSAutoresizingMaskOptions, NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow,
|
||||
NSWindowOrderingMode,
|
||||
},
|
||||
base::{id, nil, BOOL},
|
||||
foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize},
|
||||
};
|
||||
use objc::{class, msg_send, sel, sel_impl};
|
||||
|
||||
pub fn apply_effects(window: id, effects: WindowEffectsConfig) {
|
||||
let WindowEffectsConfig {
|
||||
effects,
|
||||
radius,
|
||||
state,
|
||||
..
|
||||
} = effects;
|
||||
let mut appearance: NSVisualEffectMaterial = if let Some(effect) = effects.into_iter().find(|e| {
|
||||
matches!(
|
||||
e,
|
||||
Effect::AppearanceBased
|
||||
| Effect::Light
|
||||
| Effect::Dark
|
||||
| Effect::MediumLight
|
||||
| Effect::UltraDark
|
||||
| Effect::Titlebar
|
||||
| Effect::Selection
|
||||
| Effect::Menu
|
||||
| Effect::Popover
|
||||
| Effect::Sidebar
|
||||
| Effect::HeaderView
|
||||
| Effect::Sheet
|
||||
| Effect::WindowBackground
|
||||
| Effect::HudWindow
|
||||
| Effect::FullScreenUI
|
||||
| Effect::Tooltip
|
||||
| Effect::ContentBackground
|
||||
| Effect::UnderWindowBackground
|
||||
| Effect::UnderPageBackground
|
||||
)
|
||||
}) {
|
||||
effect.into()
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
if NSAppKitVersionNumber < NSAppKitVersionNumber10_10 {
|
||||
return;
|
||||
}
|
||||
|
||||
if !msg_send![class!(NSThread), isMainThread] {
|
||||
return;
|
||||
}
|
||||
|
||||
if appearance as u32 > 9 && NSAppKitVersionNumber < NSAppKitVersionNumber10_14 {
|
||||
appearance = NSVisualEffectMaterial::AppearanceBased;
|
||||
} else if appearance as u32 > 4 && NSAppKitVersionNumber < NSAppKitVersionNumber10_11 {
|
||||
appearance = NSVisualEffectMaterial::AppearanceBased;
|
||||
}
|
||||
|
||||
let ns_view: id = window.contentView();
|
||||
let bounds = NSView::bounds(ns_view);
|
||||
|
||||
let blurred_view = NSVisualEffectView::initWithFrame_(NSVisualEffectView::alloc(nil), bounds);
|
||||
blurred_view.autorelease();
|
||||
|
||||
blurred_view.setMaterial_(appearance);
|
||||
blurred_view.setCornerRadius_(radius.unwrap_or(0.0));
|
||||
blurred_view.setBlendingMode_(NSVisualEffectBlendingMode::BehindWindow);
|
||||
blurred_view.setState_(
|
||||
state
|
||||
.map(Into::into)
|
||||
.unwrap_or(NSVisualEffectState::FollowsWindowActiveState),
|
||||
);
|
||||
NSVisualEffectView::setAutoresizingMask_(
|
||||
blurred_view,
|
||||
NSViewWidthSizable | NSViewHeightSizable,
|
||||
);
|
||||
|
||||
let _: () = msg_send![ns_view, addSubview: blurred_view positioned: NSWindowOrderingMode::NSWindowBelow relativeTo: 0];
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const NSAppKitVersionNumber10_14: f64 = 1671.0;
|
||||
|
||||
// https://developer.apple.com/documentation/appkit/nsvisualeffectview/blendingmode
|
||||
#[allow(dead_code)]
|
||||
#[repr(u64)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum NSVisualEffectBlendingMode {
|
||||
BehindWindow = 0,
|
||||
WithinWindow = 1,
|
||||
}
|
||||
|
||||
// macos 10.10+
|
||||
// https://developer.apple.com/documentation/appkit/nsvisualeffectview
|
||||
#[allow(non_snake_case)]
|
||||
trait NSVisualEffectView: Sized {
|
||||
unsafe fn alloc(_: Self) -> id {
|
||||
msg_send![class!(NSVisualEffectView), alloc]
|
||||
}
|
||||
|
||||
unsafe fn init(self) -> id;
|
||||
unsafe fn initWithFrame_(self, frameRect: NSRect) -> id;
|
||||
unsafe fn bounds(self) -> NSRect;
|
||||
unsafe fn frame(self) -> NSRect;
|
||||
unsafe fn setFrameSize(self, frameSize: NSSize);
|
||||
unsafe fn setFrameOrigin(self, frameOrigin: NSPoint);
|
||||
|
||||
unsafe fn superview(self) -> id;
|
||||
unsafe fn removeFromSuperview(self);
|
||||
unsafe fn setAutoresizingMask_(self, autoresizingMask: NSAutoresizingMaskOptions);
|
||||
|
||||
// API_AVAILABLE(macos(10.12));
|
||||
unsafe fn isEmphasized(self) -> BOOL;
|
||||
// API_AVAILABLE(macos(10.12));
|
||||
unsafe fn setEmphasized_(self, emphasized: BOOL);
|
||||
|
||||
unsafe fn setMaterial_(self, material: NSVisualEffectMaterial);
|
||||
unsafe fn setCornerRadius_(self, radius: f64);
|
||||
unsafe fn setState_(self, state: NSVisualEffectState);
|
||||
unsafe fn setBlendingMode_(self, mode: NSVisualEffectBlendingMode);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl NSVisualEffectView for id {
|
||||
unsafe fn init(self) -> id {
|
||||
msg_send![self, init]
|
||||
}
|
||||
|
||||
unsafe fn initWithFrame_(self, frameRect: NSRect) -> id {
|
||||
msg_send![self, initWithFrame: frameRect]
|
||||
}
|
||||
|
||||
unsafe fn bounds(self) -> NSRect {
|
||||
msg_send![self, bounds]
|
||||
}
|
||||
|
||||
unsafe fn frame(self) -> NSRect {
|
||||
msg_send![self, frame]
|
||||
}
|
||||
|
||||
unsafe fn setFrameSize(self, frameSize: NSSize) {
|
||||
msg_send![self, setFrameSize: frameSize]
|
||||
}
|
||||
|
||||
unsafe fn setFrameOrigin(self, frameOrigin: NSPoint) {
|
||||
msg_send![self, setFrameOrigin: frameOrigin]
|
||||
}
|
||||
|
||||
unsafe fn superview(self) -> id {
|
||||
msg_send![self, superview]
|
||||
}
|
||||
|
||||
unsafe fn removeFromSuperview(self) {
|
||||
msg_send![self, removeFromSuperview]
|
||||
}
|
||||
|
||||
unsafe fn setAutoresizingMask_(self, autoresizingMask: NSAutoresizingMaskOptions) {
|
||||
msg_send![self, setAutoresizingMask: autoresizingMask]
|
||||
}
|
||||
|
||||
// API_AVAILABLE(macos(10.12));
|
||||
unsafe fn isEmphasized(self) -> BOOL {
|
||||
msg_send![self, isEmphasized]
|
||||
}
|
||||
|
||||
// API_AVAILABLE(macos(10.12));
|
||||
unsafe fn setEmphasized_(self, emphasized: BOOL) {
|
||||
msg_send![self, setEmphasized: emphasized]
|
||||
}
|
||||
|
||||
unsafe fn setMaterial_(self, material: NSVisualEffectMaterial) {
|
||||
msg_send![self, setMaterial: material]
|
||||
}
|
||||
|
||||
unsafe fn setCornerRadius_(self, radius: f64) {
|
||||
msg_send![self, setCornerRadius: radius]
|
||||
}
|
||||
|
||||
unsafe fn setState_(self, state: NSVisualEffectState) {
|
||||
msg_send![self, setState: state]
|
||||
}
|
||||
|
||||
unsafe fn setBlendingMode_(self, mode: NSVisualEffectBlendingMode) {
|
||||
msg_send![self, setBlendingMode: mode]
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://developer.apple.com/documentation/appkit/nsvisualeffectview/material>
|
||||
#[repr(u64)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum NSVisualEffectMaterial {
|
||||
#[deprecated(
|
||||
since = "macOS 10.14",
|
||||
note = "A default material appropriate for the view's effectiveAppearance. You should instead choose an appropriate semantic material."
|
||||
)]
|
||||
AppearanceBased = 0,
|
||||
#[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
|
||||
Light = 1,
|
||||
#[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
|
||||
Dark = 2,
|
||||
#[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
|
||||
MediumLight = 8,
|
||||
#[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
|
||||
UltraDark = 9,
|
||||
|
||||
/// macOS 10.10+
|
||||
Titlebar = 3,
|
||||
/// macOS 10.10+
|
||||
Selection = 4,
|
||||
|
||||
/// macOS 10.11+
|
||||
Menu = 5,
|
||||
/// macOS 10.11+
|
||||
Popover = 6,
|
||||
/// macOS 10.11+
|
||||
Sidebar = 7,
|
||||
|
||||
/// macOS 10.14+
|
||||
HeaderView = 10,
|
||||
/// macOS 10.14+
|
||||
Sheet = 11,
|
||||
/// macOS 10.14+
|
||||
WindowBackground = 12,
|
||||
/// macOS 10.14+
|
||||
HudWindow = 13,
|
||||
/// macOS 10.14+
|
||||
FullScreenUI = 15,
|
||||
/// macOS 10.14+
|
||||
Tooltip = 17,
|
||||
/// macOS 10.14+
|
||||
ContentBackground = 18,
|
||||
/// macOS 10.14+
|
||||
UnderWindowBackground = 21,
|
||||
/// macOS 10.14+
|
||||
UnderPageBackground = 22,
|
||||
}
|
||||
|
||||
/// <https://developer.apple.com/documentation/appkit/nsvisualeffectview/state>
|
||||
#[allow(dead_code)]
|
||||
#[repr(u64)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum NSVisualEffectState {
|
||||
/// Make window vibrancy state follow the window's active state
|
||||
FollowsWindowActiveState = 0,
|
||||
/// Make window vibrancy state always active
|
||||
Active = 1,
|
||||
/// Make window vibrancy state always inactive
|
||||
Inactive = 2,
|
||||
}
|
||||
|
||||
impl From<crate::window::Effect> for NSVisualEffectMaterial {
|
||||
fn from(value: crate::window::Effect) -> Self {
|
||||
match value {
|
||||
Effect::AppearanceBased => NSVisualEffectMaterial::AppearanceBased,
|
||||
Effect::Light => NSVisualEffectMaterial::Light,
|
||||
Effect::Dark => NSVisualEffectMaterial::Dark,
|
||||
Effect::MediumLight => NSVisualEffectMaterial::MediumLight,
|
||||
Effect::UltraDark => NSVisualEffectMaterial::UltraDark,
|
||||
Effect::Titlebar => NSVisualEffectMaterial::Titlebar,
|
||||
Effect::Selection => NSVisualEffectMaterial::Selection,
|
||||
Effect::Menu => NSVisualEffectMaterial::Menu,
|
||||
Effect::Popover => NSVisualEffectMaterial::Popover,
|
||||
Effect::Sidebar => NSVisualEffectMaterial::Sidebar,
|
||||
Effect::HeaderView => NSVisualEffectMaterial::HeaderView,
|
||||
Effect::Sheet => NSVisualEffectMaterial::Sheet,
|
||||
Effect::WindowBackground => NSVisualEffectMaterial::WindowBackground,
|
||||
Effect::HudWindow => NSVisualEffectMaterial::HudWindow,
|
||||
Effect::FullScreenUI => NSVisualEffectMaterial::FullScreenUI,
|
||||
Effect::Tooltip => NSVisualEffectMaterial::Tooltip,
|
||||
Effect::ContentBackground => NSVisualEffectMaterial::ContentBackground,
|
||||
Effect::UnderWindowBackground => NSVisualEffectMaterial::UnderWindowBackground,
|
||||
Effect::UnderPageBackground => NSVisualEffectMaterial::UnderPageBackground,
|
||||
Effect::Mica | Effect::Blur | Effect::Acrylic => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::window::EffectState> for NSVisualEffectState {
|
||||
fn from(value: crate::window::EffectState) -> Self {
|
||||
match value {
|
||||
EffectState::FollowsWindowActiveState => NSVisualEffectState::FollowsWindowActiveState,
|
||||
EffectState::Active => NSVisualEffectState::Active,
|
||||
EffectState::Inactive => NSVisualEffectState::Inactive,
|
||||
}
|
||||
}
|
||||
}
|
||||
39
core/tauri/src/vibrancy/mod.rs
Normal file
39
core/tauri/src/vibrancy/mod.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
use tauri_utils::config::WindowEffectsConfig;
|
||||
|
||||
use crate::{Runtime, Window};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos;
|
||||
#[cfg(windows)]
|
||||
mod windows;
|
||||
|
||||
pub fn set_window_effects<R: Runtime>(
|
||||
window: &Window<R>,
|
||||
effects: Option<WindowEffectsConfig>,
|
||||
) -> crate::Result<()> {
|
||||
if let Some(_effects) = effects {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let hwnd = window.hwnd()?;
|
||||
windows::apply_effects(hwnd, _effects);
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let ns_window = window.ns_window()?;
|
||||
macos::apply_effects(ns_window as _, _effects);
|
||||
}
|
||||
} else {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let hwnd = window.hwnd()?;
|
||||
windows::clear_effects(hwnd);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
249
core/tauri/src/vibrancy/windows.rs
Normal file
249
core/tauri/src/vibrancy/windows.rs
Normal file
@ -0,0 +1,249 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#![cfg(windows)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
use std::ffi::c_void;
|
||||
|
||||
use crate::utils::config::WindowEffectsConfig;
|
||||
use crate::window::{Color, Effect};
|
||||
use tauri_utils::platform::{get_function_impl, is_windows_7, windows_version};
|
||||
use windows::Win32::Graphics::Dwm::{DwmSetWindowAttribute, DWMWINDOWATTRIBUTE};
|
||||
use windows::Win32::{
|
||||
Foundation::{BOOL, HWND},
|
||||
Graphics::{
|
||||
Dwm::{DwmEnableBlurBehindWindow, DWM_BB_ENABLE, DWM_BLURBEHIND},
|
||||
Gdi::HRGN,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn apply_effects(window: HWND, effects: WindowEffectsConfig) {
|
||||
let WindowEffectsConfig { effects, color, .. } = effects;
|
||||
let effect = if let Some(effect) = effects
|
||||
.iter()
|
||||
.find(|e| matches!(e, Effect::Mica | Effect::Acrylic | Effect::Blur))
|
||||
{
|
||||
effect
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
match effect {
|
||||
Effect::Blur => apply_blur(window, color),
|
||||
Effect::Acrylic => apply_acrylic(window, color),
|
||||
Effect::Mica => apply_mica(window),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_effects(window: HWND) {
|
||||
clear_blur(window);
|
||||
clear_acrylic(window);
|
||||
clear_mica(window);
|
||||
}
|
||||
|
||||
pub fn apply_blur(hwnd: HWND, color: Option<Color>) {
|
||||
if is_windows_7() {
|
||||
let bb = DWM_BLURBEHIND {
|
||||
dwFlags: DWM_BB_ENABLE,
|
||||
fEnable: true.into(),
|
||||
hRgnBlur: HRGN::default(),
|
||||
fTransitionOnMaximized: false.into(),
|
||||
};
|
||||
let _ = unsafe { DwmEnableBlurBehindWindow(hwnd, &bb) };
|
||||
} else if is_swca_supported() {
|
||||
unsafe { SetWindowCompositionAttribute(hwnd, ACCENT_STATE::ACCENT_ENABLE_BLURBEHIND, color) };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_blur(hwnd: HWND) {
|
||||
if is_windows_7() {
|
||||
let bb = DWM_BLURBEHIND {
|
||||
dwFlags: DWM_BB_ENABLE,
|
||||
fEnable: false.into(),
|
||||
hRgnBlur: HRGN::default(),
|
||||
fTransitionOnMaximized: false.into(),
|
||||
};
|
||||
let _ = unsafe { DwmEnableBlurBehindWindow(hwnd, &bb) };
|
||||
} else if is_swca_supported() {
|
||||
unsafe { SetWindowCompositionAttribute(hwnd, ACCENT_STATE::ACCENT_DISABLED, None) };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_acrylic(hwnd: HWND, color: Option<Color>) {
|
||||
if is_backdroptype_supported() {
|
||||
unsafe {
|
||||
let _ = DwmSetWindowAttribute(
|
||||
hwnd,
|
||||
DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
&DWM_SYSTEMBACKDROP_TYPE::DWMSBT_TRANSIENTWINDOW as *const _ as _,
|
||||
4,
|
||||
);
|
||||
}
|
||||
} else if is_swca_supported() {
|
||||
unsafe {
|
||||
SetWindowCompositionAttribute(hwnd, ACCENT_STATE::ACCENT_ENABLE_ACRYLICBLURBEHIND, color);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_acrylic(hwnd: HWND) {
|
||||
if is_backdroptype_supported() {
|
||||
unsafe {
|
||||
let _ = DwmSetWindowAttribute(
|
||||
hwnd,
|
||||
DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
&DWM_SYSTEMBACKDROP_TYPE::DWMSBT_DISABLE as *const _ as _,
|
||||
4,
|
||||
);
|
||||
}
|
||||
} else if is_swca_supported() {
|
||||
unsafe { SetWindowCompositionAttribute(hwnd, ACCENT_STATE::ACCENT_DISABLED, None) };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_mica(hwnd: HWND) {
|
||||
if is_backdroptype_supported() {
|
||||
unsafe {
|
||||
let _ = DwmSetWindowAttribute(
|
||||
hwnd,
|
||||
DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
&DWM_SYSTEMBACKDROP_TYPE::DWMSBT_MAINWINDOW as *const _ as _,
|
||||
4,
|
||||
);
|
||||
}
|
||||
} else if is_undocumented_mica_supported() {
|
||||
let _ = unsafe { DwmSetWindowAttribute(hwnd, DWMWA_MICA_EFFECT, &1 as *const _ as _, 4) };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_mica(hwnd: HWND) {
|
||||
if is_backdroptype_supported() {
|
||||
unsafe {
|
||||
let _ = DwmSetWindowAttribute(
|
||||
hwnd,
|
||||
DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
&DWM_SYSTEMBACKDROP_TYPE::DWMSBT_DISABLE as *const _ as _,
|
||||
4,
|
||||
);
|
||||
}
|
||||
} else if is_undocumented_mica_supported() {
|
||||
let _ = unsafe { DwmSetWindowAttribute(hwnd, DWMWA_MICA_EFFECT, &0 as *const _ as _, 4) };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const DWMWA_MICA_EFFECT: DWMWINDOWATTRIBUTE = DWMWINDOWATTRIBUTE(1029i32);
|
||||
const DWMWA_SYSTEMBACKDROP_TYPE: DWMWINDOWATTRIBUTE = DWMWINDOWATTRIBUTE(38i32);
|
||||
|
||||
#[repr(C)]
|
||||
struct ACCENT_POLICY {
|
||||
AccentState: u32,
|
||||
AccentFlags: u32,
|
||||
GradientColor: u32,
|
||||
AnimationId: u32,
|
||||
}
|
||||
|
||||
type WINDOWCOMPOSITIONATTRIB = u32;
|
||||
|
||||
#[repr(C)]
|
||||
struct WINDOWCOMPOSITIONATTRIBDATA {
|
||||
Attrib: WINDOWCOMPOSITIONATTRIB,
|
||||
pvData: *mut c_void,
|
||||
cbData: usize,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[repr(C)]
|
||||
enum ACCENT_STATE {
|
||||
ACCENT_DISABLED = 0,
|
||||
ACCENT_ENABLE_BLURBEHIND = 3,
|
||||
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
|
||||
}
|
||||
|
||||
macro_rules! get_function {
|
||||
($lib:expr, $func:ident) => {
|
||||
get_function_impl(concat!($lib, '\0'), concat!(stringify!($func), '\0'))
|
||||
.map(|f| unsafe { std::mem::transmute::<windows::Win32::Foundation::FARPROC, $func>(f) })
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn SetWindowCompositionAttribute(
|
||||
hwnd: HWND,
|
||||
accent_state: ACCENT_STATE,
|
||||
color: Option<Color>,
|
||||
) {
|
||||
type SetWindowCompositionAttribute =
|
||||
unsafe extern "system" fn(HWND, *mut WINDOWCOMPOSITIONATTRIBDATA) -> BOOL;
|
||||
|
||||
if let Some(set_window_composition_attribute) =
|
||||
get_function!("user32.dll", SetWindowCompositionAttribute)
|
||||
{
|
||||
let mut color = color.unwrap_or_default();
|
||||
|
||||
let is_acrylic = accent_state == ACCENT_STATE::ACCENT_ENABLE_ACRYLICBLURBEHIND;
|
||||
if is_acrylic && color.3 == 0 {
|
||||
// acrylic doesn't like to have 0 alpha
|
||||
color.3 = 1;
|
||||
}
|
||||
|
||||
let mut policy = ACCENT_POLICY {
|
||||
AccentState: accent_state as _,
|
||||
AccentFlags: if is_acrylic { 0 } else { 2 },
|
||||
GradientColor: (color.0 as u32)
|
||||
| (color.1 as u32) << 8
|
||||
| (color.2 as u32) << 16
|
||||
| (color.3 as u32) << 24,
|
||||
AnimationId: 0,
|
||||
};
|
||||
|
||||
let mut data = WINDOWCOMPOSITIONATTRIBDATA {
|
||||
Attrib: 0x13,
|
||||
pvData: &mut policy as *mut _ as _,
|
||||
cbData: std::mem::size_of_val(&policy),
|
||||
};
|
||||
|
||||
set_window_composition_attribute(hwnd, &mut data as *mut _ as _);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[repr(C)]
|
||||
enum DWM_SYSTEMBACKDROP_TYPE {
|
||||
DWMSBT_DISABLE = 1, // None
|
||||
DWMSBT_MAINWINDOW = 2, // Mica
|
||||
DWMSBT_TRANSIENTWINDOW = 3, // Acrylic
|
||||
DWMSBT_TABBEDWINDOW = 4, // Tabbed
|
||||
}
|
||||
|
||||
fn is_swca_supported() -> bool {
|
||||
is_at_least_build(17763)
|
||||
}
|
||||
|
||||
fn is_undocumented_mica_supported() -> bool {
|
||||
is_at_least_build(22000)
|
||||
}
|
||||
|
||||
fn is_backdroptype_supported() -> bool {
|
||||
is_at_least_build(22523)
|
||||
}
|
||||
|
||||
fn is_at_least_build(build: u32) -> bool {
|
||||
let v = windows_version().unwrap_or_default();
|
||||
v.2 >= build
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
pub(crate) mod menu;
|
||||
|
||||
pub use menu::{MenuEvent, MenuHandle};
|
||||
pub use tauri_utils::{config::Color, WindowEffect as Effect, WindowEffectState as EffectState};
|
||||
use url::Url;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
@ -30,7 +31,7 @@ use crate::{
|
||||
},
|
||||
sealed::ManagerBase,
|
||||
sealed::RuntimeOrDispatch,
|
||||
utils::config::{WindowConfig, WindowUrl},
|
||||
utils::config::{WindowConfig, WindowEffectsConfig, WindowUrl},
|
||||
EventLoopMessage, Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager, PageLoadPayload,
|
||||
Runtime, Theme, WindowEvent,
|
||||
};
|
||||
@ -226,6 +227,10 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
let app_handle = manager.app_handle();
|
||||
let url = config.url.clone();
|
||||
let file_drop_enabled = config.file_drop_enabled;
|
||||
let mut webview_attributes = WebviewAttributes::new(url);
|
||||
if let Some(effects) = config.window_effects.clone() {
|
||||
webview_attributes = webview_attributes.window_effects(effects);
|
||||
}
|
||||
let mut builder = Self {
|
||||
manager: manager.manager().clone(),
|
||||
runtime,
|
||||
@ -234,7 +239,7 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
window_builder: <R::Dispatcher as Dispatch<EventLoopMessage>>::WindowBuilder::with_config(
|
||||
config,
|
||||
),
|
||||
webview_attributes: WebviewAttributes::new(url),
|
||||
webview_attributes,
|
||||
web_resource_request_handler: None,
|
||||
navigation_handler: None,
|
||||
};
|
||||
@ -333,7 +338,7 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
&labels,
|
||||
web_resource_request_handler,
|
||||
)?;
|
||||
|
||||
let window_effects = pending.webview_attributes.window_effects.clone();
|
||||
let window = match &mut self.runtime {
|
||||
RuntimeOrDispatch::Runtime(runtime) => runtime.create_window(pending),
|
||||
RuntimeOrDispatch::RuntimeHandle(handle) => handle.create_window(pending),
|
||||
@ -341,6 +346,9 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
}
|
||||
.map(|window| self.manager.attach_window(self.app_handle.clone(), window))?;
|
||||
|
||||
if let Some(effects) = window_effects {
|
||||
crate::vibrancy::set_window_effects(&window, Some(effects))?;
|
||||
}
|
||||
self.manager.eval_script_all(format!(
|
||||
"window.__TAURI_METADATA__.__windows = {window_labels_array}.map(function (label) {{ return {{ label: label }} }})",
|
||||
window_labels_array = serde_json::to_string(&self.manager.labels())?,
|
||||
@ -604,6 +612,19 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
self.webview_attributes.accept_first_mouse = accept;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets window effects.
|
||||
///
|
||||
/// Requires the window to be transparent.
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Windows**: If using decorations or shadows, you may want to try this workaround https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891
|
||||
/// - **Linux**: Unsupported
|
||||
pub fn effects(mut self, effects: WindowEffectsConfig) -> Self {
|
||||
self.webview_attributes = self.webview_attributes.window_effects(effects);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Webview attributes.
|
||||
@ -1301,6 +1322,42 @@ impl<R: Runtime> Window<R> {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Sets window effects, pass [`None`] to clear any effects applied if possible.
|
||||
///
|
||||
/// Requires the window to be transparent.
|
||||
///
|
||||
/// See [`EffectsBuilder`] for a convenient builder for [`WindowEffectsConfig`].
|
||||
///
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::{Manager, window::{Color, Effect, EffectState, EffectsBuilder}};
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let window = app.get_window("main").unwrap();
|
||||
/// window.set_effects(
|
||||
/// EffectsBuilder::new()
|
||||
/// .effect(Effect::Popover)
|
||||
/// .state(EffectState::Active)
|
||||
/// .radius(5.)
|
||||
/// .color(Color(0, 0, 0, 255))
|
||||
/// .build(),
|
||||
/// )?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Windows**: If using decorations or shadows, you may want to try this workaround https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891
|
||||
/// - **Linux**: Unsupported
|
||||
pub fn set_effects<E: Into<Option<WindowEffectsConfig>>>(&self, effects: E) -> crate::Result<()> {
|
||||
let effects = effects.into();
|
||||
let window = self.clone();
|
||||
self.run_on_main_thread(move || {
|
||||
let _ = crate::vibrancy::set_window_effects(&window, effects);
|
||||
})
|
||||
}
|
||||
|
||||
/// Determines if this window should always be on top of other windows.
|
||||
pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
|
||||
self
|
||||
@ -1898,6 +1955,61 @@ impl<R: Runtime> Window<R> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`WindowEffectsConfig`] object builder
|
||||
#[derive(Default)]
|
||||
pub struct EffectsBuilder(WindowEffectsConfig);
|
||||
impl EffectsBuilder {
|
||||
/// Create a new [`WindowEffectsConfig`] builder
|
||||
pub fn new() -> Self {
|
||||
Self(WindowEffectsConfig::default())
|
||||
}
|
||||
|
||||
/// Adds effect to the [`WindowEffectsConfig`] `effects` field
|
||||
pub fn effect(mut self, effect: Effect) -> Self {
|
||||
self.0.effects.push(effect);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds effects to the [`WindowEffectsConfig`] `effects` field
|
||||
pub fn effects<I: IntoIterator<Item = Effect>>(mut self, effects: I) -> Self {
|
||||
self.0.effects.extend(effects);
|
||||
self
|
||||
}
|
||||
|
||||
/// Clears the [`WindowEffectsConfig`] `effects` field
|
||||
pub fn clear_effects(mut self) -> Self {
|
||||
self.0.effects.clear();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets `state` field for the [`WindowEffectsConfig`] **macOS Only**
|
||||
pub fn state(mut self, state: EffectState) -> Self {
|
||||
self.0.state = Some(state);
|
||||
self
|
||||
}
|
||||
/// Sets `radius` field fo the [`WindowEffectsConfig`] **macOS Only**
|
||||
pub fn radius(mut self, radius: f64) -> Self {
|
||||
self.0.radius = Some(radius);
|
||||
self
|
||||
}
|
||||
/// Sets `color` field fo the [`WindowEffectsConfig`] **Windows Only**
|
||||
pub fn color(mut self, color: Color) -> Self {
|
||||
self.0.color = Some(color);
|
||||
self
|
||||
}
|
||||
|
||||
/// Builds a [`WindowEffectsConfig`]
|
||||
pub fn build(self) -> WindowEffectsConfig {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WindowEffectsConfig> for EffectsBuilder {
|
||||
fn from(value: WindowEffectsConfig) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const IPC_SCOPE_DOES_NOT_ALLOW: &str = "Not allowed by the scope";
|
||||
|
||||
pub(crate) fn ipc_scope_not_found_error_message(label: &str, url: &str) -> String {
|
||||
|
||||
14
examples/api/src-tauri/Cargo.lock
generated
14
examples/api/src-tauri/Cargo.lock
generated
@ -2967,7 +2967,7 @@ checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.0.0-alpha.8"
|
||||
version = "2.0.0-alpha.9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -3016,7 +3016,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.0.0-alpha.4"
|
||||
version = "2.0.0-alpha.5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
@ -3035,7 +3035,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.0.0-alpha.4"
|
||||
version = "2.0.0-alpha.5"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"brotli",
|
||||
@ -3059,7 +3059,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.0.0-alpha.4"
|
||||
version = "2.0.0-alpha.5"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@ -3115,7 +3115,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "0.13.0-alpha.4"
|
||||
version = "0.13.0-alpha.5"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
@ -3134,7 +3134,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "0.13.0-alpha.4"
|
||||
version = "0.13.0-alpha.5"
|
||||
dependencies = [
|
||||
"cocoa",
|
||||
"gtk",
|
||||
@ -3153,7 +3153,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.0.0-alpha.4"
|
||||
version = "2.0.0-alpha.5"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"brotli",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -488,6 +488,17 @@
|
||||
"description": "Whether or not the window has shadow.\n\n## Platform-specific\n\n- **Windows:** - `false` has no effect on decorated window, shadow are always ON. - `true` will make ndecorated window have a 1px white border, and on Windows 11, it will have a rounded corners. - **Linux:** Unsupported.",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"windowEffects": {
|
||||
"description": "Window effects.\n\nRequires the window to be transparent.\n\n## Platform-specific:\n\n- **Windows**: If using decorations or shadows, you may want to try this workaround https://github.com/tauri-apps/tao/issues/72#issuecomment-975607891 - **Linux**: Unsupported",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WindowEffectsConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@ -551,6 +562,271 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"WindowEffectsConfig": {
|
||||
"description": "The window effects configuration object",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"effects"
|
||||
],
|
||||
"properties": {
|
||||
"effects": {
|
||||
"description": "List of Window effects to apply to the Window. Conflicting effects will apply the first one and ignore the rest.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/WindowEffect"
|
||||
}
|
||||
},
|
||||
"state": {
|
||||
"description": "Window effect state **macOS Only**",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WindowEffectState"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"radius": {
|
||||
"description": "Window effect corner radius **macOS Only**",
|
||||
"type": [
|
||||
"number",
|
||||
"null"
|
||||
],
|
||||
"format": "double"
|
||||
},
|
||||
"color": {
|
||||
"description": "Window effect color. Affects [`WindowEffects::Blur`] and [`WindowEffects::Acrylic`] only on Windows 10 v1903+. Doesn't have any effect on Windows 7 or Windows 11.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Color"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"WindowEffect": {
|
||||
"description": "Platform-specific window effects",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "A default material appropriate for the view's effectiveAppearance. **macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"appearanceBased"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"light"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"dark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mediumLight"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14-**",
|
||||
"deprecated": true,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ultraDark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.10+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"titlebar"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.10+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"selection"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.11+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"menu"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.11+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"popover"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.11+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"sidebar"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"headerView"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"sheet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"windowBackground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"hudWindow"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"fullScreenUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tooltip"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"contentBackground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"underWindowBackground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*macOS 10.14+**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"underPageBackground"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "*Windows 11 Only**",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "**Windows 7/10/11(22H1) Only**\n\n## Notes\n\nThis effect has bad performance when resizing/dragging the window on Windows 11 build 22621.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"blur"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "**Windows 10/11 Only**\n\n## Notes\n\nThis effect has bad performance when resizing/dragging the window on Windows 10 v1903+ and Windows 11 build 22000.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"acrylic"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"WindowEffectState": {
|
||||
"description": "Window effect state **macOS only**\n\n<https://developer.apple.com/documentation/appkit/nsvisualeffectview/state>",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Make window effect state follow the window's active state",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"followsWindowActiveState"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Make window effect state always active",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"active"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Make window effect state always inactive",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"inactive"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"Color": {
|
||||
"description": "a tuple struct of RGBA colors. Each value has minimum of 0 and maximum of 255.",
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
}
|
||||
],
|
||||
"maxItems": 4,
|
||||
"minItems": 4
|
||||
},
|
||||
"BundleConfig": {
|
||||
"description": "Configuration for tauri-bundler.\n\nSee more: https://tauri.app/v1/api/config#bundleconfig",
|
||||
"type": "object",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user