Skip to content

Commit 136d795

Browse files
huntiefacebook-github-bot
authored andcommitted
Implement saved window positioning per target (#53743)
Summary: Pull Request resolved: #53743 As titled. A long awaited quality of life improvement that we can now deliver with our desktop shell. Window arrangements are saved per [`windowKey`](https://github.com/facebook/react-native/blob/da7bf9c54567aae62ff355b79e66f511cb382065/packages/dev-middleware/src/middleware/openDebuggerMiddleware.js#L193), mapping to each previously opened debugger target. **Limitations** - Does not save/restore macOS fullscreen app state. Changelog: [Internal] Reviewed By: vzaidman Differential Revision: D82236159 fbshipit-source-id: e3c2f9c0cb05a3b8ef2208eb4a288e0be064489a
1 parent 88f3452 commit 136d795

File tree

4 files changed

+242
-13
lines changed

4 files changed

+242
-13
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
* @format
9+
*/
10+
11+
declare module 'electron-store' {
12+
declare export type Schema = any;
13+
14+
declare export type Options = {
15+
+name?: string,
16+
defaults?: Object,
17+
schema?: any,
18+
migrations?: any,
19+
beforeEachMigration?: any,
20+
clearInvalidConfig?: boolean,
21+
serialize?: any,
22+
deserialize?: any,
23+
accessPropertiesByDotNotation?: boolean,
24+
watch?: boolean,
25+
encryptionKey?: string | Buffer | $ReadOnlyArray<number>,
26+
...
27+
};
28+
29+
declare class ElectronStore {
30+
constructor(options?: Options): this;
31+
get(key: string): any;
32+
get(key: string, defaultValue: any): any;
33+
set(key: string, value: any): void;
34+
set(object: Object): void;
35+
has(key: string): boolean;
36+
delete(key: string): void;
37+
clear(): void;
38+
}
39+
40+
declare module.exports: Class<ElectronStore>;
41+
}

packages/debugger-shell/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
},
3636
"devDependencies": {
3737
"electron": "37.2.6",
38+
"electron-store": "^8.2.0",
3839
"semver": "^7.1.3"
3940
},
4041
"files": [

packages/debugger-shell/src/electron/MainInstanceEntryPoint.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010

1111
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
1212
const {BrowserWindow, Menu, app, shell, ipcMain} = require('electron') as any;
13+
const Store = require('electron-store');
1314
const path = require('path');
1415
const util = require('util');
1516

17+
const appSettings = new Store();
1618
const windowMetadata = new WeakMap<
1719
typeof BrowserWindow,
1820
$ReadOnly<{
@@ -53,10 +55,11 @@ function handleLaunchArgs(argv: string[]) {
5355
}, 1000);
5456
}
5557
} else {
56-
// Create the browser window.
5758
frontendWindow = new BrowserWindow({
58-
width: 1200,
59-
height: 600,
59+
...(getSavedWindowPosition(windowKey) ?? {
60+
width: 1200,
61+
height: 600,
62+
}),
6063
webPreferences: {
6164
partition: 'persist:react-native-devtools',
6265
preload: require.resolve('./preload.js'),
@@ -66,6 +69,8 @@ function handleLaunchArgs(argv: string[]) {
6669
});
6770
// Auto-hide the Windows/Linux menu bar
6871
frontendWindow.setMenuBarVisibility(false);
72+
// Observe and update saved window position
73+
setupWindowResizeListeners(frontendWindow, windowKey);
6974
}
7075

7176
// Open links in the default browser instead of in new Electron windows.
@@ -119,6 +124,37 @@ function configureAppMenu() {
119124
Menu.setApplicationMenu(menu);
120125
}
121126

127+
function getSavedWindowPosition(
128+
windowKey: string,
129+
): ?{width: number, height: number, x?: number, y?: number} {
130+
return appSettings.get('windowArrangements', {})[windowKey];
131+
}
132+
133+
function saveWindowPosition(
134+
windowKey: string,
135+
position: {x: number, y: number, width: number, height: number},
136+
) {
137+
const windowArrangements = appSettings.get('windowArrangements', {});
138+
windowArrangements[windowKey] = position;
139+
appSettings.set('windowArrangements', windowArrangements);
140+
}
141+
142+
function setupWindowResizeListeners(
143+
browserWindow: typeof BrowserWindow,
144+
windowKey: string,
145+
) {
146+
const savePosition = () => {
147+
if (!browserWindow.isDestroyed()) {
148+
const [x, y] = browserWindow.getPosition();
149+
const [width, height] = browserWindow.getSize();
150+
saveWindowPosition(windowKey, {x, y, width, height});
151+
}
152+
};
153+
browserWindow.on('moved', savePosition);
154+
browserWindow.on('resized', savePosition);
155+
browserWindow.on('closed', savePosition);
156+
}
157+
122158
app.whenReady().then(() => {
123159
handleLaunchArgs(process.argv.slice(app.isPackaged ? 1 : 2));
124160
configureAppMenu();

0 commit comments

Comments
 (0)