Build Lotus Chat Desktop / prepare (push) Successful in 10s
Build Lotus Chat Desktop / build-linux (push) Successful in 28m46s
Build Lotus Chat Desktop / build-arch (push) Successful in 14s
Build Lotus Chat Desktop / build-windows (push) Successful in 38m32s
Build Lotus Chat Desktop / update-manifest (push) Successful in 9s
Closing the window (OS close button or the custom title bar's ×) now goes through one handler: - in a call → always hide to the tray (a close must never drop a call); - saved "tray" → hide; "quit" → exit the app; - "ask" (the default until chosen) → emit `lotus-close-requested` so the web client shows the one-time dialog; if the page isn't listening yet, fall back to the tray. The choice lives in `close-behavior` in the app config dir; get_close_behavior / set_close_behavior / resolve_close_request back the dialog and the Settings select. Verified on Linux under Xvfb + openbox with real WM close requests (wmctrl -c): tray → hidden, still running; quit → exits; unset with no page listening → hidden; ask with the page listening → window stays, page receives the event; quit during a call → hidden, still running. Bump cinny (the dialog + Settings control). Closes #5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
86 lines
3.6 KiB
Rust
86 lines
3.6 KiB
Rust
//! P5-47 — TDS Custom Window Chrome (opt-in, runtime-reversible).
|
|
//!
|
|
//! When the user opts into custom window chrome, the web client renders its own
|
|
//! `<TitleBar/>` (folds/TDS styled) and we strip the OS-native window frame so
|
|
//! the two don't stack. This is entirely opt-in: the window is built with native
|
|
//! `decorations(true)` and only `set_custom_chrome(true)` makes it frameless, so
|
|
//! the safe default is the untouched native frame.
|
|
//!
|
|
//! Everything here goes through the cross-platform Tauri v2 window API (plus a
|
|
//! Windows-only `window_vibrancy` dance in `set_custom_chrome`, since Mica and a
|
|
//! frameless window can't coexist). Each command resolves the "main" window and
|
|
//! silently no-ops if it isn't present (e.g. during teardown); the `Result`s are
|
|
//! intentionally ignored since a failed chrome tweak should never surface as an
|
|
//! error to the user.
|
|
|
|
use tauri::{AppHandle, Manager};
|
|
|
|
/// Toggle the native window frame. `enabled` = custom chrome on, which means the
|
|
/// OS decorations must come **off** (`set_decorations(!enabled)`). Passing
|
|
/// `false` restores the native frame, making the feature fully reversible at
|
|
/// runtime without a restart.
|
|
#[tauri::command]
|
|
pub fn set_custom_chrome(app: AppHandle, enabled: bool) {
|
|
if let Some(window) = app.get_webview_window("main") {
|
|
// Windows: the Mica backdrop (applied at startup in lib.rs) and a
|
|
// frameless window are a known-bad combo — stripping WS_CAPTION under a
|
|
// system backdrop glitches the whole surface (black/blank window). Drop
|
|
// the backdrop before undecorating, and restore it together with the
|
|
// native frame when custom chrome turns off.
|
|
#[cfg(target_os = "windows")]
|
|
if enabled {
|
|
let _ = window_vibrancy::clear_mica(&window);
|
|
}
|
|
let _ = window.set_decorations(!enabled);
|
|
// Re-assert the DWM shadow so a frameless window keeps its drop shadow
|
|
// and resize borders on Windows (no-op / harmless elsewhere).
|
|
let _ = window.set_shadow(true);
|
|
#[cfg(target_os = "windows")]
|
|
if !enabled {
|
|
let _ = window_vibrancy::apply_mica(&window, Some(true));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Minimize the main window (custom titlebar min button).
|
|
#[tauri::command]
|
|
pub fn window_minimize(app: AppHandle) {
|
|
if let Some(window) = app.get_webview_window("main") {
|
|
let _ = window.minimize();
|
|
}
|
|
}
|
|
|
|
/// Toggle maximize/restore the main window (custom titlebar max button and
|
|
/// drag-region double-click).
|
|
#[tauri::command]
|
|
pub fn window_toggle_maximize(app: AppHandle) {
|
|
if let Some(window) = app.get_webview_window("main") {
|
|
if window.is_maximized().unwrap_or(false) {
|
|
let _ = window.unmaximize();
|
|
} else {
|
|
let _ = window.maximize();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Begin an OS-level window drag from the custom titlebar drag region. The web
|
|
/// side also marks the drag area with `data-tauri-drag-region`; this command is
|
|
/// the explicit fallback so behaviour is identical across platforms.
|
|
#[tauri::command]
|
|
pub fn window_start_drag(app: AppHandle) {
|
|
if let Some(window) = app.get_webview_window("main") {
|
|
let _ = window.start_dragging();
|
|
}
|
|
}
|
|
|
|
/// Close from the custom titlebar. Mirrors the app's close-to-tray behaviour
|
|
/// (see the `CloseRequested` handler in `lib.rs`): we `hide()` the window rather
|
|
/// than exiting, so the tray keeps the app running and the tray menu remains the
|
|
/// single explicit quit path.
|
|
#[tauri::command]
|
|
pub fn window_close(app: AppHandle) {
|
|
// Same rules as the OS close button (tray / quit / first-close dialog,
|
|
// cinny-desktop #5).
|
|
crate::handle_close_request(&app);
|
|
}
|