@@ -32,7 +32,11 @@ use super::tray::start_system_tray;
3232use super :: types:: TrayStatusShared ;
3333use super :: types:: { AlreadyRunningError , BackendRunner , OverlayState } ;
3434
35- const VISIBILITY_TOGGLE_DEBOUNCE : Duration = Duration :: from_millis ( 700 ) ;
35+ // Some desktop custom shortcut runners, observed on KDE, can launch the same
36+ // plain `--daemon-toggle` command twice about 400-600ms apart from one key press.
37+ // Suppress only duplicate plain toggles after a successful toggle completes, so
38+ // typed requests still run.
39+ const DUPLICATE_SHORTCUT_SUPPRESSION_WINDOW : Duration = Duration :: from_millis ( 700 ) ;
3640
3741pub struct Daemon {
3842 pub ( super ) overlay_state : OverlayState ,
@@ -58,7 +62,7 @@ pub struct Daemon {
5862 pub ( super ) overlay_spawn_failures : u32 ,
5963 pub ( super ) overlay_spawn_next_retry : Option < std:: time:: Instant > ,
6064 pub ( super ) overlay_spawn_backoff_logged : bool ,
61- pub ( super ) last_visibility_toggle_at : Option < Instant > ,
65+ pub ( super ) last_plain_visibility_toggle_completed_at : Option < Instant > ,
6266 #[ cfg( feature = "tray" ) ]
6367 pub ( super ) tray_status : Arc < TrayStatusShared > ,
6468}
@@ -97,7 +101,7 @@ impl Daemon {
97101 overlay_spawn_failures : 0 ,
98102 overlay_spawn_next_retry : None ,
99103 overlay_spawn_backoff_logged : false ,
100- last_visibility_toggle_at : None ,
104+ last_plain_visibility_toggle_completed_at : None ,
101105 #[ cfg( feature = "tray" ) ]
102106 tray_status : Arc :: new ( TrayStatusShared :: new ( ) ) ,
103107 }
@@ -133,7 +137,7 @@ impl Daemon {
133137 overlay_spawn_failures : 0 ,
134138 overlay_spawn_next_retry : None ,
135139 overlay_spawn_backoff_logged : false ,
136- last_visibility_toggle_at : None ,
140+ last_plain_visibility_toggle_completed_at : None ,
137141 #[ cfg( feature = "tray" ) ]
138142 tray_status : Arc :: new ( TrayStatusShared :: new ( ) ) ,
139143 }
@@ -198,10 +202,13 @@ impl Daemon {
198202 request. as_ref ( ) . is_none_or ( DaemonToggleRequest :: is_empty) ;
199203 if plain_visibility_toggle_requested {
200204 let now = Instant :: now ( ) ;
201- if self . last_visibility_toggle_at . is_some_and ( |previous| {
202- now. saturating_duration_since ( previous) < VISIBILITY_TOGGLE_DEBOUNCE
203- } ) {
204- info ! ( "Ignoring duplicate daemon visibility toggle" ) ;
205+ if self
206+ . last_plain_visibility_toggle_completed_at
207+ . is_some_and ( |previous| {
208+ now. saturating_duration_since ( previous) < DUPLICATE_SHORTCUT_SUPPRESSION_WINDOW
209+ } )
210+ {
211+ info ! ( "Ignoring duplicate plain daemon visibility toggle" ) ;
205212 return Ok ( false ) ;
206213 }
207214 }
@@ -235,7 +242,7 @@ impl Daemon {
235242 return Err ( err) ;
236243 }
237244 if plain_visibility_toggle_requested {
238- self . last_visibility_toggle_at = Some ( Instant :: now ( ) ) ;
245+ self . last_plain_visibility_toggle_completed_at = Some ( Instant :: now ( ) ) ;
239246 }
240247 Ok ( false )
241248 }
@@ -795,7 +802,7 @@ mod tests {
795802 . process_single_toggle ( Some ( DaemonToggleRequest :: default ( ) ) , None , false )
796803 . unwrap ( ) ;
797804 assert ! (
798- hide_started. elapsed( ) >= VISIBILITY_TOGGLE_DEBOUNCE ,
805+ hide_started. elapsed( ) >= DUPLICATE_SHORTCUT_SUPPRESSION_WINDOW ,
799806 "test setup should keep hide slow enough to cross the debounce window"
800807 ) ;
801808 assert_eq ! ( daemon. test_state( ) , OverlayState :: Hidden ) ;
@@ -828,8 +835,8 @@ mod tests {
828835 daemon
829836 . process_single_toggle ( Some ( DaemonToggleRequest :: default ( ) ) , None , false )
830837 . unwrap ( ) ;
831- daemon. last_visibility_toggle_at =
832- Some ( Instant :: now ( ) - VISIBILITY_TOGGLE_DEBOUNCE - Duration :: from_millis ( 1 ) ) ;
838+ daemon. last_plain_visibility_toggle_completed_at =
839+ Some ( Instant :: now ( ) - DUPLICATE_SHORTCUT_SUPPRESSION_WINDOW - Duration :: from_millis ( 1 ) ) ;
833840 daemon
834841 . process_single_toggle ( Some ( DaemonToggleRequest :: default ( ) ) , None , false )
835842 . unwrap ( ) ;
0 commit comments