-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Preserve window state between sessions
ngjermundshaug edited this page Feb 11, 2016
·
15 revisions
First you need to hide the window until your app loads previous state, so be sure you got in package.json this line:
{
"window": {
"show": false
}
}
Then you can restore your previously saved window state. You can use this library as it is, or make similar solution fitting your own needs.
winstate.js library:
'use strict'
/**
* https://github.com/nwjs/nw.js/wiki/Preserve-window-state-between-sessions
*
* Cross-platform window state preservation.
* Yes this code is quite complicated, but this is the best I came up with for
* current state of node-webkit Window API (v0.7.3 and later).
*
* Known issues:
* - Unmaximization not always sets the window (x, y) in the lastly used coordinates.
* - Unmaximization animation sometimes looks wierd.
* - Extra height added to window, at least in linux x64 gnome-shell env. It seems that
* when we read height then it returns it with window frame, but if we resize window
* then it applies dimensions only to internal document without external frame.
* Need to test in other environments with different visual themes.
*
* Change log:
* 2013-12-01
* - Workaround of extra height in gnome-shell added.
*
* 2014-03-22
* - Repared workaround (from 2013-12-01) behaviour when use frameless window.
* Now it works correctly.
* 2014-10-02
* - Fixed cannot set windowState of null error when attempting to set localStorage
*
* 2015-03-05
* - Don't call window.show() if dev tools are already open (see initWindowState).
*
* 2015-06-15
* - Don't resize the window when using LiveReload.
*/
var gui = require('nw.gui');
var win = gui.Window.get();
var winState;
var currWinMode;
var resizeTimeout;
var isMaximizationEvent = false;
// extra height added in linux x64 gnome-shell env, use it as workaround
var deltaHeight = gui.App.manifest.window.frame ? 0 : 'disabled';
function initWindowState() {
// Don't resize the window when using LiveReload.
// There seems to be no way to check whether a window was reopened, so let's
// check for dev tools - they can't be open on the app start, so if
// dev tools are open, LiveReload was used.
if (!win.isDevToolsOpen()) {
winState = JSON.parse(localStorage.windowState || 'null');
if (winState) {
currWinMode = winState.mode;
if (currWinMode === 'maximized') {
win.maximize();
} else {
restoreWindowState();
}
} else {
currWinMode = 'normal';
dumpWindowState();
}
win.show();
}
}
function dumpWindowState() {
if (!winState) {
winState = {};
}
// we don't want to save minimized state, only maximized or normal
if (currWinMode === 'maximized') {
winState.mode = 'maximized';
} else {
winState.mode = 'normal';
}
// when window is maximized you want to preserve normal
// window dimensions to restore them later (even between sessions)
if (currWinMode === 'normal') {
winState.x = win.x;
winState.y = win.y;
winState.width = win.width;
winState.height = win.height;
// save delta only of it is not zero
if (deltaHeight !== 'disabled' && deltaHeight !== 0 && currWinMode !== 'maximized') {
winState.deltaHeight = deltaHeight;
}
}
}
function restoreWindowState() {
// deltaHeight already saved, so just restore it and adjust window height
if (deltaHeight !== 'disabled' && typeof winState.deltaHeight !== 'undefined') {
deltaHeight = winState.deltaHeight
winState.height = winState.height - deltaHeight
}
//Make sure that the window is displayed somewhere on a screen that is connected to the PC.
//Imagine you run the program on a secondary screen connected to a laptop - and then the next time you start the
//program the screen is not connected...
gui.Screen.Init();
var screens = gui.Screen.screens;
var locationIsOnAScreen = false;
for (var i = 0; i < screens.length; i++) {
var screen = screens[i];
if (winState.x > screen.bounds.x && winState.x < screen.bounds.x + screen.bounds.width) {
if (winState.y > screen.bounds.y && winState.y < screen.bounds.y + screen.bounds.height) {
console.debug("Location of window (" + winState.x + "," + winState.y + ") is on screen " + JSON.stringify(screen));
locationIsOnAScreen = true;
}
}
}
if (!locationIsOnAScreen) {
console.debug("Last saved position of windows is not usable on current monitor setup. Moving window to center!");
win.setPosition("center");
}
else {
win.resizeTo(winState.width, winState.height);
win.moveTo(winState.x, winState.y);
}
}
function saveWindowState() {
dumpWindowState();
localStorage['windowState'] = JSON.stringify(winState);
}
initWindowState();
win.on('maximize', function () {
isMaximizationEvent = true;
currWinMode = 'maximized';
});
win.on('unmaximize', function () {
currWinMode = 'normal';
restoreWindowState();
});
win.on('minimize', function () {
currWinMode = 'minimized';
});
win.on('restore', function () {
currWinMode = 'normal';
});
win.window.addEventListener('resize', function () {
// resize event is fired many times on one resize action,
// this hack with setTiemout forces it to fire only once
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function () {
// on MacOS you can resize maximized window, so it's no longer maximized
if (isMaximizationEvent) {
// first resize after maximization event should be ignored
isMaximizationEvent = false;
} else {
if (currWinMode === 'maximized') {
currWinMode = 'normal';
}
}
// there is no deltaHeight yet, calculate it and adjust window size
if (deltaHeight !== 'disabled' && deltaHeight === false) {
deltaHeight = win.height - winState.height;
// set correct size
if (deltaHeight !== 0) {
win.resizeTo(winState.width, win.height - deltaHeight);
}
}
dumpWindowState();
}, 500);
}, false);
win.on('close', function () {
try {
saveWindowState();
} catch(err) {
console.log("winstateError: " + err);
}
this.close(true);
});
Then connect library to HTML file, which you used in "main"
option of package.json:
<!-- use your own path -->
<script src="lib/winstate.js"></script>