From cf3d53d1e5372a0aad45e1bb2eb44603cf9cf992 Mon Sep 17 00:00:00 2001 From: Grimmer Kang Date: Tue, 7 Apr 2026 01:12:34 +0800 Subject: [PATCH 1/3] fix: use setActivationPolicy instead of dock.hide/show MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace app.dock.hide()/show() with app.setActivationPolicy(): - Normal mode: 'regular' (dock icon + running dot + App Switcher) - Menu bar mode: 'accessory' (no dock icon, same as LSUIElement) setActivationPolicy is the official macOS API for this, cleaner than dock.hide() which has known Electron bugs. LSUIElement=true kept in Info.plist to prevent dock icon flash on app launch. Caveat: switching to 'accessory' hides all windows — re-show with 100ms delay after policy change. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/main.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main.ts b/src/main.ts index f947fc9..23f5d66 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1032,9 +1032,11 @@ const trayToggleEvtHandler = async () => { // Load app mode setting early (before window creation) appMode = ((await settings.get('app-mode')) as 'normal' | 'menubar') || 'normal'; - if (appMode === 'menubar') { - app.dock.hide(); + if (appMode === 'normal') { + app.setActivationPolicy('regular'); } + // LSUIElement=true in Info.plist starts as accessory (no dock icon). + // 'regular' adds dock icon + running dot + App Switcher. // Auto-update: check for updates via update.electronjs.org (non-MAS only) if (!isMAS()) { @@ -1972,9 +1974,14 @@ ipcMain.on('set-app-mode', async (_event, mode: string) => { await settings.set('app-mode', newMode); appMode = newMode; if (newMode === 'menubar') { - app.dock.hide(); + app.setActivationPolicy('accessory'); + // accessory mode hides all windows — re-show after short delay + const win = getSwitcherWindow(); + if (win) { + setTimeout(() => { win.show(); win.focus(); }, 100); + } } else { - await app.dock.show(); + app.setActivationPolicy('regular'); } // Notify renderer to update drag region const window = getSwitcherWindow(); @@ -2131,4 +2138,4 @@ ipcMain.handle('detect-active-ide-projects', async () => { return Array.from(folderNames); }); -// app.dock.hide() moved to async init block (after settings loaded) +// Dock visibility managed via app.setActivationPolicy() (see set-app-mode handler) From a3bdeece4d1e07e0c813673c88e82aa2a005de7d Mon Sep 17 00:00:00 2001 From: Grimmer Kang Date: Tue, 7 Apr 2026 01:29:28 +0800 Subject: [PATCH 2/3] feat: add mode toggle to tray right-click menu Shows 'Switch to Menu Bar Mode' or 'Switch to Normal App Mode' at the top of the tray context menu. Reuses the same IPC logic as the Settings toggle. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/TrayGenerator.ts | 12 ++++++++++++ src/main.ts | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/src/TrayGenerator.ts b/src/TrayGenerator.ts index 2dfdd67..a928e4e 100644 --- a/src/TrayGenerator.ts +++ b/src/TrayGenerator.ts @@ -21,6 +21,8 @@ export class TrayGenerator { tray: Tray; attachedWindow: BrowserWindow; onTrayClickCallback: any; + onToggleAppMode: (() => void) | null = null; + getAppMode: (() => string) | null = null; title: string; shortcuts: ShortcutSettings = { quickSwitcher: 'Command+Control+R', @@ -83,7 +85,17 @@ export class TrayGenerator { }, ]; + const currentMode = this.getAppMode ? this.getAppMode() : 'normal'; + const modeLabel = currentMode === 'normal' ? 'Switch to Menu Bar Mode' : 'Switch to Normal App Mode'; + const menu: any = [ + { + label: modeLabel, + click: () => { + if (this.onToggleAppMode) this.onToggleAppMode(); + }, + }, + { type: 'separator' }, { label: 'Settings', submenu: settingsItems, diff --git a/src/main.ts b/src/main.ts index 23f5d66..c6f91b2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1294,6 +1294,12 @@ const trayToggleEvtHandler = async () => { } tray = new TrayGenerator(switcherWindow, title, trayToggleEvtHandler); + tray.getAppMode = () => appMode; + tray.onToggleAppMode = () => { + const newMode = appMode === 'normal' ? 'menubar' : 'normal'; + // Reuse the same logic as the IPC handler + require('electron').ipcMain.emit('set-app-mode', {}, newMode); + }; // https://www.electronjs.org/docs/latest/tutorial/keyboard-shortcuts#global-shortcuts From 8693a7b8ecc2dd28f232ca8af57a99cbeb4b679d Mon Sep 17 00:00:00 2001 From: Grimmer Kang Date: Tue, 7 Apr 2026 01:30:52 +0800 Subject: [PATCH 3/3] chore: bump version to 1.0.71 Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 986233d..8395276 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.0.71 + +- Fix: use `setActivationPolicy` instead of `app.dock.hide/show` for proper Dock behavior + - Normal mode: Dock icon with running dot + App Switcher + - Menu bar mode: no Dock icon (clean accessory mode) + - No Dock icon flash on app launch (LSUIElement=true kept) +- Feat: tray right-click menu mode toggle (Switch to Normal/Menu Bar Mode) + ## 1.0.70 - Feat: Normal App mode — window stays visible, shows in Dock, draggable diff --git a/package.json b/package.json index 054a1a1..285f32f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "CodeV", "productName": "CodeV", - "version": "1.0.70", + "version": "1.0.71", "description": "Quick switcher for VS Code, Cursor, and Claude Code sessions", "repository": { "type": "git",