@@ -99,6 +99,8 @@ let tray: Tray | undefined;
9999let isQuitting = false ;
100100let shutdownComplete = false ;
101101let shutdownPromise : Promise < void > | undefined ;
102+ let visibleUpdateCheckTimer : NodeJS . Timeout | undefined ;
103+ let lastVisibleUpdateCheckAt = 0 ;
102104const store = new AppStore ( ) ;
103105let migrationService : MigrationService ;
104106const aiVerifications = new Map < string , { fingerprint : string ; expiresAt : number } > ( ) ;
@@ -380,6 +382,7 @@ function createWindow(): BrowserWindow {
380382
381383 window . setMenuBarVisibility ( false ) ;
382384 trackWindowActivity ( window ) ;
385+ window . on ( "restore" , ( ) => triggerVisibleUpdateCheck ( "main-window-restored" ) ) ;
383386 trackWindowBounds ( window , "mainWindowBounds" ) ;
384387 window . on ( "close" , ( event ) => {
385388 if ( isQuitting || ! store . getSettings ( ) . minimizeToTray ) return ;
@@ -434,6 +437,36 @@ function emitUpdateState(state: AppUpdateInfo): void {
434437 }
435438}
436439
440+ function triggerVisibleUpdateCheck ( reason : string , delayMs = 0 ) : void {
441+ if ( ! updateService || isQuitting ) return ;
442+ const busyPhases = new Set ( [ "checking" , "downloading" , "verifying" , "ready" , "installing" ] ) ;
443+ if ( busyPhases . has ( updateService . getState ( ) . phase ) ) return ;
444+ if ( visibleUpdateCheckTimer ) {
445+ clearTimeout ( visibleUpdateCheckTimer ) ;
446+ visibleUpdateCheckTimer = undefined ;
447+ }
448+ const run = ( ) => {
449+ visibleUpdateCheckTimer = undefined ;
450+ if ( ! updateService || isQuitting ) return ;
451+ if ( busyPhases . has ( updateService . getState ( ) . phase ) ) return ;
452+ if ( Date . now ( ) - lastVisibleUpdateCheckAt < 1_500 ) return ;
453+ lastVisibleUpdateCheckAt = Date . now ( ) ;
454+ logger . info ( "update.visible_check" , { reason } ) ;
455+ void updateService . check ( true ) . catch ( ( error ) => {
456+ logger . warn ( "update.visible_check_failed" , {
457+ reason,
458+ error : serializeError ( error )
459+ } ) ;
460+ } ) ;
461+ } ;
462+ if ( delayMs > 0 ) {
463+ visibleUpdateCheckTimer = setTimeout ( run , delayMs ) ;
464+ visibleUpdateCheckTimer . unref ( ) ;
465+ } else {
466+ run ( ) ;
467+ }
468+ }
469+
437470function assertUpdateCanInstall ( ) : Promise < void > {
438471 const busyStages = new Set ( [
439472 "preflight" ,
@@ -466,11 +499,17 @@ function showMainView(
466499 view : "overview" | "search" | "ownership-map" | "analyze" | "migrate" | "history" | "settings" ,
467500 options : { path ?: string ; focus ?: "ai-settings" | "search-input" } = { }
468501) : void {
502+ const shouldCheckForUpdates =
503+ ! mainWindow ||
504+ mainWindow . isDestroyed ( ) ||
505+ ! mainWindow . isVisible ( ) ||
506+ mainWindow . isMinimized ( ) ;
469507 if ( ! mainWindow || mainWindow . isDestroyed ( ) ) mainWindow = createWindow ( ) ;
470508 if ( mainWindow . isMinimized ( ) ) mainWindow . restore ( ) ;
471509 mainWindow . show ( ) ;
472510 mainWindow . focus ( ) ;
473511 sendNavigation ( mainWindow , { view, ...options } ) ;
512+ if ( shouldCheckForUpdates ) triggerVisibleUpdateCheck ( "main-window-restored" ) ;
474513}
475514
476515function createQuickSearchWindow ( ) : BrowserWindow {
@@ -1765,9 +1804,7 @@ if (!singleInstance) {
17651804 } ) ;
17661805 await store . init ( ) ;
17671806 applyNativeEffect ( store . getSettings ( ) . effectMode ) ;
1768- mainWindow = createWindow ( ) ;
17691807 await completePendingUpdate ( ) ;
1770- createTray ( ) ;
17711808 const currentSettings = store . getSettings ( ) ;
17721809 searchService = new SearchService (
17731810 ( status ) => {
@@ -1784,22 +1821,41 @@ if (!singleInstance) {
17841821 }
17851822 }
17861823 } ,
1824+ ( event ) => {
1825+ for ( const window of [ mainWindow , quickSearchWindow ] ) {
1826+ if (
1827+ window &&
1828+ ! window . isDestroyed ( ) &&
1829+ window . isVisible ( ) &&
1830+ ! window . isMinimized ( )
1831+ ) {
1832+ window . webContents . send ( "search:index-changed" , event ) ;
1833+ }
1834+ }
1835+ } ,
17871836 ( ) => createQuickSearchWindow ( ) ,
17881837 {
17891838 button : currentSettings . mouseQuickSearchButton ,
17901839 holdMs : currentSettings . mouseQuickSearchHoldMs
17911840 }
17921841 ) ;
1793- syncSearchBackgroundMode ( ) ;
17941842 migrationService = new MigrationService ( store , ( record , message ) => {
17951843 if ( mainWindow && ! mainWindow . isDestroyed ( ) ) {
17961844 mainWindow . webContents . send ( "migration:progress" , { record, message } ) ;
17971845 }
17981846 } ) ;
17991847 updateService = new UpdateService ( emitUpdateState , assertUpdateCanInstall ) ;
18001848 registerIpc ( ) ;
1849+ const startupMinimized =
1850+ process . argv . includes ( "--startup-minimized" ) &&
1851+ currentSettings . launchAtLogin &&
1852+ currentSettings . launchMinimized ;
1853+ if ( ! startupMinimized ) mainWindow = createWindow ( ) ;
1854+ createTray ( ) ;
1855+ syncSearchBackgroundMode ( ) ;
1856+ triggerVisibleUpdateCheck ( "application-startup" , 2_500 ) ;
18011857 const shortcutFailures = applyGlobalShortcuts ( store . getSettings ( ) ) ;
1802- if ( shortcutFailures . length > 0 ) {
1858+ if ( shortcutFailures . length > 0 && mainWindow && ! mainWindow . isDestroyed ( ) ) {
18031859 void dialog . showMessageBox ( mainWindow , {
18041860 type : "warning" ,
18051861 title : "全局快捷键未完全启用" ,
@@ -1809,6 +1865,12 @@ if (!singleInstance) {
18091865 noLink : true
18101866 } ) ;
18111867 }
1868+ if ( shortcutFailures . length > 0 && startupMinimized ) {
1869+ logger . warn ( "shortcut.registration_incomplete" , {
1870+ startupMinimized,
1871+ failures : shortcutFailures
1872+ } ) ;
1873+ }
18121874 await migrationService . recoverIncomplete ( ) ;
18131875 // Let Chromium finish the first interactive frame before parsing a
18141876 // multi-million-entry persistent index. Search remains fully accurate once
@@ -1836,7 +1898,7 @@ if (!singleInstance) {
18361898 }
18371899
18381900 app . on ( "activate" , ( ) => {
1839- if ( BrowserWindow . getAllWindows ( ) . length === 0 ) mainWindow = createWindow ( ) ;
1901+ if ( BrowserWindow . getAllWindows ( ) . length === 0 ) showMainView ( "overview" ) ;
18401902 } ) ;
18411903 } ) ;
18421904}
@@ -1852,6 +1914,10 @@ app.on("window-all-closed", () => {
18521914
18531915app . on ( "before-quit" , ( event ) => {
18541916 isQuitting = true ;
1917+ if ( visibleUpdateCheckTimer ) {
1918+ clearTimeout ( visibleUpdateCheckTimer ) ;
1919+ visibleUpdateCheckTimer = undefined ;
1920+ }
18551921 if ( shutdownComplete ) return ;
18561922 event . preventDefault ( ) ;
18571923 logger . info ( "application.shutdown_started" , {
0 commit comments