fix(overlay): stabilize macOS focus handoff and sidebar Yomitan pause

- Keep overlay visible during macOS foreground probe after overlay blur
- Hold sidebar hover-pause while a Yomitan lookup popup remains open
This commit is contained in:
2026-05-22 00:31:36 -07:00
parent 47e78ff698
commit e17c499cfe
13 changed files with 364 additions and 9 deletions
@@ -1260,6 +1260,54 @@ test('macOS tracked overlay hides when mpv loses foreground', () => {
assert.ok(!calls.includes('show'));
});
test('macOS keeps visible overlay stable while probing frontmost app after overlay blur', () => {
const { window, calls } = createMainWindowRecorder();
const tracker: WindowTrackerStub = {
isTracking: () => true,
getGeometry: () => ({ x: 0, y: 0, width: 1280, height: 720 }),
isTargetWindowFocused: () => false,
isTargetWindowMinimized: () => false,
};
window.show();
calls.length = 0;
updateVisibleOverlayVisibility({
visibleOverlayVisible: true,
mainWindow: window as never,
windowTracker: tracker as never,
trackerNotReadyWarningShown: false,
setTrackerNotReadyWarningShown: () => {},
updateVisibleOverlayBounds: () => {
calls.push('update-bounds');
},
ensureOverlayWindowLevel: () => {
calls.push('ensure-level');
},
syncPrimaryOverlayWindowLayer: () => {
calls.push('sync-layer');
},
enforceOverlayLayerOrder: () => {
calls.push('enforce-order');
},
syncOverlayShortcuts: () => {
calls.push('sync-shortcuts');
},
isMacOSPlatform: true,
isWindowsPlatform: false,
macOSForegroundProbeActive: true,
} as never);
assert.ok(calls.includes('update-bounds'));
assert.ok(calls.includes('sync-layer'));
assert.ok(calls.includes('mouse-ignore:true:forward'));
assert.ok(calls.includes('ensure-level'));
assert.ok(calls.includes('enforce-order'));
assert.ok(calls.includes('sync-shortcuts'));
assert.ok(!calls.includes('always-on-top:false'));
assert.ok(!calls.includes('hide'));
});
test('macOS keeps tracked overlay visible while overlay interaction is active after mpv loses foreground', () => {
const { window, calls, setFocused } = createMainWindowRecorder();
const tracker: WindowTrackerStub = {
+11 -1
View File
@@ -71,6 +71,7 @@ export function updateVisibleOverlayVisibility(args: {
lastKnownWindowsForegroundProcessName?: string | null;
windowsOverlayProcessName?: string | null;
windowsFocusHandoffGraceActive?: boolean;
macOSForegroundProbeActive?: boolean;
trackerNotReadyWarningShown: boolean;
setTrackerNotReadyWarningShown: (shown: boolean) => void;
updateVisibleOverlayBounds: (geometry: WindowGeometry) => void;
@@ -128,6 +129,12 @@ export function updateVisibleOverlayVisibility(args: {
const isTrackedMacOSTargetMinimized =
canReportMacOSTargetMinimized && windowTracker?.isTargetWindowMinimized() === true;
const trackedMacOSTargetFocused = args.windowTracker?.isTargetWindowFocused?.();
const shouldPreserveMacOSOverlayDuringForegroundProbe =
args.isMacOSPlatform &&
args.macOSForegroundProbeActive === true &&
!!windowTracker &&
!isTrackedMacOSTargetMinimized &&
(windowTracker.isTracking() || windowTracker.getGeometry() !== null);
const hasTransientMacOSTrackerLoss =
args.isMacOSPlatform &&
canReportMacOSTargetMinimized &&
@@ -137,7 +144,10 @@ export function updateVisibleOverlayVisibility(args: {
trackedMacOSTargetFocused !== false &&
mainWindow.isVisible();
const isTrackedMacOSTargetFocused =
hasTransientMacOSTrackerLoss || !args.isMacOSPlatform || !args.windowTracker
hasTransientMacOSTrackerLoss ||
shouldPreserveMacOSOverlayDuringForegroundProbe ||
!args.isMacOSPlatform ||
!args.windowTracker
? true
: (trackedMacOSTargetFocused ?? true);
const shouldReleaseMacOSOverlayLevel =