From 6c41b2c5195e80dfa36b74d1b85cecaf534c8538 Mon Sep 17 00:00:00 2001 From: yyhhyyyyyy Date: Wed, 6 Aug 2025 18:17:59 +0800 Subject: [PATCH 1/2] fix: resolve focus flicker when creating new windows with Ctrl+Shift+N --- src/main/presenter/tabPresenter.ts | 7 +++++++ src/main/presenter/windowPresenter/index.ts | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/presenter/tabPresenter.ts b/src/main/presenter/tabPresenter.ts index 3b5d2504a..741ff44f7 100644 --- a/src/main/presenter/tabPresenter.ts +++ b/src/main/presenter/tabPresenter.ts @@ -10,6 +10,7 @@ import { getContextMenuLabels } from '@shared/i18n' import { app } from 'electron' import { addWatermarkToNativeImage } from '@/lib/watermark' import { stitchImagesVertically } from '@/lib/scrollCapture' +import { presenter } from './' export class TabPresenter implements ITabPresenter { // 全局标签页实例存储 @@ -533,6 +534,12 @@ export class TabPresenter implements ITabPresenter { // Once did-finish-load happens, emit first content loaded webContents.once('did-finish-load', () => { eventBus.sendToMain(WINDOW_EVENTS.FIRST_CONTENT_LOADED, windowId) + setTimeout(() => { + const windowPresenter = presenter.windowPresenter as any + if (windowPresenter && typeof windowPresenter.focusActiveTab === 'function') { + windowPresenter.focusActiveTab(windowId) + } + }, 300) }) } diff --git a/src/main/presenter/windowPresenter/index.ts b/src/main/presenter/windowPresenter/index.ts index a041f2f26..f04e510c5 100644 --- a/src/main/presenter/windowPresenter/index.ts +++ b/src/main/presenter/windowPresenter/index.ts @@ -379,7 +379,7 @@ export class WindowPresenter implements IWindowPresenter { * 将焦点传递给指定窗口的活动标签页 * @param windowId 窗口 ID */ - private focusActiveTab(windowId: number): void { + public focusActiveTab(windowId: number): void { try { setTimeout(async () => { const tabPresenterInstance = presenter.tabPresenter as TabPresenter @@ -558,7 +558,9 @@ export class WindowPresenter implements IWindowPresenter { if (!shellWindow.isDestroyed()) { shellWindow.webContents.send('window-focused', windowId) } - this.focusActiveTab(windowId) + if (!options?.initialTab) { + this.focusActiveTab(windowId) + } }) // 窗口失去焦点 From 9574c68ed4c37bc94ce3443b6265cbceb40dc69b Mon Sep 17 00:00:00 2001 From: yyhhyyyyyy Date: Wed, 6 Aug 2025 18:52:54 +0800 Subject: [PATCH 2/2] fix: resolve focus flicker when creating new windows with Ctrl+Shift+N --- src/main/presenter/tabPresenter.ts | 2 +- src/main/presenter/windowPresenter/index.ts | 79 +++++++++++++++++++-- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/main/presenter/tabPresenter.ts b/src/main/presenter/tabPresenter.ts index 741ff44f7..27053a0e7 100644 --- a/src/main/presenter/tabPresenter.ts +++ b/src/main/presenter/tabPresenter.ts @@ -537,7 +537,7 @@ export class TabPresenter implements ITabPresenter { setTimeout(() => { const windowPresenter = presenter.windowPresenter as any if (windowPresenter && typeof windowPresenter.focusActiveTab === 'function') { - windowPresenter.focusActiveTab(windowId) + windowPresenter.focusActiveTab(windowId, 'initial') } }, 300) }) diff --git a/src/main/presenter/windowPresenter/index.ts b/src/main/presenter/windowPresenter/index.ts index f04e510c5..60686d86d 100644 --- a/src/main/presenter/windowPresenter/index.ts +++ b/src/main/presenter/windowPresenter/index.ts @@ -26,6 +26,16 @@ export class WindowPresenter implements IWindowPresenter { private isQuitting: boolean = false // 当前获得焦点的窗口 ID (内部记录) private focusedWindowId: number | null = null + // 窗口聚焦状态管理 + private windowFocusStates = new Map< + number, + { + lastFocusTime: number + shouldFocus: boolean + isNewWindow: boolean + hasInitialFocus: boolean + } + >() constructor(configPresenter: ConfigPresenter) { this.windows = new Map() @@ -310,7 +320,6 @@ export class WindowPresenter implements IWindowPresenter { this.handleWindowRestore(targetWindow.id).catch((error) => { console.error(`Error handling restore logic after showing window ${targetWindow!.id}:`, error) }) - this.focusActiveTab(targetWindow.id) } /** @@ -375,19 +384,69 @@ export class WindowPresenter implements IWindowPresenter { return focusedWindow ? focusedWindow.id === windowId : false } + /** + * 检查是否应该聚焦标签页 + * @param windowId 窗口 ID + * @param reason 聚焦原因 + */ + private shouldFocusTab( + windowId: number, + reason: 'focus' | 'restore' | 'show' | 'initial' + ): boolean { + const state = this.windowFocusStates.get(windowId) + if (!state) { + return true + } + const now = Date.now() + if (now - state.lastFocusTime < 100) { + console.log(`Skipping focus for window ${windowId}, too frequent (${reason})`) + return false + } + switch (reason) { + case 'initial': + return !state.hasInitialFocus + case 'focus': + return state.shouldFocus + case 'restore': + case 'show': + return state.isNewWindow || state.shouldFocus + default: + return false + } + } + /** * 将焦点传递给指定窗口的活动标签页 * @param windowId 窗口 ID + * @param reason 聚焦原因 */ - public focusActiveTab(windowId: number): void { + public focusActiveTab( + windowId: number, + reason: 'focus' | 'restore' | 'show' | 'initial' = 'focus' + ): void { + if (!this.shouldFocusTab(windowId, reason)) { + return + } try { setTimeout(async () => { const tabPresenterInstance = presenter.tabPresenter as TabPresenter const tabsData = await tabPresenterInstance.getWindowTabsData(windowId) const activeTab = tabsData.find((tab) => tab.isActive) if (activeTab) { - console.log(`Focusing active tab ${activeTab.id} in window ${windowId}`) + console.log( + `Focusing active tab ${activeTab.id} in window ${windowId} (reason: ${reason})` + ) await tabPresenterInstance.switchTab(activeTab.id) + const state = this.windowFocusStates.get(windowId) + if (state) { + state.lastFocusTime = Date.now() + if (reason === 'initial') { + state.hasInitialFocus = true + } + if (reason === 'focus' || reason === 'initial') { + state.isNewWindow = false + } + } } }, 50) } catch (error) { @@ -531,6 +590,13 @@ export class WindowPresenter implements IWindowPresenter { const windowId = shellWindow.id this.windows.set(windowId, shellWindow) // 将窗口实例存入 Map + this.windowFocusStates.set(windowId, { + lastFocusTime: 0, + shouldFocus: true, + isNewWindow: true, + hasInitialFocus: false + }) + shellWindowState.manage(shellWindow) // 管理窗口状态 // 应用内容保护设置 @@ -558,9 +624,7 @@ export class WindowPresenter implements IWindowPresenter { if (!shellWindow.isDestroyed()) { shellWindow.webContents.send('window-focused', windowId) } - if (!options?.initialTab) { - this.focusActiveTab(windowId) - } + this.focusActiveTab(windowId, 'focus') }) // 窗口失去焦点 @@ -608,7 +672,7 @@ export class WindowPresenter implements IWindowPresenter { this.handleWindowRestore(windowId).catch((error) => { console.error(`Error handling restore logic for window ${windowId}:`, error) }) - this.focusActiveTab(windowId) + this.focusActiveTab(windowId, 'restore') eventBus.sendToMain(WINDOW_EVENTS.WINDOW_RESTORED, windowId) } shellWindow.on('restore', handleRestore) @@ -719,6 +783,7 @@ export class WindowPresenter implements IWindowPresenter { shellWindow.removeListener('restore', handleRestore) this.windows.delete(windowIdBeingClosed) // 从 Map 中移除 + this.windowFocusStates.delete(windowIdBeingClosed) shellWindowState.unmanage() // 停止管理窗口状态 eventBus.sendToMain(WINDOW_EVENTS.WINDOW_CLOSED, windowIdBeingClosed) console.log(