Switch to double quotes and reformat codebase with Biome
This commit is contained in:
@@ -2,11 +2,7 @@ import { spawn, type ChildProcess } from "node:child_process";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { app, ipcMain } from "electron";
|
||||
import {
|
||||
loadConfig,
|
||||
resolvePaseoHome,
|
||||
getOrCreateServerId,
|
||||
} from "@getpaseo/server";
|
||||
import { loadConfig, resolvePaseoHome, getOrCreateServerId } from "@getpaseo/server";
|
||||
import {
|
||||
copyAttachmentFileToManagedStorage,
|
||||
deleteManagedAttachmentFile,
|
||||
@@ -14,19 +10,13 @@ import {
|
||||
readManagedFileBase64,
|
||||
writeAttachmentBase64,
|
||||
} from "../features/attachments.js";
|
||||
import {
|
||||
checkForAppUpdate,
|
||||
downloadAndInstallUpdate,
|
||||
} from "../features/auto-updater.js";
|
||||
import { checkForAppUpdate, downloadAndInstallUpdate } from "../features/auto-updater.js";
|
||||
import {
|
||||
openLocalTransportSession,
|
||||
sendLocalTransportMessage,
|
||||
closeLocalTransportSession,
|
||||
} from "./local-transport.js";
|
||||
import {
|
||||
createElectronNodeEnv,
|
||||
resolveDaemonRunnerEntrypoint,
|
||||
} from "./runtime-paths.js";
|
||||
import { createElectronNodeEnv, resolveDaemonRunnerEntrypoint } from "./runtime-paths.js";
|
||||
|
||||
const DAEMON_LOG_FILENAME = "daemon.log";
|
||||
const DAEMON_PID_FILENAME = "paseo.pid";
|
||||
@@ -155,7 +145,7 @@ function buildDesktopDaemonCorsOriginsEnv(): string | undefined {
|
||||
(process.env.PASEO_CORS_ORIGINS ?? "")
|
||||
.split(",")
|
||||
.map((value) => value.trim())
|
||||
.filter((value) => value.length > 0)
|
||||
.filter((value) => value.length > 0),
|
||||
);
|
||||
|
||||
origins.add("paseo://app");
|
||||
@@ -315,7 +305,7 @@ async function startDaemon(): Promise<DesktopDaemonStatus> {
|
||||
...(corsOrigins ? { PASEO_CORS_ORIGINS: corsOrigins } : {}),
|
||||
}),
|
||||
stdio: ["ignore", "ignore", "ignore"],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
child.unref();
|
||||
@@ -343,9 +333,7 @@ async function startDaemon(): Promise<DesktopDaemonStatus> {
|
||||
|
||||
if (exitedEarly) {
|
||||
const logs = tailFile(logFilePath(), 15);
|
||||
throw new Error(
|
||||
`Daemon failed to start.${logs ? `\n\nRecent logs:\n${logs}` : ""}`
|
||||
);
|
||||
throw new Error(`Daemon failed to start.${logs ? `\n\nRecent logs:\n${logs}` : ""}`);
|
||||
}
|
||||
|
||||
// Poll for PID file with server ID
|
||||
@@ -524,19 +512,21 @@ export function createDaemonCommandHandlers(): Record<string, DesktopCommandHand
|
||||
copy_attachment_file: (args) => copyAttachmentFileToManagedStorage(args ?? {}),
|
||||
read_file_base64: (args) => readManagedFileBase64(args ?? {}),
|
||||
delete_attachment_file: (args) => deleteManagedAttachmentFile(args ?? {}),
|
||||
garbage_collect_attachment_files: (args) =>
|
||||
garbageCollectManagedAttachmentFiles(args ?? {}),
|
||||
garbage_collect_attachment_files: (args) => garbageCollectManagedAttachmentFiles(args ?? {}),
|
||||
open_local_daemon_transport: async (args) => {
|
||||
const target = args as { transportType: "socket" | "pipe"; transportPath: string };
|
||||
return await openLocalTransportSession(target);
|
||||
},
|
||||
send_local_daemon_transport_message: async (args) => {
|
||||
await sendLocalTransportMessage(args as { sessionId: string; text?: string; binaryBase64?: string });
|
||||
await sendLocalTransportMessage(
|
||||
args as { sessionId: string; text?: string; binaryBase64?: string },
|
||||
);
|
||||
},
|
||||
close_local_daemon_transport: (args) => {
|
||||
const sessionId = typeof args === "object" && args !== null && "sessionId" in args
|
||||
? (args as { sessionId: string }).sessionId
|
||||
: "";
|
||||
const sessionId =
|
||||
typeof args === "object" && args !== null && "sessionId" in args
|
||||
? (args as { sessionId: string }).sessionId
|
||||
: "";
|
||||
if (sessionId) closeLocalTransportSession(sessionId);
|
||||
},
|
||||
check_app_update: async () => {
|
||||
@@ -568,6 +558,6 @@ export function registerDaemonManager(): void {
|
||||
throw new Error(`Unknown desktop command: ${command}`);
|
||||
}
|
||||
return await handler(args);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,10 +52,7 @@ function describeTransportTarget(target: TransportTarget): string {
|
||||
return target.transportType === "pipe" ? "local daemon pipe" : "local daemon socket";
|
||||
}
|
||||
|
||||
function decodeTransportMessage(input: {
|
||||
text?: string;
|
||||
binaryBase64?: string;
|
||||
}): string | Buffer {
|
||||
function decodeTransportMessage(input: { text?: string; binaryBase64?: string }): string | Buffer {
|
||||
if (typeof input.text === "string") {
|
||||
return input.text;
|
||||
}
|
||||
@@ -125,7 +122,7 @@ export function openLocalTransportSession(target: TransportTarget): Promise<stri
|
||||
|
||||
if (!openSettled) {
|
||||
finalizeOpenFailure(
|
||||
`${describeTransportTarget(target)} closed before the session became ready.`
|
||||
`${describeTransportTarget(target)} closed before the session became ready.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -143,7 +140,7 @@ export function openLocalTransportSession(target: TransportTarget): Promise<stri
|
||||
ws.on("error", (err: Error) => {
|
||||
if (!openSettled) {
|
||||
finalizeOpenFailure(
|
||||
`Failed to connect to ${describeTransportTarget(target)}: ${err.message}`
|
||||
`Failed to connect to ${describeTransportTarget(target)}: ${err.message}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -171,7 +168,7 @@ export async function sendLocalTransportMessage(input: {
|
||||
throw new Error(
|
||||
session.state === "opening"
|
||||
? "Local transport session is not open yet."
|
||||
: "Local transport session is closed."
|
||||
: "Local transport session is closed.",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,10 +73,7 @@ function resolvePackagedAsarPath(): string {
|
||||
return path.join(process.resourcesPath, "app.asar");
|
||||
}
|
||||
|
||||
function assertPathExists(input: {
|
||||
label: string;
|
||||
filePath: string;
|
||||
}): string {
|
||||
function assertPathExists(input: { label: string; filePath: string }): string {
|
||||
if (!existsSync(input.filePath)) {
|
||||
throw new Error(`${input.label} is missing at ${input.filePath}`);
|
||||
}
|
||||
@@ -105,7 +102,7 @@ export function resolveDaemonRunnerEntrypoint(): NodeEntrypointSpec {
|
||||
"server",
|
||||
"dist",
|
||||
"scripts",
|
||||
"daemon-runner.js"
|
||||
"daemon-runner.js",
|
||||
),
|
||||
}),
|
||||
execArgv: [],
|
||||
@@ -141,7 +138,7 @@ export function resolveCliEntrypoint(): NodeEntrypointSpec {
|
||||
"@getpaseo",
|
||||
"cli",
|
||||
"dist",
|
||||
"index.js"
|
||||
"index.js",
|
||||
),
|
||||
}),
|
||||
execArgv: [],
|
||||
|
||||
@@ -122,9 +122,7 @@ export async function readManagedFileBase64(input: { path?: unknown }): Promise<
|
||||
return bytes.toString("base64");
|
||||
}
|
||||
|
||||
export async function deleteManagedAttachmentFile(input: {
|
||||
path?: unknown;
|
||||
}): Promise<boolean> {
|
||||
export async function deleteManagedAttachmentFile(input: { path?: unknown }): Promise<boolean> {
|
||||
const filePath = resolveManagedAttachmentPath(input.path);
|
||||
await rm(filePath, { force: true });
|
||||
return true;
|
||||
@@ -139,7 +137,7 @@ export async function garbageCollectManagedAttachmentFiles(input: {
|
||||
input.referencedIds
|
||||
.filter((value): value is string => typeof value === "string")
|
||||
.map((value) => value.trim())
|
||||
.filter((value) => ATTACHMENT_ID_PATTERN.test(value))
|
||||
.filter((value) => ATTACHMENT_ID_PATTERN.test(value)),
|
||||
)
|
||||
: new Set<string>();
|
||||
|
||||
|
||||
@@ -96,7 +96,9 @@ export async function checkForAppUpdate(currentVersion: string): Promise<AppUpda
|
||||
}
|
||||
}
|
||||
|
||||
export async function downloadAndInstallUpdate(currentVersion: string): Promise<AppUpdateInstallResult> {
|
||||
export async function downloadAndInstallUpdate(
|
||||
currentVersion: string,
|
||||
): Promise<AppUpdateInstallResult> {
|
||||
if (!app.isPackaged) {
|
||||
return {
|
||||
installed: false,
|
||||
|
||||
@@ -19,7 +19,8 @@ export function registerDialogHandlers(): void {
|
||||
ipcMain.handle("paseo:dialog:ask", async (event, message: string, options?: AskOptions) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
const result = await dialog.showMessageBox(win ?? BrowserWindow.getFocusedWindow()!, {
|
||||
type: options?.kind === "warning" ? "warning" : options?.kind === "error" ? "error" : "question",
|
||||
type:
|
||||
options?.kind === "warning" ? "warning" : options?.kind === "error" ? "error" : "question",
|
||||
title: options?.title ?? "Confirm",
|
||||
message,
|
||||
buttons: [options?.cancelLabel ?? "Cancel", options?.okLabel ?? "OK"],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { app, Menu, BrowserWindow } from "electron";
|
||||
|
||||
function withBrowserWindow(
|
||||
callback: (win: BrowserWindow) => void
|
||||
callback: (win: BrowserWindow) => void,
|
||||
): (_item: Electron.MenuItem, baseWin: Electron.BaseWindow | undefined) => void {
|
||||
return (_item, baseWin) => {
|
||||
const win = baseWin instanceof BrowserWindow ? baseWin : BrowserWindow.getFocusedWindow();
|
||||
|
||||
@@ -3,11 +3,21 @@ import { pathToFileURL } from "node:url";
|
||||
import { existsSync } from "node:fs";
|
||||
import { app, BrowserWindow, nativeImage, net, protocol } from "electron";
|
||||
import { registerDaemonManager } from "./daemon/daemon-manager.js";
|
||||
import { parseCliPassthroughArgsFromArgv, runCliPassthroughCommand } from "./daemon/runtime-paths.js";
|
||||
import {
|
||||
parseCliPassthroughArgsFromArgv,
|
||||
runCliPassthroughCommand,
|
||||
} from "./daemon/runtime-paths.js";
|
||||
import { closeAllTransportSessions } from "./daemon/local-transport.js";
|
||||
import { registerWindowManager, setupWindowResizeEvents, setupDragDropPrevention } from "./window/window-manager.js";
|
||||
import {
|
||||
registerWindowManager,
|
||||
setupWindowResizeEvents,
|
||||
setupDragDropPrevention,
|
||||
} from "./window/window-manager.js";
|
||||
import { registerDialogHandlers } from "./features/dialogs.js";
|
||||
import { registerNotificationHandlers, ensureNotificationCenterRegistration } from "./features/notifications.js";
|
||||
import {
|
||||
registerNotificationHandlers,
|
||||
ensureNotificationCenterRegistration,
|
||||
} from "./features/notifications.js";
|
||||
import { registerOpenerHandlers } from "./features/opener.js";
|
||||
import { setupApplicationMenu } from "./features/menu.js";
|
||||
|
||||
@@ -38,12 +48,15 @@ function getAppDistDir(): string {
|
||||
function getWindowIconPath(): string | null {
|
||||
const candidates = app.isPackaged
|
||||
? process.platform === "win32"
|
||||
? [path.join(process.resourcesPath, "icon.ico"), path.join(process.resourcesPath, "icon.png")]
|
||||
: [path.join(process.resourcesPath, "icon.png")]
|
||||
? [path.join(process.resourcesPath, "icon.ico"), path.join(process.resourcesPath, "icon.png")]
|
||||
: [path.join(process.resourcesPath, "icon.png")]
|
||||
: process.platform === "darwin"
|
||||
? [path.resolve(__dirname, "../assets/icon.png")]
|
||||
: process.platform === "win32"
|
||||
? [path.resolve(__dirname, "../assets/icon.ico"), path.resolve(__dirname, "../assets/icon.png")]
|
||||
? [
|
||||
path.resolve(__dirname, "../assets/icon.ico"),
|
||||
path.resolve(__dirname, "../assets/icon.png"),
|
||||
]
|
||||
: [path.resolve(__dirname, "../assets/icon.png")];
|
||||
|
||||
return candidates.find((candidate) => existsSync(candidate)) ?? null;
|
||||
@@ -136,7 +149,7 @@ async function runCliPassthroughIfRequested(): Promise<boolean> {
|
||||
const exitCode = runCliPassthroughCommand(cliArgs);
|
||||
process.exit(exitCode);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.stack ?? error.message : String(error);
|
||||
const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
|
||||
process.stderr.write(`${message}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -200,7 +213,7 @@ async function bootstrap(): Promise<void> {
|
||||
}
|
||||
|
||||
void bootstrap().catch((error) => {
|
||||
const message = error instanceof Error ? error.stack ?? error.message : String(error);
|
||||
const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
|
||||
process.stderr.write(`${message}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -41,8 +41,7 @@ contextBridge.exposeInMainWorld("paseoDesktop", {
|
||||
dialog: {
|
||||
ask: (message: string, options?: Record<string, unknown>) =>
|
||||
ipcRenderer.invoke("paseo:dialog:ask", message, options),
|
||||
open: (options?: Record<string, unknown>) =>
|
||||
ipcRenderer.invoke("paseo:dialog:open", options),
|
||||
open: (options?: Record<string, unknown>) => ipcRenderer.invoke("paseo:dialog:open", options),
|
||||
},
|
||||
notification: {
|
||||
isSupported: () => ipcRenderer.invoke("paseo:notification:isSupported"),
|
||||
|
||||
@@ -1,71 +1,73 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
createWindowMoveState,
|
||||
readWindowMovePayload,
|
||||
resolveWindowMovePosition,
|
||||
} from './window-drag-coordinates'
|
||||
} from "./window-drag-coordinates";
|
||||
|
||||
describe('window-drag-coordinates', () => {
|
||||
describe('readWindowMovePayload', () => {
|
||||
it('returns finite screen coordinates', () => {
|
||||
describe("window-drag-coordinates", () => {
|
||||
describe("readWindowMovePayload", () => {
|
||||
it("returns finite screen coordinates", () => {
|
||||
expect(readWindowMovePayload({ screenX: 1500, screenY: 900 })).toEqual({
|
||||
screenX: 1500,
|
||||
screenY: 900,
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects non-finite screen coordinates', () => {
|
||||
expect(readWindowMovePayload({ screenX: Number.NaN, screenY: 900 })).toBeNull()
|
||||
expect(readWindowMovePayload({ screenX: 1500, screenY: Number.POSITIVE_INFINITY })).toBeNull()
|
||||
})
|
||||
})
|
||||
it("rejects non-finite screen coordinates", () => {
|
||||
expect(readWindowMovePayload({ screenX: Number.NaN, screenY: 900 })).toBeNull();
|
||||
expect(
|
||||
readWindowMovePayload({ screenX: 1500, screenY: Number.POSITIVE_INFINITY }),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('createWindowMoveState', () => {
|
||||
it('derives finite offsets from the window position', () => {
|
||||
describe("createWindowMoveState", () => {
|
||||
it("derives finite offsets from the window position", () => {
|
||||
expect(
|
||||
createWindowMoveState({
|
||||
payload: { screenX: 1500, screenY: 900 },
|
||||
windowX: 1200,
|
||||
windowY: 700,
|
||||
})
|
||||
}),
|
||||
).toEqual({
|
||||
offsetX: 300,
|
||||
offsetY: 200,
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects non-finite offsets', () => {
|
||||
it("rejects non-finite offsets", () => {
|
||||
expect(
|
||||
createWindowMoveState({
|
||||
payload: { screenX: 1500, screenY: 900 },
|
||||
windowX: Number.NaN,
|
||||
windowY: 700,
|
||||
})
|
||||
).toBeNull()
|
||||
})
|
||||
})
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveWindowMovePosition', () => {
|
||||
it('rounds the next window position', () => {
|
||||
describe("resolveWindowMovePosition", () => {
|
||||
it("rounds the next window position", () => {
|
||||
expect(
|
||||
resolveWindowMovePosition({
|
||||
payload: { screenX: 1501.4, screenY: 902.6 },
|
||||
state: { offsetX: 300, offsetY: 200 },
|
||||
})
|
||||
}),
|
||||
).toEqual({
|
||||
x: 1201,
|
||||
y: 703,
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects non-finite next positions', () => {
|
||||
it("rejects non-finite next positions", () => {
|
||||
expect(
|
||||
resolveWindowMovePosition({
|
||||
payload: { screenX: 1500, screenY: 900 },
|
||||
state: { offsetX: Number.NaN, offsetY: 200 },
|
||||
})
|
||||
).toBeNull()
|
||||
})
|
||||
})
|
||||
})
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
export type WindowMovePayload = {
|
||||
screenX: number
|
||||
screenY: number
|
||||
}
|
||||
screenX: number;
|
||||
screenY: number;
|
||||
};
|
||||
|
||||
export type WindowMoveState = {
|
||||
offsetX: number
|
||||
offsetY: number
|
||||
}
|
||||
offsetX: number;
|
||||
offsetY: number;
|
||||
};
|
||||
|
||||
export type WindowPosition = {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
type WindowMovePayloadInput =
|
||||
| {
|
||||
screenX?: unknown
|
||||
screenY?: unknown
|
||||
screenX?: unknown;
|
||||
screenY?: unknown;
|
||||
}
|
||||
| null
|
||||
| undefined
|
||||
| undefined;
|
||||
|
||||
function isFiniteCoordinate(value: unknown): value is number {
|
||||
return typeof value === 'number' && Number.isFinite(value)
|
||||
return typeof value === "number" && Number.isFinite(value);
|
||||
}
|
||||
|
||||
export function readWindowMovePayload(input: WindowMovePayloadInput): WindowMovePayload | null {
|
||||
if (!isFiniteCoordinate(input?.screenX) || !isFiniteCoordinate(input?.screenY)) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
screenX: input.screenX,
|
||||
screenY: input.screenY,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createWindowMoveState(input: {
|
||||
payload: WindowMovePayload
|
||||
windowX: number
|
||||
windowY: number
|
||||
payload: WindowMovePayload;
|
||||
windowX: number;
|
||||
windowY: number;
|
||||
}): WindowMoveState | null {
|
||||
const offsetX = input.payload.screenX - input.windowX
|
||||
const offsetY = input.payload.screenY - input.windowY
|
||||
const offsetX = input.payload.screenX - input.windowX;
|
||||
const offsetY = input.payload.screenY - input.windowY;
|
||||
if (!Number.isFinite(offsetX) || !Number.isFinite(offsetY)) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return { offsetX, offsetY }
|
||||
return { offsetX, offsetY };
|
||||
}
|
||||
|
||||
export function resolveWindowMovePosition(input: {
|
||||
payload: WindowMovePayload
|
||||
state: WindowMoveState
|
||||
payload: WindowMovePayload;
|
||||
state: WindowMoveState;
|
||||
}): WindowPosition | null {
|
||||
const x = Math.round(input.payload.screenX - input.state.offsetX)
|
||||
const y = Math.round(input.payload.screenY - input.state.offsetY)
|
||||
const x = Math.round(input.payload.screenX - input.state.offsetX);
|
||||
const y = Math.round(input.payload.screenY - input.state.offsetY);
|
||||
if (!Number.isFinite(x) || !Number.isFinite(y)) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return { x, y }
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
@@ -1,103 +1,103 @@
|
||||
import { app, BrowserWindow, ipcMain } from 'electron'
|
||||
import { app, BrowserWindow, ipcMain } from "electron";
|
||||
import {
|
||||
createWindowMoveState,
|
||||
readWindowMovePayload,
|
||||
resolveWindowMovePosition,
|
||||
type WindowMoveState,
|
||||
} from './window-drag-coordinates.js'
|
||||
} from "./window-drag-coordinates.js";
|
||||
|
||||
export function registerWindowManager(): void {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Manual window dragging (replaces flaky CSS -webkit-app-region: drag).
|
||||
// State is keyed per window id to support multiple windows.
|
||||
// ---------------------------------------------------------------------------
|
||||
const moveStates = new Map<number, WindowMoveState>()
|
||||
const moveStates = new Map<number, WindowMoveState>();
|
||||
|
||||
ipcMain.on('paseo:window:startMove', (event, payload: { screenX: number; screenY: number }) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
if (!win) return
|
||||
const movePayload = readWindowMovePayload(payload)
|
||||
ipcMain.on("paseo:window:startMove", (event, payload: { screenX: number; screenY: number }) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (!win) return;
|
||||
const movePayload = readWindowMovePayload(payload);
|
||||
if (!movePayload) {
|
||||
moveStates.delete(win.id)
|
||||
return
|
||||
moveStates.delete(win.id);
|
||||
return;
|
||||
}
|
||||
const [winX, winY] = win.getPosition()
|
||||
const [winX, winY] = win.getPosition();
|
||||
const moveState = createWindowMoveState({
|
||||
payload: movePayload,
|
||||
windowX: winX,
|
||||
windowY: winY,
|
||||
})
|
||||
});
|
||||
if (!moveState) {
|
||||
moveStates.delete(win.id)
|
||||
return
|
||||
moveStates.delete(win.id);
|
||||
return;
|
||||
}
|
||||
moveStates.set(win.id, moveState)
|
||||
})
|
||||
moveStates.set(win.id, moveState);
|
||||
});
|
||||
|
||||
ipcMain.on('paseo:window:moving', (event, payload: { screenX: number; screenY: number }) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
if (!win) return
|
||||
const state = moveStates.get(win.id)
|
||||
if (!state) return
|
||||
const movePayload = readWindowMovePayload(payload)
|
||||
ipcMain.on("paseo:window:moving", (event, payload: { screenX: number; screenY: number }) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (!win) return;
|
||||
const state = moveStates.get(win.id);
|
||||
if (!state) return;
|
||||
const movePayload = readWindowMovePayload(payload);
|
||||
if (!movePayload) {
|
||||
moveStates.delete(win.id)
|
||||
return
|
||||
moveStates.delete(win.id);
|
||||
return;
|
||||
}
|
||||
const nextPosition = resolveWindowMovePosition({
|
||||
payload: movePayload,
|
||||
state,
|
||||
})
|
||||
});
|
||||
if (!nextPosition) {
|
||||
moveStates.delete(win.id)
|
||||
return
|
||||
moveStates.delete(win.id);
|
||||
return;
|
||||
}
|
||||
win.setPosition(nextPosition.x, nextPosition.y)
|
||||
})
|
||||
win.setPosition(nextPosition.x, nextPosition.y);
|
||||
});
|
||||
|
||||
ipcMain.on('paseo:window:endMove', (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
if (win) moveStates.delete(win.id)
|
||||
})
|
||||
ipcMain.on("paseo:window:endMove", (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (win) moveStates.delete(win.id);
|
||||
});
|
||||
|
||||
app.on('browser-window-created', (_event, win) => {
|
||||
win.on('closed', () => moveStates.delete(win.id))
|
||||
})
|
||||
app.on("browser-window-created", (_event, win) => {
|
||||
win.on("closed", () => moveStates.delete(win.id));
|
||||
});
|
||||
|
||||
ipcMain.handle('paseo:window:toggleMaximize', (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
if (!win) return
|
||||
ipcMain.handle("paseo:window:toggleMaximize", (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (!win) return;
|
||||
if (win.isMaximized()) {
|
||||
win.unmaximize()
|
||||
win.unmaximize();
|
||||
} else {
|
||||
win.maximize()
|
||||
win.maximize();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
ipcMain.handle('paseo:window:isFullscreen', (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
return win?.isFullScreen() ?? false
|
||||
})
|
||||
ipcMain.handle("paseo:window:isFullscreen", (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
return win?.isFullScreen() ?? false;
|
||||
});
|
||||
|
||||
ipcMain.handle('paseo:window:setBadgeCount', (_event, count?: number) => {
|
||||
if (process.platform === 'darwin' || process.platform === 'linux') {
|
||||
app.setBadgeCount(count ?? 0)
|
||||
ipcMain.handle("paseo:window:setBadgeCount", (_event, count?: number) => {
|
||||
if (process.platform === "darwin" || process.platform === "linux") {
|
||||
app.setBadgeCount(count ?? 0);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export function setupWindowResizeEvents(win: BrowserWindow): void {
|
||||
win.on('resize', () => {
|
||||
win.webContents.send('paseo:window:resized', {})
|
||||
})
|
||||
win.on("resize", () => {
|
||||
win.webContents.send("paseo:window:resized", {});
|
||||
});
|
||||
|
||||
win.on('enter-full-screen', () => {
|
||||
win.webContents.send('paseo:window:resized', {})
|
||||
})
|
||||
win.on("enter-full-screen", () => {
|
||||
win.webContents.send("paseo:window:resized", {});
|
||||
});
|
||||
|
||||
win.on('leave-full-screen', () => {
|
||||
win.webContents.send('paseo:window:resized', {})
|
||||
})
|
||||
win.on("leave-full-screen", () => {
|
||||
win.webContents.send("paseo:window:resized", {});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,11 +105,11 @@ export function setupWindowResizeEvents(win: BrowserWindow): void {
|
||||
* The renderer handles drag-drop via standard HTML5 APIs instead.
|
||||
*/
|
||||
export function setupDragDropPrevention(win: BrowserWindow): void {
|
||||
win.webContents.on('will-navigate', (event, url) => {
|
||||
win.webContents.on("will-navigate", (event, url) => {
|
||||
// Allow normal navigation (e.g. dev server hot-reload) but block file:// URLs
|
||||
// that result from dropping files onto the window.
|
||||
if (url.startsWith('file://')) {
|
||||
event.preventDefault()
|
||||
if (url.startsWith("file://")) {
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user