From d2414c286f0ed972dd9bbe1c87b7bbae89fd1bf6 Mon Sep 17 00:00:00 2001 From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com> Date: Mon, 15 Apr 2024 17:15:18 -0400 Subject: [PATCH] Fix settings window disappearing on macOS when dragged to another monitor (#3006) * Fix settings window disappearing on macOS when dragged to another monitor * Force other windows to show on the same screen as the main window when created * Try to center the window relative to the main window * Fix test --- src/main/app/app.ts | 6 +++- src/main/app/utils.test.js | 38 +++++++++++++++++++++++- src/main/app/utils.ts | 46 ++++++++++++++++++------------ src/main/windows/settingsWindow.ts | 1 - 4 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/main/app/app.ts b/src/main/app/app.ts index b837518d..e8dd4f90 100644 --- a/src/main/app/app.ts +++ b/src/main/app/app.ts @@ -50,7 +50,11 @@ export function handleAppBrowserWindowCreated(event: Event, newWindow: BrowserWi log.debug('handleAppBrowserWindowCreated'); // Screen cannot be required before app is ready - resizeScreen(newWindow); + if (app.isReady()) { + resizeScreen(newWindow); + } else { + newWindow.once('restore', () => resizeScreen(newWindow)); + } } export function handleAppWillFinishLaunching() { diff --git a/src/main/app/utils.test.js b/src/main/app/utils.test.js index 6bdad6b3..5ae19925 100644 --- a/src/main/app/utils.test.js +++ b/src/main/app/utils.test.js @@ -7,6 +7,7 @@ import {dialog, screen} from 'electron'; import JsonFileManager from 'common/JsonFileManager'; import {updatePaths} from 'main/constants'; +import MainWindow from 'main/windows/mainWindow'; import {getDeeplinkingURL, resizeScreen, migrateMacAppStore} from './utils'; @@ -52,7 +53,10 @@ jest.mock('main/menus/app', () => ({})); jest.mock('main/menus/tray', () => ({})); jest.mock('main/tray/tray', () => ({})); jest.mock('main/views/viewManager', () => ({})); -jest.mock('main/windows/mainWindow', () => ({})); +jest.mock('main/windows/mainWindow', () => ({ + get: jest.fn(), + getSize: jest.fn(), +})); jest.mock('./initialize', () => ({ mainProtocol: 'mattermost', @@ -130,6 +134,38 @@ describe('main/app/utils', () => { expect(browserWindow.setPosition).not.toHaveBeenCalled(); expect(browserWindow.center).toHaveBeenCalled(); }); + + it('should snap to main window if it exists', () => { + MainWindow.get.mockReturnValue({ + getPosition: () => [450, 350], + getSize: () => [1280, 720], + }); + const browserWindow = { + getPosition: () => [500, 400], + getSize: () => [1280, 720], + setPosition: jest.fn(), + center: jest.fn(), + once: jest.fn(), + }; + resizeScreen(browserWindow); + expect(browserWindow.setPosition).toHaveBeenCalledWith(450, 350); + }); + + it('should snap to the middle of the main window', () => { + MainWindow.get.mockReturnValue({ + getPosition: () => [450, 350], + getSize: () => [1280, 720], + }); + const browserWindow = { + getPosition: () => [500, 400], + getSize: () => [800, 600], + setPosition: jest.fn(), + center: jest.fn(), + once: jest.fn(), + }; + resizeScreen(browserWindow); + expect(browserWindow.setPosition).toHaveBeenCalledWith(690, 410); + }); }); describe('migrateMacAppStore', () => { diff --git a/src/main/app/utils.ts b/src/main/app/utils.ts index 12200e68..6a54d32d 100644 --- a/src/main/app/utils.ts +++ b/src/main/app/utils.ts @@ -144,26 +144,36 @@ function getValidWindowPosition(state: Rectangle) { return {x: state.x, y: state.y}; } -export function resizeScreen(browserWindow: BrowserWindow) { - function handle() { - log.debug('resizeScreen.handle'); - const position = browserWindow.getPosition(); - const size = browserWindow.getSize(); - const validPosition = getValidWindowPosition({ - x: position[0], - y: position[1], - width: size[0], - height: size[1], - }); - if (typeof validPosition.x !== 'undefined' || typeof validPosition.y !== 'undefined') { - browserWindow.setPosition(validPosition.x || 0, validPosition.y || 0); - } else { - browserWindow.center(); - } +function getNewWindowPosition(browserWindow: BrowserWindow) { + const mainWindow = MainWindow.get(); + if (!mainWindow) { + return browserWindow.getPosition(); } - browserWindow.once('restore', handle); - handle(); + const newWindowSize = browserWindow.getSize(); + const mainWindowSize = mainWindow.getSize(); + const mainWindowPosition = mainWindow.getPosition(); + + return [ + mainWindowPosition[0] + ((mainWindowSize[0] - newWindowSize[0]) / 2), + mainWindowPosition[1] + ((mainWindowSize[1] - newWindowSize[1]) / 2), + ]; +} + +export function resizeScreen(browserWindow: BrowserWindow) { + const position = getNewWindowPosition(browserWindow); + const size = browserWindow.getSize(); + const validPosition = getValidWindowPosition({ + x: position[0], + y: position[1], + width: size[0], + height: size[1], + }); + if (typeof validPosition.x !== 'undefined' || typeof validPosition.y !== 'undefined') { + browserWindow.setPosition(validPosition.x || 0, validPosition.y || 0); + } else { + browserWindow.center(); + } } export function flushCookiesStore() { diff --git a/src/main/windows/settingsWindow.ts b/src/main/windows/settingsWindow.ts index 76ec6df0..bb6d16b8 100644 --- a/src/main/windows/settingsWindow.ts +++ b/src/main/windows/settingsWindow.ts @@ -46,7 +46,6 @@ export class SettingsWindow { const preload = getLocalPreload('internalAPI.js'); const spellcheck = (typeof Config.useSpellChecker === 'undefined' ? true : Config.useSpellChecker); this.win = new BrowserWindow({ - parent: mainWindow, title: 'Desktop App Settings', fullscreen: false, webPreferences: {