diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 43378ff..48df830 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -4,6 +4,8 @@ mod grid3; mod input; #[cfg(target_os = "macos")] mod macos; +#[cfg(target_os = "macos")] +mod macos_overlay_window; mod modifier_overlay; mod mouse_repeat; mod overlay; diff --git a/src-tauri/src/macos_overlay_window.rs b/src-tauri/src/macos_overlay_window.rs new file mode 100644 index 0000000..4563edb --- /dev/null +++ b/src-tauri/src/macos_overlay_window.rs @@ -0,0 +1,39 @@ +use objc2_app_kit::{ + NSScreenSaverWindowLevel, NSWindow, NSWindowCollectionBehavior, NSWindowLevel, +}; + +const OVERLAY_COLLECTION_BEHAVIOR: NSWindowCollectionBehavior = NSWindowCollectionBehavior( + NSWindowCollectionBehavior::CanJoinAllSpaces.0 + | NSWindowCollectionBehavior::Stationary.0 + | NSWindowCollectionBehavior::IgnoresCycle.0 + | NSWindowCollectionBehavior::FullScreenAuxiliary.0, +); + +pub(crate) fn configure(window: &NSWindow) { + window.setLevel(overlay_window_level()); + window.setHidesOnDeactivate(false); + window.setCollectionBehavior(OVERLAY_COLLECTION_BEHAVIOR); +} + +fn overlay_window_level() -> NSWindowLevel { + NSScreenSaverWindowLevel +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn overlays_use_the_screen_saver_window_level() { + assert_eq!(overlay_window_level(), NSScreenSaverWindowLevel); + } + + #[test] + fn overlay_collection_behavior_is_complete_and_exact() { + let expected = NSWindowCollectionBehavior::CanJoinAllSpaces + | NSWindowCollectionBehavior::Stationary + | NSWindowCollectionBehavior::IgnoresCycle + | NSWindowCollectionBehavior::FullScreenAuxiliary; + assert_eq!(OVERLAY_COLLECTION_BEHAVIOR, expected); + } +} diff --git a/src-tauri/src/modifier_overlay.rs b/src-tauri/src/modifier_overlay.rs index 51c4bf4..b90b77f 100644 --- a/src-tauri/src/modifier_overlay.rs +++ b/src-tauri/src/modifier_overlay.rs @@ -6,6 +6,8 @@ use tauri::{ }; use crate::input::ModifierKey; +#[cfg(target_os = "macos")] +use crate::macos_overlay_window; use crate::state::{emit_state, set_activity, ActivityKind, SharedModel}; const OVERLAY_WINDOW_LABEL: &str = "modifier-overlay"; @@ -65,6 +67,7 @@ impl ModifierOverlay { .visible(false) .build() .map_err(|error| error.to_string())?; + configure_platform_window(&window)?; window .set_ignore_cursor_events(true) .map_err(|error| error.to_string())?; @@ -184,6 +187,21 @@ impl ModifierOverlay { } } +#[cfg(target_os = "macos")] +fn configure_platform_window(window: &WebviewWindow) -> Result<(), String> { + window + .with_webview(|webview| unsafe { + let window: &objc2_app_kit::NSWindow = &*webview.ns_window().cast(); + macos_overlay_window::configure(window); + }) + .map_err(|error| error.to_string()) +} + +#[cfg(not(target_os = "macos"))] +fn configure_platform_window(_window: &WebviewWindow) -> Result<(), String> { + Ok(()) +} + impl ModifierKeyOverlayNotifier for ModifierOverlay { fn set_active_modifiers(&self, active_modifiers: &[ModifierKey]) { self.update(active_modifiers); diff --git a/src-tauri/src/overlay_macos.rs b/src-tauri/src/overlay_macos.rs index e670a8d..93f601b 100644 --- a/src-tauri/src/overlay_macos.rs +++ b/src-tauri/src/overlay_macos.rs @@ -7,12 +7,12 @@ use objc2::rc::Retained; use objc2::{AnyThread, MainThreadMarker, MainThreadOnly}; use objc2_app_kit::{ NSBackingStoreType, NSBitmapFormat, NSBitmapImageRep, NSCalibratedRGBColorSpace, NSColor, - NSEvent, NSImage, NSImageRep, NSImageView, NSPanel, NSScreen, NSStatusWindowLevel, - NSWindowCollectionBehavior, NSWindowStyleMask, + NSEvent, NSImage, NSImageRep, NSImageView, NSPanel, NSScreen, NSWindowStyleMask, }; use objc2_foundation::{NSArray, NSPoint, NSRect, NSSize}; use tauri::AppHandle; +use crate::macos_overlay_window; use crate::overlay::{render_marker, run_loop, Command, Frame}; use crate::state::{emit_state, set_activity, ActivityKind, SharedModel}; @@ -195,12 +195,7 @@ fn make_panel(mtm: MainThreadMarker) -> Retained { panel.setBackgroundColor(Some(&NSColor::clearColor())); panel.setHasShadow(false); panel.setIgnoresMouseEvents(true); - panel.setLevel(NSStatusWindowLevel); - panel.setCollectionBehavior( - NSWindowCollectionBehavior::CanJoinAllSpaces - | NSWindowCollectionBehavior::FullScreenAuxiliary - | NSWindowCollectionBehavior::IgnoresCycle, - ); + macos_overlay_window::configure(&panel); panel }