//! Windows system AppBar integration for the App side panel. use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicU32, Ordering}; use windows::{ core::{w, Error, Result}, Win32::{ Foundation::{HWND, LPARAM, LRESULT, RECT, WPARAM}, Graphics::Gdi::{ GetMonitorInfoW, MonitorFromWindow, MONITORINFO, MONITOR_DEFAULTTONEAREST, }, UI::{ Shell::{ DefSubclassProc, RemoveWindowSubclass, SHAppBarMessage, SetWindowSubclass, ABE_RIGHT, ABM_ACTIVATE, ABM_NEW, ABM_QUERYPOS, ABM_REMOVE, ABM_SETPOS, ABM_WINDOWPOSCHANGED, ABN_POSCHANGED, APPBARDATA, }, WindowsAndMessaging::{ GetWindowRect, RegisterWindowMessageW, SetWindowPos, SWP_NOACTIVATE, SWP_NOZORDER, WM_ACTIVATE, WM_WINDOWPOSCHANGED, }, }, }, }; const SUBCLASS_ID: usize = 0x5341_4142; // "SAAB" (SenlinAI AppBar) static CALLBACK_MESSAGE: AtomicU32 = AtomicU32::new(0); static REGISTERED_HWND: AtomicIsize = AtomicIsize::new(0); static LAYOUT_IN_PROGRESS: AtomicBool = AtomicBool::new(false); /// Registers the main App window as a right-edge AppBar. pub fn register(hwnd: HWND) -> Result<()> { if REGISTERED_HWND.load(Ordering::Acquire) != 0 { return Ok(()); } let callback_message = unsafe { RegisterWindowMessageW(w!("SenlinAI.App.AppBar.Callback")) }; if callback_message == 0 { return Err(Error::from_win32()); } unsafe { SetWindowSubclass(hwnd, Some(appbar_subclass_proc), SUBCLASS_ID, 0).ok()?; } let mut data = appbar_data(hwnd); data.uCallbackMessage = callback_message; if unsafe { SHAppBarMessage(ABM_NEW, &mut data) } == 0 { unsafe { let _ = RemoveWindowSubclass(hwnd, Some(appbar_subclass_proc), SUBCLASS_ID); } return Err(Error::from_win32()); } CALLBACK_MESSAGE.store(callback_message, Ordering::Release); REGISTERED_HWND.store(hwnd.0 as isize, Ordering::Release); if let Err(error) = layout(hwnd) { unregister(); return Err(error); } Ok(()) } /// Removes the AppBar reservation before the Tauri window is destroyed. pub fn unregister() { let raw_hwnd = REGISTERED_HWND.swap(0, Ordering::AcqRel); CALLBACK_MESSAGE.store(0, Ordering::Release); if raw_hwnd == 0 { return; } let hwnd = HWND(raw_hwnd as *mut _); let mut data = appbar_data(hwnd); unsafe { SHAppBarMessage(ABM_REMOVE, &mut data); let _ = RemoveWindowSubclass(hwnd, Some(appbar_subclass_proc), SUBCLASS_ID); } } unsafe extern "system" fn appbar_subclass_proc( hwnd: HWND, message: u32, wparam: WPARAM, lparam: LPARAM, _subclass_id: usize, _reference_data: usize, ) -> LRESULT { let callback_message = CALLBACK_MESSAGE.load(Ordering::Acquire); if message == callback_message && wparam.0 as u32 == ABN_POSCHANGED { let _ = layout(hwnd); } else if message == WM_ACTIVATE { let mut data = appbar_data(hwnd); SHAppBarMessage(ABM_ACTIVATE, &mut data); } else if message == WM_WINDOWPOSCHANGED { let mut data = appbar_data(hwnd); SHAppBarMessage(ABM_WINDOWPOSCHANGED, &mut data); if !LAYOUT_IN_PROGRESS.load(Ordering::Acquire) { let _ = layout(hwnd); } } DefSubclassProc(hwnd, message, wparam, lparam) } fn layout(hwnd: HWND) -> Result<()> { if LAYOUT_IN_PROGRESS.swap(true, Ordering::AcqRel) { return Ok(()); } let result = layout_inner(hwnd); LAYOUT_IN_PROGRESS.store(false, Ordering::Release); result } fn layout_inner(hwnd: HWND) -> Result<()> { let mut window_rect = RECT::default(); unsafe { GetWindowRect(hwnd, &mut window_rect)? }; let width = window_rect.right - window_rect.left; let monitor = unsafe { MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) }; let mut monitor_info = MONITORINFO { cbSize: std::mem::size_of::() as u32, ..Default::default() }; unsafe { GetMonitorInfoW(monitor, &mut monitor_info).ok()? }; let mut data = appbar_data(hwnd); data.uEdge = ABE_RIGHT; data.rc = monitor_info.rcMonitor; data.rc.left = data.rc.right - width; unsafe { SHAppBarMessage(ABM_QUERYPOS, &mut data); data.rc.left = data.rc.right - width; SHAppBarMessage(ABM_SETPOS, &mut data); SetWindowPos( hwnd, None, data.rc.left, data.rc.top, data.rc.right - data.rc.left, data.rc.bottom - data.rc.top, SWP_NOACTIVATE | SWP_NOZORDER, )?; } Ok(()) } fn appbar_data(hwnd: HWND) -> APPBARDATA { APPBARDATA { cbSize: std::mem::size_of::() as u32, hWnd: hwnd, ..Default::default() } }