@@ -29,13 +29,18 @@ const ACTIVITY_EVENTS = [
2929// Throttle activity detection to avoid excessive timer resets
3030const THROTTLE_MS = 1000 ;
3131
32+ // Grace period before locking on minimize/hide — prevents locking on brief
33+ // tab switches, notification clicks, or quick app toggles.
34+ const MINIMIZE_GRACE_MS = 30_000 ; // 30 seconds
35+
3236let _timer = null ;
3337let _lastActivity = Date . now ( ) ;
3438let _onLock = null ;
3539let _paused = false ;
3640let _started = false ;
3741let _throttleTimeout = null ;
3842let _visibilityHandler = null ;
43+ let _minimizeGraceTimer = null ;
3944let _tauriUnlisteners = [ ] ;
4045
4146/**
@@ -87,11 +92,29 @@ function start(onLock) {
8792 document . addEventListener ( event , onActivity , { passive : true , capture : true } ) ;
8893 }
8994
90- // Visibility change handler (lock on minimize)
95+ // Visibility change handler (lock on minimize with grace period )
9196 _visibilityHandler = ( ) => {
9297 const prefs = getLockPrefs ( ) ;
93- if ( prefs . lockOnMinimize && document . hidden && _onLock && ! _paused ) {
94- _onLock ( ) ;
98+ if ( ! prefs . lockOnMinimize || _paused ) return ;
99+
100+ if ( document . hidden ) {
101+ // Start grace period — don't lock immediately so brief tab switches
102+ // (checking a notification, switching apps momentarily) don't trigger it
103+ if ( ! _minimizeGraceTimer && _onLock ) {
104+ _minimizeGraceTimer = setTimeout ( ( ) => {
105+ _minimizeGraceTimer = null ;
106+ // Re-check: still hidden and not paused?
107+ if ( document . hidden && ! _paused && _started && _onLock ) {
108+ _onLock ( ) ;
109+ }
110+ } , MINIMIZE_GRACE_MS ) ;
111+ }
112+ } else {
113+ // User returned — cancel the grace timer
114+ if ( _minimizeGraceTimer ) {
115+ clearTimeout ( _minimizeGraceTimer ) ;
116+ _minimizeGraceTimer = null ;
117+ }
95118 }
96119 } ;
97120 document . addEventListener ( 'visibilitychange' , _visibilityHandler ) ;
@@ -112,12 +135,25 @@ async function setupTauriListeners() {
112135 const { getCurrentWindow } = await import ( '@tauri-apps/api/window' ) ;
113136 const appWindow = getCurrentWindow ( ) ;
114137
115- // Lock on window blur if lockOnMinimize is enabled
138+ // Lock on window blur if lockOnMinimize is enabled (with grace period)
116139 const unlistenBlur = await appWindow . onFocusChanged ( ( { payload : focused } ) => {
117- if ( ! focused && ! _paused && _started ) {
118- const prefs = getLockPrefs ( ) ;
119- if ( prefs . lockOnMinimize && _onLock ) {
120- _onLock ( ) ;
140+ if ( ! _started || _paused ) return ;
141+ const prefs = getLockPrefs ( ) ;
142+ if ( ! prefs . lockOnMinimize ) return ;
143+
144+ if ( ! focused ) {
145+ if ( ! _minimizeGraceTimer && _onLock ) {
146+ _minimizeGraceTimer = setTimeout ( ( ) => {
147+ _minimizeGraceTimer = null ;
148+ if ( ! _paused && _started && _onLock ) {
149+ _onLock ( ) ;
150+ }
151+ } , MINIMIZE_GRACE_MS ) ;
152+ }
153+ } else {
154+ if ( _minimizeGraceTimer ) {
155+ clearTimeout ( _minimizeGraceTimer ) ;
156+ _minimizeGraceTimer = null ;
121157 }
122158 }
123159 } ) ;
@@ -144,6 +180,11 @@ function stop() {
144180 _throttleTimeout = null ;
145181 }
146182
183+ if ( _minimizeGraceTimer ) {
184+ clearTimeout ( _minimizeGraceTimer ) ;
185+ _minimizeGraceTimer = null ;
186+ }
187+
147188 for ( const event of ACTIVITY_EVENTS ) {
148189 document . removeEventListener ( event , onActivity , { capture : true } ) ;
149190 }
@@ -175,6 +216,10 @@ function pause() {
175216 clearTimeout ( _timer ) ;
176217 _timer = null ;
177218 }
219+ if ( _minimizeGraceTimer ) {
220+ clearTimeout ( _minimizeGraceTimer ) ;
221+ _minimizeGraceTimer = null ;
222+ }
178223}
179224
180225/**
0 commit comments