tauri_plugin_liquid_glass/
lib.rs

1//! Tauri plugin for macOS 26+ Liquid Glass effect support
2//!
3//! This plugin provides native macOS Liquid Glass effects for Tauri applications.
4//! On macOS 26 (Tahoe) and later, it uses the private NSGlassEffectView API.
5//! On older macOS versions, it falls back to NSVisualEffectView.
6//!
7//! # Example
8//!
9//! ```rust,no_run
10//! use tauri_plugin_liquid_glass::LiquidGlassExt;
11//!
12//! tauri::Builder::default()
13//!     .plugin(tauri_plugin_liquid_glass::init())
14//!     .setup(|app| {
15//!         // Access the plugin API via extension trait
16//!         let supported = app.liquid_glass().is_supported();
17//!         println!("Liquid Glass supported: {}", supported);
18//!         Ok(())
19//!     })
20//!     .run(tauri::generate_context!())
21//!     .expect("error while running tauri application");
22//! ```
23
24// The cocoa/objc crates are deprecated in favor of objc2, but objc2 requires
25// significant architectural changes (MainThreadMarker, strict Send/Sync) without
26// functional benefit. These crates remain fully functional for our use case.
27#![allow(deprecated)]
28
29use tauri::{
30    plugin::{Builder, TauriPlugin},
31    Manager, Runtime,
32};
33
34mod commands;
35mod desktop;
36mod error;
37mod models;
38
39#[cfg(target_os = "macos")]
40mod glass_effect;
41
42pub use desktop::LiquidGlass;
43pub use error::{Error, Result};
44pub use models::*;
45
46// ============================================================================
47// Extension Trait
48// ============================================================================
49
50/// Extension trait for accessing the Liquid Glass plugin API
51///
52/// This trait is implemented for all types that implement [`Manager`],
53/// including [`AppHandle`](tauri::AppHandle), [`App`](tauri::App), and [`WebviewWindow`](tauri::WebviewWindow).
54///
55/// # Example
56///
57/// ```rust,no_run
58/// use tauri_plugin_liquid_glass::LiquidGlassExt;
59///
60/// fn example(app: tauri::AppHandle, window: tauri::WebviewWindow) {
61///     // Check if supported
62///     let supported = app.liquid_glass().is_supported();
63///
64///     // Apply effect
65///     app.liquid_glass().set_effect(&window, Default::default()).unwrap();
66/// }
67/// ```
68pub trait LiquidGlassExt<R: Runtime> {
69    /// Returns a handle to the Liquid Glass plugin API
70    fn liquid_glass(&self) -> &LiquidGlass<R>;
71}
72
73impl<R: Runtime, T: Manager<R>> LiquidGlassExt<R> for T {
74    fn liquid_glass(&self) -> &LiquidGlass<R> {
75        self.state::<LiquidGlass<R>>().inner()
76    }
77}
78
79// ============================================================================
80// Plugin Initialization
81// ============================================================================
82
83/// Initialize the liquid-glass plugin
84///
85/// # Example
86///
87/// ```rust,no_run
88/// use tauri_plugin_liquid_glass::LiquidGlassExt;
89///
90/// tauri::Builder::default()
91///     .plugin(tauri_plugin_liquid_glass::init())
92///     .setup(|app| {
93///         // Use the extension trait to access the API
94///         let supported = app.liquid_glass().is_supported();
95///         Ok(())
96///     })
97///     .run(tauri::generate_context!())
98///     .expect("error while running tauri application");
99/// ```
100pub fn init<R: Runtime>() -> TauriPlugin<R> {
101    Builder::new("liquid-glass")
102        .invoke_handler(tauri::generate_handler![
103            commands::is_glass_supported,
104            commands::set_liquid_glass_effect,
105        ])
106        .setup(|app, _api| {
107            // Manage the LiquidGlass struct for the extension trait
108            app.manage(LiquidGlass::new(app.clone()));
109
110            #[cfg(target_os = "macos")]
111            {
112                app.manage(glass_effect::GlassViewRegistry::default());
113            }
114            Ok(())
115        })
116        .build()
117}