experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(izui): restore window-level transient-on-blur auto-hide regressed by panel-type focus events

+50 -1
+42
backend/electron/ipc.ts
··· 76 76 closeOrHideWindow, 77 77 getSystemThemeBackgroundColor, 78 78 getPrefs, 79 + TRANSIENT_ROLES, 79 80 } from './windows.js'; 80 81 81 82 ··· 2052 2053 id: win.id, 2053 2054 role: winInfo?.params?.role as string | undefined, 2054 2055 }); 2056 + 2057 + // Auto-hide sibling transient windows when another window gains 2058 + // focus. IZUI policy: palette / quick-view / overlay windows are 2059 + // transient — they should dismiss as soon as focus moves to any 2060 + // other window. The per-window `blur` handler attached to modals 2061 + // covers Cmd+Tab and clicks into other apps, but macOS NSPanels 2062 + // (type:'panel' + alwaysOnTop) don't fire reliable `blur` when 2063 + // focus shifts to another panel-type window in the same app — so 2064 + // opening slide B from edge X never closes slide A on edge Y. The 2065 + // cmd panel restored this on the renderer side via a 2066 + // `window:focused` subscription (commit 6361cf19); generalize it 2067 + // here for all transient roles in the main process so we don't 2068 + // need a per-feature renderer hook for every panel-style tile. 2069 + // 2070 + // Skip when the focusing window is itself transient/utility: 2071 + // - utility (chain popup) is a child of a transient and must 2072 + // not dismiss its parent 2073 + // - palette/quick-view/overlay focusing each other would cause 2074 + // the just-opened transient to immediately close itself in 2075 + // the wrong order; let the new transient stand and dismiss 2076 + // the previous one(s). 2077 + const focusedRole = winInfo?.params?.role as string | undefined; 2078 + if (focusedRole !== 'utility') { 2079 + for (const other of BrowserWindow.getAllWindows()) { 2080 + if (other.id === win.id) continue; 2081 + if (other.isDestroyed()) continue; 2082 + if (!other.isVisible()) continue; 2083 + const otherInfo = getWindowInfo(other.id); 2084 + const otherRole = otherInfo?.params?.role as string | undefined; 2085 + if (!otherRole || !TRANSIENT_ROLES.has(otherRole)) continue; 2086 + // Overlays manage their own restoration flow via the IZUI 2087 + // coordinator — don't drive them through closeOrHideWindow. 2088 + if (otherRole === 'overlay') continue; 2089 + DEBUG && console.log('[izui] window-focused autoclose transient sibling:', other.id, 'role:', otherRole, 'focused:', win.id, 'role:', focusedRole); 2090 + try { 2091 + closeOrHideWindow(other.id); 2092 + } catch (err) { 2093 + DEBUG && console.log('[izui] autoclose transient failed:', err); 2094 + } 2095 + } 2096 + } 2055 2097 }); 2056 2098 // Also track immediately if this is a content/visible window (non-modal only) 2057 2099 trackContentWindowFocus(win);
+8 -1
backend/electron/windows.ts
··· 338 338 * These are modal/overlay windows (cmd palette, quick-view, windows switcher) 339 339 * that open and close frequently. Counting them causes dock show/hide cycling 340 340 * which triggers activation policy changes and spurious blur events. 341 + * 342 + * Also used by the focus-driven auto-hide path: when a non-transient, 343 + * non-utility window gains focus, any other window with one of these roles 344 + * is dismissed via closeOrHideWindow. Restores the "open another window 345 + * → previous transient closes" behavior that panel-type windows lose 346 + * because macOS NSPanels don't fire reliable per-window blur events when 347 + * focus shifts within the app. 341 348 */ 342 - const TRANSIENT_ROLES = new Set(['palette', 'quick-view', 'overlay']); 349 + export const TRANSIENT_ROLES = new Set(['palette', 'quick-view', 'overlay']); 343 350 344 351 /** 345 352 * Get count of visible persistent windows (excluding background, modals, overlays, HUD).