From 8ac82588c7eaf11e0c9012b4cb7c24d5a12d5f7e Mon Sep 17 00:00:00 2001 From: LudoO Date: Wed, 5 Feb 2025 11:05:33 +0100 Subject: [PATCH] feat: center tray window --- package-lock.json | 35 ++++++++++++++++---- src/main/MainRunner.ts | 9 +++-- src/main/desktop.ts | 17 ++++++++++ src/main/tray.ts | 65 +++++++++++++------------------------ src/main/utils/Constants.ts | 3 ++ 5 files changed, 78 insertions(+), 51 deletions(-) create mode 100644 src/main/desktop.ts diff --git a/package-lock.json b/package-lock.json index 193961a..e1da818 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2349,6 +2349,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.1.tgz", "integrity": "sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.16.1", @@ -2382,6 +2383,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.1.tgz", "integrity": "sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "7.16.1", "@typescript-eslint/types": "7.16.1", @@ -2410,6 +2412,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.1.tgz", "integrity": "sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.16.1", "@typescript-eslint/visitor-keys": "7.16.1" @@ -2427,6 +2430,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.1.tgz", "integrity": "sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "7.16.1", "@typescript-eslint/utils": "7.16.1", @@ -2454,6 +2458,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.1.tgz", "integrity": "sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -2467,6 +2472,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.1.tgz", "integrity": "sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "7.16.1", "@typescript-eslint/visitor-keys": "7.16.1", @@ -2495,6 +2501,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.1.tgz", "integrity": "sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.16.1", @@ -2517,6 +2524,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.1.tgz", "integrity": "sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.16.1", "eslint-visitor-keys": "^3.4.3" @@ -3216,6 +3224,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3461,6 +3470,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -4573,6 +4583,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -6118,16 +6129,17 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -6138,6 +6150,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -6220,6 +6233,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -6689,6 +6703,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -7332,6 +7347,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -8200,6 +8216,7 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -8209,6 +8226,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -9122,6 +9140,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10003,6 +10022,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10508,6 +10528,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -10536,9 +10557,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "license": "MIT", "engines": { diff --git a/src/main/MainRunner.ts b/src/main/MainRunner.ts index 803b03d..ea0f600 100644 --- a/src/main/MainRunner.ts +++ b/src/main/MainRunner.ts @@ -1,7 +1,8 @@ import { app, BrowserWindow, RenderProcessGoneDetails, BrowserWindowConstructorOptions } from 'electron' import Constants from './utils/Constants' import IPCs from './IPCs' -import { createTray, setWindowAutoHide, showWindow } from './tray.ts' +import { createTray, setWindowAutoHide } from './tray.ts' +import { moveToCurrentDesktop } from './desktop.ts' const options = { tray: true, @@ -45,10 +46,12 @@ export const createMainWindow = async (): Promise => { show: false, frame: false, fullscreenable: false, + hiddenInMissionControl: true, resizable: false, transparent: true, alwaysOnTop: true, webPreferences: { + ...Constants.DEFAULT_WEB_PREFERENCES, backgroundThrottling: false } } @@ -63,7 +66,7 @@ export const createMainWindow = async (): Promise => { }) mainWindow.webContents.on('did-frame-finish-load', (): void => { - if (Constants.IS_DEV_ENV) { + if (Constants.IS_DEV_ENV && Constants.IS_DEVTOOLS) { mainWindow.webContents.openDevTools() } }) @@ -81,6 +84,8 @@ export const createMainWindow = async (): Promise => { mainWindow.show() mainWindow.focus() mainWindow.setAlwaysOnTop(false) + + // moveToCurrentDesktop(mainWindow) }) } diff --git a/src/main/desktop.ts b/src/main/desktop.ts new file mode 100644 index 0000000..f23b00f --- /dev/null +++ b/src/main/desktop.ts @@ -0,0 +1,17 @@ +import { screen } from 'electron' + +// To detect proper desktop/workspace, find the display where the mouse cursor is +export function getDisplayNearestPoint(){ + return screen.getDisplayNearestPoint(screen.getCursorScreenPoint()); +} + +export function moveToCurrentDesktop(mainWindow){ + const currentDisplay = getDisplayNearestPoint(); +// Center window relatively to that display + const centerX = Math.round((currentDisplay.workArea.width - mainWindow.getBounds().width) / 2); + const centerY = Math.round((currentDisplay.workArea.height - mainWindow.getBounds().height) / 2); + mainWindow.setPosition(currentDisplay.workArea.x + centerX, currentDisplay.workArea.y + centerY); +} + + + diff --git a/src/main/tray.ts b/src/main/tray.ts index 6b6d3b8..4209031 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -1,6 +1,6 @@ -import { app, Menu, Tray, BaseWindow, BrowserWindow } from 'electron' +import { app, screen, Menu, Tray, BaseWindow, BrowserWindow } from 'electron' import Constants from './utils/Constants.ts' -const electron = require("electron"); +import { getDisplayNearestPoint } from './desktop.ts' // defaults // const width = 800; @@ -103,48 +103,29 @@ export function alignWindow(window: BaseWindow) { } function calculateWindowPosition() { - const margin = trayOptions.margin; + // To detect proper desktop/workspace, find the display where the mouse cursor is + const currentDisplay = getDisplayNearestPoint(); + console.log("currentDisplay.workArea=", currentDisplay.workArea); + + const margin = { + x: trayOptions.margin.x, // + currentDisplay.workArea.width, + y: trayOptions.margin.y // + currentDisplay.workArea.height + }; const b = trayOptions - const screenBounds = electron.screen.getPrimaryDisplay().size; + const screenBounds = screen.getPrimaryDisplay().size; const trayBounds = tray.getBounds(); - // where is the icon on the screen? - let trayPos = 4; // 1:top-left 2:top-right 3:bottom-left 4.bottom-right - trayPos = trayBounds.y > screenBounds.height / 2 ? trayPos : trayPos / 2; - trayPos = trayBounds.x > screenBounds.width / 2 ? trayPos : trayPos - 1; - let x = 0; - let y = 0 ; + const bottom = trayBounds.y > screenBounds.height / 2 ; + const x = Math.floor(trayBounds.x - b.width/2 - margin.x + trayBounds.width / 2); + const y = bottom ? + Math.floor(trayBounds.y - b.height - margin.y + trayBounds.height / 2) + : + Math.floor(trayBounds.y + margin.y + trayBounds.height / 2) + ; - // calculate the new window position - switch (trayPos) { - case 1: // for TOP - LEFT - x = Math.floor(trayBounds.x + margin.x + trayBounds.width / 2); - y = Math.floor(trayBounds.y + margin.y + trayBounds.height / 2); - break; - - case 2: // for TOP - RIGHT - x = Math.floor( - trayBounds.x - b.width - margin.x + trayBounds.width / 2 - ); - y = Math.floor(trayBounds.y + margin.y + trayBounds.height / 2); - break; - - case 3: // for BOTTOM - LEFT - x = Math.floor(trayBounds.x + margin.x + trayBounds.width / 2); - y = Math.floor( - trayBounds.y - b.height - margin.y + trayBounds.height / 2 - ); - break; - - case 4: // for BOTTOM - RIGHT - x = Math.floor( - trayBounds.x - b.width - margin.x + trayBounds.width / 2 - ); - y = Math.floor( - trayBounds.y - b.height - margin.y + trayBounds.height / 2 - ); - break; - } - - return { x, y }; + // constraint into screen + return { + x: Math.max(0, Math.min(screenBounds.width - b.width, x)), + y: Math.max(0, Math.min(screenBounds.height - b.height, y)) + }; } diff --git a/src/main/utils/Constants.ts b/src/main/utils/Constants.ts index 2a541ad..a97fbc7 100644 --- a/src/main/utils/Constants.ts +++ b/src/main/utils/Constants.ts @@ -12,6 +12,9 @@ export default class Constants { static IS_DEV_ENV = process.env.NODE_ENV === 'development' + // required IS_DEV_ENV + static IS_DEVTOOLS = true + static IS_MAC = process.platform === 'darwin' static DEFAULT_WEB_PREFERENCES = {