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}