//! Native materials are applied on the UI thread. Unsupported systems stay //! opaque; stored preferences are retained for the user's next supported session. use crate::settings::BackgroundMaterial; use serde::Serialize; use tauri::WebviewWindow; #[derive(Clone, Debug, Serialize)] pub struct AppearanceStatus { pub requested_material: BackgroundMaterial, pub effective_material: BackgroundMaterial, pub opacity: u8, pub native_effect: bool, pub fallback_reason: Option, } pub fn apply( window: &WebviewWindow, material: BackgroundMaterial, opacity: u8, high_contrast: bool, ) -> AppearanceStatus { let mut status = AppearanceStatus { requested_material: material, effective_material: BackgroundMaterial::Solid, opacity, native_effect: false, fallback_reason: None, }; if high_contrast || material == BackgroundMaterial::Solid || opacity == 100 { #[cfg(windows)] { let _ = window_vibrancy::clear_acrylic(window); } if high_contrast { status.fallback_reason = Some("High contrast uses an opaque background.".into()); } return status; } #[cfg(windows)] { if !native_backdrop_available() { status.fallback_reason = Some("Glass requires Windows 11 22H2 or newer with desktop composition enabled and high contrast off. Using a solid background.".into()); return status; } let _ = window_vibrancy::clear_acrylic(window); // Keep the webview clear; the frontend draws a theme-aware readable tint. let result = window .set_background_color(Some(tauri::window::Color(0, 0, 0, 0))) .map_err(|error| error.to_string()) .and_then(|()| { match material { BackgroundMaterial::Glass => { window_vibrancy::apply_acrylic(window, Some((0, 0, 0, 0))) } BackgroundMaterial::Frosted => { window_vibrancy::apply_acrylic(window, Some((0, 0, 0, 0))) } BackgroundMaterial::Solid => unreachable!(), } .map_err(|error| error.to_string()) }); match result { Ok(()) => { status.effective_material = material; status.native_effect = true; } Err(_) => { status.fallback_reason = Some("Native transparency is unavailable. Using a solid background.".into()); } } } #[cfg(not(windows))] { let _ = window; status.fallback_reason = Some( if cfg!(target_os = "macos") { "Native glass is unavailable in this macOS build. Using a solid background." } else { "Native glass is unavailable on this desktop. Using a solid background." } .into(), ); } status } #[cfg(windows)] fn native_backdrop_available() -> bool { use windows_sys::Win32::UI::Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTW}; use windows_sys::Win32::{ Graphics::Dwm::DwmIsCompositionEnabled, UI::WindowsAndMessaging::{SystemParametersInfoW, SPI_GETHIGHCONTRAST}, }; let mut composition = 0; let mut contrast = HIGHCONTRASTW { cbSize: std::mem::size_of::() as u32, dwFlags: 0, lpszDefaultScheme: std::ptr::null_mut(), }; // Failure to query accessibility/composition is treated conservatively. unsafe { if DwmIsCompositionEnabled(&mut composition) < 0 || composition == 0 || SystemParametersInfoW( SPI_GETHIGHCONTRAST, contrast.cbSize, &mut contrast as *mut _ as *mut _, 0, ) == 0 || contrast.dwFlags & HCF_HIGHCONTRASTON != 0 { return false; } } // The established crate checks the HRESULT of the public backdrop API on // Windows 11 22H2+. Its older undocumented path cannot confirm success. let mut version = windows_sys::Win32::System::SystemInformation::OSVERSIONINFOW { dwOSVersionInfoSize: std::mem::size_of::< windows_sys::Win32::System::SystemInformation::OSVERSIONINFOW, >() as u32, ..unsafe { std::mem::zeroed() } }; unsafe { windows_sys::Wdk::System::SystemServices::RtlGetVersion(&mut version) >= 0 && version.dwBuildNumber >= 22621 } }