99 * Software description: A modern desktop application that monitors security vulnerabilities across your GitHub repositories in real-time.
1010 */
1111
12- use tauri:: { PhysicalPosition , Manager , LogicalSize } ;
13- use std:: time:: Instant ;
14- use crate :: state:: AppState ;
12+ use tauri:: { PhysicalPosition , LogicalSize } ;
1513
1614// ============================================================================
1715// Window Management
@@ -51,125 +49,33 @@ pub fn position_window_near_tray(window: &tauri::WebviewWindow) {
5149 }
5250}
5351
54- pub fn handle_window_focus_lost ( window : & tauri:: Window ) {
55- let app = window. app_handle ( ) ;
56-
57- // Check if auto-hide is paused (for dropdown interactions)
58- let is_paused = if let Some ( state) = app. try_state :: < AppState > ( ) {
59- let auto_hide_paused = state. auto_hide_paused . lock ( ) . unwrap ( ) ;
60- * auto_hide_paused
61- } else {
62- false
63- } ;
64-
65- if is_paused {
66- println ! ( "[WINDOW] Auto-hide paused - ignoring focus loss" ) ;
67- return ;
68- }
69-
70- // On Linux, use a delayed hide approach to handle dropdown interactions
71- #[ cfg( target_os = "linux" ) ]
72- {
73- let should_hide = if let Some ( state) = app. try_state :: < AppState > ( ) {
74- let last_shown = state. last_shown . lock ( ) . unwrap ( ) ;
75- if let Some ( instant) = * last_shown {
76- instant. elapsed ( ) . as_millis ( ) > 1000 // 1 second minimum on Linux
77- } else {
78- true
79- }
80- } else {
81- true
82- } ;
83-
84- if should_hide {
85- let window_clone = window. clone ( ) ;
86- let app_clone = app. clone ( ) ;
87-
88- // Store the focus lost time
89- if let Some ( state) = app. try_state :: < AppState > ( ) {
90- let mut last_focus_lost = state. last_focus_lost . lock ( ) . unwrap ( ) ;
91- * last_focus_lost = Some ( Instant :: now ( ) ) ;
92- }
93-
94- std:: thread:: spawn ( move || {
95- std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 300 ) ) ; // Wait 300ms
96-
97- // Check if auto-hide is still not paused and focus wasn't regained
98- let should_still_hide = if let Some ( state) = app_clone. try_state :: < AppState > ( ) {
99- let auto_hide_paused = state. auto_hide_paused . lock ( ) . unwrap ( ) ;
100- if * auto_hide_paused {
101- return ; // Auto-hide was paused during the delay
102- }
103-
104- let last_focus_lost = state. last_focus_lost . lock ( ) . unwrap ( ) ;
105- if let Some ( focus_lost_time) = * last_focus_lost {
106- // If more than 300ms have passed since focus lost and focus wasn't regained, hide
107- focus_lost_time. elapsed ( ) . as_millis ( ) >= 300
108- } else {
109- false // Focus was regained
110- }
111- } else {
112- true
113- } ;
114-
115- if should_still_hide {
116- if let Ok ( is_focused) = window_clone. is_focused ( ) {
117- if !is_focused {
118- let _ = window_clone. hide ( ) ;
119- }
120- }
121- }
122- } ) ;
123- }
124- }
125-
126- // On other platforms, use the original logic
127- #[ cfg( not( target_os = "linux" ) ) ]
128- {
129- let should_hide = if let Some ( state) = app. try_state :: < AppState > ( ) {
130- let last_shown = state. last_shown . lock ( ) . unwrap ( ) ;
131- if let Some ( instant) = * last_shown {
132- instant. elapsed ( ) . as_millis ( ) > 500
133- } else {
134- true
135- }
136- } else {
137- true
138- } ;
139-
140- if should_hide {
141- let _ = window. hide ( ) ;
142- }
143- }
144- }
145-
146- pub fn handle_window_show ( app : & tauri:: AppHandle ) {
147- if let Some ( state) = app. try_state :: < AppState > ( ) {
148- let mut last_shown = state. last_shown . lock ( ) . unwrap ( ) ;
149- * last_shown = Some ( Instant :: now ( ) ) ;
150- }
151- }
152-
15352// ============================================================================
154- // Focus Management Commands (Linux dropdown fix)
53+ // macOS Window Configuration
15554// ============================================================================
15655
157- #[ tauri:: command]
158- pub fn pause_auto_hide ( app : tauri:: AppHandle ) -> Result < ( ) , String > {
159- if let Some ( state) = app. try_state :: < AppState > ( ) {
160- let mut auto_hide_paused = state. auto_hide_paused . lock ( ) . unwrap ( ) ;
161- * auto_hide_paused = true ;
162- println ! ( "[WINDOW] Auto-hide paused" ) ;
56+ /// Configure the window for macOS tray-app behavior:
57+ /// - Visible on all Spaces (never swept away by swipe gestures)
58+ /// - Does not auto-hide when the app loses focus
59+ #[ cfg( target_os = "macos" ) ]
60+ pub fn set_macos_window_level ( window : & tauri:: WebviewWindow ) {
61+ use objc2_app_kit:: NSWindow ;
62+
63+ // Visible on all Spaces via Tauri native API
64+ // (sets NSWindowCollectionBehaviorCanJoinAllSpaces under the hood)
65+ let _ = window. set_visible_on_all_workspaces ( true ) ;
66+
67+ // setHidesOnDeactivate is not exposed by Tauri — call via objc2-app-kit.
68+ // Prevents macOS from auto-hiding the window when the app loses focus.
69+ unsafe {
70+ let ns_window: & NSWindow = & * window
71+ . ns_window ( )
72+ . expect ( "Failed to get NSWindow handle" )
73+ . cast ( ) ;
74+ ns_window. setHidesOnDeactivate ( false ) ;
16375 }
164- Ok ( ( ) )
16576}
16677
167- #[ tauri:: command]
168- pub fn resume_auto_hide ( app : tauri:: AppHandle ) -> Result < ( ) , String > {
169- if let Some ( state) = app. try_state :: < AppState > ( ) {
170- let mut auto_hide_paused = state. auto_hide_paused . lock ( ) . unwrap ( ) ;
171- * auto_hide_paused = false ;
172- println ! ( "[WINDOW] Auto-hide resumed" ) ;
173- }
174- Ok ( ( ) )
175- }
78+ #[ cfg( not( target_os = "macos" ) ) ]
79+ pub fn set_macos_window_level ( _window : & tauri:: WebviewWindow ) {
80+ // No-op on non-macOS platforms
81+ }
0 commit comments