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:
Amr Bashir 2023-05-23 21:29:46 +03:00 committed by GitHub
parent 7e5905ae1d
commit e0f0dce220
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1497 additions and 20 deletions

View File

@ -0,0 +1,5 @@
---
'api': minor
---
Added the `windowEffects` option when creating a window and `setWindowEffects` method to change it at runtime.

View File

@ -0,0 +1,5 @@
---
'tauri-utils': minor
---
Added the `window_effects` option to the window configuration.

View 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.

View File

@ -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",

View File

@ -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).

View File

@ -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
);
}
}

View File

@ -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))]

View File

@ -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());

View File

@ -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))?;
}
}
}

View File

@ -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")]

View 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,
}
}
}

View 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(())
}

View 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
}

View File

@ -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 {

View File

@ -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

View File

@ -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",