Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion electron/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { app, BrowserWindow, dialog, ipcMain, session } from 'electron'
import { app, BrowserWindow, dialog, ipcMain, session, systemPreferences } from 'electron'
import type { IpcMainInvokeEvent } from 'electron'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { execFile } from 'node:child_process'
Expand Down Expand Up @@ -227,6 +227,32 @@ async function pickOpenPath(): Promise<PickResult> {
}

function registerIpcHandlers(): void {
/*
* `titleBarStyle: 'hiddenInset'` gives the renderer the drag region
* (`-webkit-app-region: drag` on the TopBar, see TopBar.module.css) but
* NOT the OS's usual double-click-to-zoom behaviour that a real title
* bar has for free — Chromium's drag region is a plain mouse listener,
* not an NSWindow title bar, so nothing tells macOS to react to the
* second click. The renderer's own dblclick handler calls this so we
* can honour the user's actual System Settings > Desktop & Dock choice
* ("Zoom", "Minimize" or "None") instead of hardcoding one.
*/
ipcMain.handle('window:titlebarDoubleClick', (evt) => {
if (process.platform !== 'darwin') return
const win = BrowserWindow.fromWebContents(evt.sender)
if (!win) return
const action = systemPreferences.getUserDefault('AppleActionOnDoubleClick', 'string')
if (action === 'Minimize') {
win.minimize()
} else if (action === 'None') {
// no-op, matches the system setting
} else {
// Default action ('Maximize', or unset) mirrors a native title bar.
if (win.isMaximized()) win.unmaximize()
else win.maximize()
}
})

ipcMain.handle('dialog:save', async (evt, defaultName: string) => {
/*
* Parent the modal to the window that MADE the call, not to whatever
Expand Down
4 changes: 3 additions & 1 deletion electron/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,9 @@ const api = {
window: {
/** Represented file + edited flag: macOS proxy icon and title-bar dot. */
setDocument: (p: { path: string | null; edited: boolean }): void =>
ipcRenderer.send('window:document', p)
ipcRenderer.send('window:document', p),
titlebarDoubleClick: (): Promise<void> =>
ipcRenderer.invoke('window:titlebarDoubleClick')
},
/** Errors the main process caught instead of dying from. */
onMainError: (cb: (msg: string) => void): (() => void) => onChannel('app:main-error', cb),
Expand Down
10 changes: 10 additions & 0 deletions src/components/layout/TopBar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@
*/
position: relative;
z-index: var(--dp-z-chrome, 20);
-webkit-app-region: drag;
}

.root button,
.root input,
.root select,
.root a,
.root [role='tab'],
.root [role='option'] {
-webkit-app-region: no-drag;
}

.left {
Expand Down
16 changes: 15 additions & 1 deletion src/components/layout/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,22 @@ export function TopBar() {
const [verificationOpen, setVerificationOpen] = useState(false)
const [testKind, setTestKind] = useState<NodeKind | null>(null)

/*
* The drag region (`-webkit-app-region: drag` in TopBar.module.css)
* substitutes for the title bar `hiddenInset` removes, but it's just a
* mouse listener to Chromium — macOS never learns to zoom the window on
* a second click there the way it would for a real NSWindow title bar.
* Skip it entirely over interactive descendants so double-clicking a
* button/tab doesn't ALSO toggle the window size.
*/
const onRootDoubleClick = (e: React.MouseEvent): void => {
const target = e.target as HTMLElement
if (target.closest('button, input, select, a, [role="tab"], [role="option"]')) return
void window.daisy.window.titlebarDoubleClick()
}

return (
<div className={styles.root}>
<div className={styles.root} onDoubleClick={onRootDoubleClick}>
<div className={styles.left}>
<span className={styles.dot} aria-hidden />
<span className={styles.wordmark}>DAISYPATCHER</span>
Expand Down