Skip to content

Instantly share code, notes, and snippets.

@medmunds
Created May 9, 2015 00:41
Show Gist options
  • Save medmunds/fb1cd6b370a6cec5d618 to your computer and use it in GitHub Desktop.
Save medmunds/fb1cd6b370a6cec5d618 to your computer and use it in GitHub Desktop.
Save and restore window state for Electron (Atom-Shell)
// Preserve and restore window state in localStorage.
// Adapted for Electron from nw.js:
// https://github.com/nwjs/nw.js/wiki/Preserve-window-state-between-sessions
//
// As written, it only handles a single-window app.
//
// This code is meant to run in the renderer process.
// To use, load from index.html (or whatever file you loadUrl into your BrowserWindow):
// <script src="winstate.js"></script>
// Ported code:
'use strict';
/**
* 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:
* 2015-05-08
* - Electron (atom-shell) port
*
* 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).
*/
var remote = require('remote');
var win = remote.getCurrentWindow();
var localStorageKey = 'windowState'; // you could include win.id for a multi-window app
var winState;
var currWinMode;
var resizeTimeout;
var isMaximizationEvent = false;
// extra height added in linux x64 gnome-shell env, use it as workaround
var deltaHeight = (function () {
// TODO: not sure how to find out if BrowserWindow is frameless
// TODO: (also not sure if this workaround is needed in Electron)
// use deltaHeight only in windows with frame enabled
// if (gui.App.manifest.window.frame) return true; else return 'disabled';
return true;
})();
function initWindowState() {
winState = JSON.parse(localStorage[localStorageKey] || 'null');
if (winState) {
currWinMode = winState.mode;
if (currWinMode === 'maximized') {
win.maximize();
} else {
restoreWindowState();
}
} else {
currWinMode = 'normal';
if (deltaHeight !== 'disabled') deltaHeight = 0;
dumpWindowState();
}
// On Windows win.show() also acts like win.requestAttention().
// If you use LiveReload, it becomes annoying when your app is already open
// but starts to blink in the taskbar on changes.
// There seems to be no way to check if a window is open, so let's at least
// check for dev tools.
if (!win.isDevToolsOpened()) {
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') {
var pos = win.getPosition(),
size = win.getSize();
winState.x = pos[0];
winState.y = pos[1];
winState.width = size[0];
winState.height = size[1];
// 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;
}
win.setSize(winState.width, winState.height);
win.setPosition(winState.x, winState.y);
}
function saveWindowState() {
dumpWindowState();
localStorage[localStorageKey] = 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';
});
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) {
var size = win.getSize(),
width = size[0],
height = size[1];
deltaHeight = height - winState.height;
// set correct size
if (deltaHeight !== 0) {
win.resizeTo(width, height - deltaHeight);
}
}
dumpWindowState();
}, 500);
}, false);
win.on('close', function () {
try {
saveWindowState();
} catch(err) {
console.log("winstateError: " + err);
}
this.close(true);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment