Skip to content

Commit 08d51f7

Browse files
bobbyjohnstxclaude
andcommitted
feat(desktop): P2 polish — zoom persistence, dock badges, global hotkey, entitlements audit
- Zoom persistence: Store and restore zoom factor across app restarts - New ZOOM_FACTOR_KEY constant - wireZoom() reads stored zoom on window creation and persists changes - IPC set-zoom-factor also persists to store - Dock/taskbar notifications: Badge (macOS) or flash (Windows) on background activity - Focus/blur event handlers track window focus state - update-ready IPC event triggers badge/flash when window not focused - Clear badge/flash on window focus - Global hotkey: Cmd/Ctrl+Shift+T to show and focus main window - Registered via globalShortcut.register() - Unregister on will-quit - DevTools shortcut: Already handled via role="toggleDevTools" (no change needed) - Entitlements audit: Removed unnecessary/risky macOS entitlements - Removed: disable-executable-page-protection (not needed) - Removed: allow-dyld-environment-variables (shell-env.ts doesn't need it) - Removed: device.audio-input (no audio features in code editor) - Kept: allow-jit, allow-unsigned-executable-memory, disable-library-validation (required for Electron/V8) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 53ac2bf commit 08d51f7

5 files changed

Lines changed: 39 additions & 10 deletions

File tree

‎packages/desktop/resources/entitlements.plist‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,7 @@
66
<true/>
77
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
88
<true/>
9-
<key>com.apple.security.cs.disable-executable-page-protection</key>
10-
<true/>
11-
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
12-
<true/>
139
<key>com.apple.security.cs.disable-library-validation</key>
1410
<true/>
15-
<key>com.apple.security.device.audio-input</key>
16-
<true/>
1711
</dict>
1812
</plist>

‎packages/desktop/src/main/constants.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export const SETTINGS_STORE = "tinycode.settings"
88
export const DEFAULT_SERVER_URL_KEY = "defaultServerUrl"
99
export const WSL_ENABLED_KEY = "wslEnabled"
1010
export const PINCH_ZOOM_ENABLED_KEY = "pinchZoomEnabled"
11+
export const ZOOM_FACTOR_KEY = "zoomFactor"
1112
export const UPDATER_ENABLED = app.isPackaged && CHANNEL !== "dev"

‎packages/desktop/src/main/index.ts‎

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { homedir, tmpdir } from "node:os"
77
import { join } from "node:path"
88
import { getCACertificates, setDefaultCACertificates } from "node:tls"
99
import type { Event } from "electron"
10-
import { app, BrowserWindow, dialog } from "electron"
10+
import { app, BrowserWindow, dialog, globalShortcut, ipcMain } from "electron"
1111

1212
import contextMenu from "electron-context-menu"
1313

@@ -206,6 +206,7 @@ const main = Effect.gen(function* () {
206206
})
207207

208208
app.on("will-quit", () => {
209+
globalShortcut.unregisterAll()
209210
void killSidecar()
210211
})
211212

@@ -422,6 +423,34 @@ const main = Effect.gen(function* () {
422423
},
423424
quit: () => app.quit(),
424425
})
426+
427+
globalShortcut.register("CommandOrControl+Shift+T", () => {
428+
if (mainWindow && !mainWindow.isDestroyed()) {
429+
mainWindow.show()
430+
mainWindow.focus()
431+
}
432+
})
433+
434+
let hasFocus = mainWindow.isFocused()
435+
mainWindow.on("focus", () => {
436+
hasFocus = true
437+
if (process.platform === "darwin") app.dock?.setBadge("")
438+
mainWindow?.flashFrame(false)
439+
})
440+
441+
mainWindow.on("blur", () => {
442+
hasFocus = false
443+
})
444+
445+
ipcMain.on("update-ready", () => {
446+
if (!hasFocus && mainWindow && !mainWindow.isDestroyed()) {
447+
if (process.platform === "darwin") {
448+
app.dock?.setBadge("!")
449+
} else {
450+
mainWindow.flashFrame(true)
451+
}
452+
}
453+
})
425454
}
426455

427456
overlay?.close()

‎packages/desktop/src/main/ipc.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ export function registerIpcHandlers(deps: Deps) {
207207
ipcMain.handle("get-zoom-factor", (event: IpcMainInvokeEvent) => event.sender.getZoomFactor())
208208
ipcMain.handle("set-zoom-factor", (event: IpcMainInvokeEvent, factor: number) => {
209209
event.sender.setZoomFactor(factor)
210+
getStore().set("zoomFactor", factor)
210211
const win = BrowserWindow.fromWebContents(event.sender)
211212
if (!win) return
212213
updateTitlebar(win)

‎packages/desktop/src/main/windows.ts‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { app, BrowserWindow, dialog, net, nativeImage, nativeTheme, protocol, sh
66
import { dirname, isAbsolute, join, relative, resolve } from "node:path"
77
import { fileURLToPath, pathToFileURL } from "node:url"
88
import type { TitlebarTheme } from "../preload/types"
9-
import { PINCH_ZOOM_ENABLED_KEY } from "./constants"
9+
import { PINCH_ZOOM_ENABLED_KEY, ZOOM_FACTOR_KEY } from "./constants"
1010
import { exportDebugLogs, write as writeLog } from "./logging"
1111
import { getStore } from "./store"
1212
import { createUnresponsiveSampler } from "./unresponsive"
@@ -444,11 +444,15 @@ function isRendererUrl(value?: string, html = false) {
444444

445445
function wireZoom(win: BrowserWindow) {
446446
pinchZoomEnabled.set(win, getPinchZoomEnabled())
447-
win.webContents.setZoomFactor(1)
447+
const storedZoom = getStore().get(ZOOM_FACTOR_KEY)
448+
const initialZoom = typeof storedZoom === "number" ? clampZoom(storedZoom) : 1
449+
win.webContents.setZoomFactor(initialZoom)
448450
win.webContents.on("zoom-changed", (event, zoomDirection) => {
449451
event.preventDefault()
450452
if (pinchZoomEnabled.get(win)) {
451-
win.webContents.setZoomFactor(clampZoom(win.webContents.getZoomFactor() + (zoomDirection === "in" ? 0.2 : -0.2)))
453+
const newZoom = clampZoom(win.webContents.getZoomFactor() + (zoomDirection === "in" ? 0.2 : -0.2))
454+
win.webContents.setZoomFactor(newZoom)
455+
getStore().set(ZOOM_FACTOR_KEY, newZoom)
452456
updateZoom(win)
453457
return
454458
}

0 commit comments

Comments
 (0)