Skip to content

Commit 1d0d1bc

Browse files
Merge pull request #1248 from NordicSemiconductor/feat/per-app-window-settings
Feat/per app window settings
2 parents 08ab92a + 50a5633 commit 1d0d1bc

File tree

3 files changed

+85
-42
lines changed

3 files changed

+85
-42
lines changed

Changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## 5.3.0 - unreleased
22

3+
### Added
4+
5+
- Restore window positions per app at startup.
6+
37
### Changed
48

59
- Updated bundled SEGGER J-Link to v8.76 for Windows.

src/common/persistedStore.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import packageJson from '../../package.json';
1010
import type { TokenInformation } from '../ipc/artifactoryToken';
1111
import type { SourceName } from './sources';
1212

13-
type WindowState = {
13+
export type WindowState = {
1414
x?: number;
1515
y?: number;
1616
width: number;
@@ -26,7 +26,7 @@ export type ShownStates = {
2626
interface Schema {
2727
lastBundledAppInstalledVersion: string;
2828
isQuickStartInfoShownBefore: boolean;
29-
lastWindowState: WindowState;
29+
[lastWindowState: `lastWindowState.${string}`]: WindowState;
3030
updateCheck: {
3131
doOnStartup: boolean;
3232
lastUpdate?: Date;
@@ -49,15 +49,30 @@ const store = new Store<Schema>();
4949

5050
export const resetStore = () => store.clear();
5151

52-
const defaultWindowSize = {
52+
export const windowSizeLauncherKey = 'Launcher';
53+
const defaultAppWindowSize = {
5354
width: 1024,
5455
height: 800,
5556
maximized: false,
5657
};
57-
export const getLastWindowState = () =>
58-
store.get('lastWindowState', defaultWindowSize);
59-
export const setLastWindowState = (lastWindowState: WindowState) =>
60-
store.set('lastWindowState', lastWindowState);
58+
const defaultLauncherWindowSize = {
59+
width: 760,
60+
height: 600,
61+
maximized: false,
62+
};
63+
64+
export const getLastWindowStateLegacy = (app: string) => {
65+
if (app === windowSizeLauncherKey) {
66+
return defaultLauncherWindowSize;
67+
}
68+
// Use old 'lastWindowState' as backup for some versions so people don't suddenly jump to non-persisted size
69+
return store.get('lastWindowState', defaultAppWindowSize);
70+
};
71+
72+
export const getLastWindowState = (app: string) =>
73+
store.get(`lastWindowState.${app}`, getLastWindowStateLegacy(app));
74+
export const setLastWindowState = (app: string, lastWindowState: WindowState) =>
75+
store.set(`lastWindowState.${app}`, lastWindowState);
6176

6277
export const getCheckForUpdatesAtStartup = () =>
6378
store.get('updateCheck')?.doOnStartup ?? true;

src/main/windows.ts

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
import {
1313
app as electronApp,
1414
BrowserWindow,
15-
type Rectangle,
1615
screen,
1716
type WebContents,
1817
} from 'electron';
@@ -22,6 +21,8 @@ import packageJson from '../../package.json';
2221
import {
2322
getLastWindowState,
2423
setLastWindowState,
24+
windowSizeLauncherKey,
25+
type WindowState,
2526
} from '../common/persistedStore';
2627
import { LOCAL } from '../common/sources';
2728
import {
@@ -52,13 +53,59 @@ export const openLauncherWindow = () => {
5253
}
5354
};
5455

56+
const keepPositionWithinBounds = ({ x, y, height, width }: WindowState) => {
57+
if (x && y) {
58+
const { bounds } = screen.getDisplayMatching({
59+
x,
60+
y,
61+
width,
62+
height,
63+
});
64+
const left = Math.max(x, bounds.x);
65+
const top = Math.max(y, bounds.y);
66+
const right = Math.min(x + width, bounds.x + bounds.width);
67+
const bottom = Math.min(y + height, bounds.y + bounds.height);
68+
if (left > right || top > bottom) {
69+
// the window would be off screen
70+
return {};
71+
}
72+
}
73+
74+
return { x, y };
75+
};
76+
77+
const maximizeWindow = (window: BrowserWindow) => {
78+
window.webContents.on('did-finish-load', () => {
79+
window.maximize();
80+
});
81+
};
82+
83+
const storeWindowPositionOnClose = (window: BrowserWindow, appName: string) => {
84+
window.on('close', () => {
85+
const bounds = window.getBounds();
86+
setLastWindowState(appName, {
87+
x: bounds.x,
88+
y: bounds.y,
89+
width: bounds.width,
90+
height: bounds.height,
91+
maximized: window.isMaximized(),
92+
});
93+
});
94+
};
95+
5596
const createLauncherWindow = () => {
97+
const lastWindowState = getLastWindowState(windowSizeLauncherKey);
98+
99+
const { x, y } = keepPositionWithinBounds(lastWindowState);
100+
const { width, height } = lastWindowState;
56101
const window = createWindow({
57102
title: `nRF Connect for Desktop v${packageJson.version}`,
58103
url: `file://${getBundledResourcePath()}/launcher.html`,
59104
icon: getNrfConnectForDesktopIcon(),
60-
width: 760,
61-
height: 600,
105+
x,
106+
y,
107+
width,
108+
height,
62109
minHeight: 500,
63110
minWidth: 600,
64111
center: true,
@@ -67,6 +114,10 @@ const createLauncherWindow = () => {
67114

68115
registerLauncherWindowFromMain(window);
69116

117+
if (lastWindowState.maximized) maximizeWindow(window);
118+
119+
storeWindowPositionOnClose(window, windowSizeLauncherKey);
120+
70121
window.on('close', event => {
71122
if (appWindows.length > 0) {
72123
event.preventDefault();
@@ -105,26 +156,11 @@ const getSizeOptions = (app: LaunchableApp) => {
105156
};
106157
}
107158

108-
const lastWindowState = getLastWindowState();
159+
const lastWindowState = getLastWindowState(app.name);
109160

110-
let { x, y } = lastWindowState;
161+
const { x, y } = keepPositionWithinBounds(lastWindowState);
111162
const { width, height } = lastWindowState;
112163

113-
if (x && y) {
114-
const { bounds } = screen.getDisplayMatching(
115-
lastWindowState as Rectangle,
116-
);
117-
const left = Math.max(x, bounds.x);
118-
const top = Math.max(y, bounds.y);
119-
const right = Math.min(x + width, bounds.x + bounds.width);
120-
const bottom = Math.min(y + height, bounds.y + bounds.height);
121-
if (left > right || top > bottom) {
122-
// the window would be off screen, let's open it where the launcher is
123-
x = undefined;
124-
y = undefined;
125-
}
126-
}
127-
128164
return {
129165
x,
130166
y,
@@ -163,22 +199,10 @@ export const openAppWindow = (app: LaunchableApp, args: string[]) => {
163199
});
164200

165201
if (!isQuickStartApp(app)) {
166-
appWindow.webContents.on('did-finish-load', () => {
167-
if (getLastWindowState().maximized) {
168-
appWindow.maximize();
169-
}
170-
});
202+
const isMaximized = getLastWindowState(app.name).maximized;
203+
if (isMaximized) maximizeWindow(appWindow);
171204

172-
appWindow.on('close', () => {
173-
const bounds = appWindow.getBounds();
174-
setLastWindowState({
175-
x: bounds.x,
176-
y: bounds.y,
177-
width: bounds.width,
178-
height: bounds.height,
179-
maximized: appWindow.isMaximized(),
180-
});
181-
});
205+
storeWindowPositionOnClose(appWindow, app.name);
182206
}
183207

184208
let reloading = false;

0 commit comments

Comments
 (0)