UNPKG

4.42 kBJavaScriptView Raw
1'use strict';
2
3var path = require('path');
4var electron = require('electron');
5var jsonfile = require('jsonfile');
6var mkdirp = require('mkdirp');
7var deepEqual = require('deep-equal');
8
9module.exports = function (options) {
10 var app = electron.app;
11 var screen = electron.screen;
12 var state;
13 var winRef;
14 var stateChangeTimer;
15 var eventHandlingDelay = 100;
16 var config = Object.assign({
17 file: 'window-state.json',
18 path: app.getPath('userData'),
19 maximize: true,
20 fullScreen: true
21 }, options);
22 var fullStoreFileName = path.join(config.path, config.file);
23
24 function isNormal(win) {
25 return !win.isMaximized() && !win.isMinimized() && !win.isFullScreen();
26 }
27
28 function hasBounds() {
29 return state &&
30 Number.isInteger(state.x) &&
31 Number.isInteger(state.y) &&
32 Number.isInteger(state.width) &&
33 Number.isInteger(state.height);
34 }
35
36 function validateState() {
37 var isValid = state && (hasBounds() || state.isMaximized || state.isFullScreen);
38 if (!isValid) {
39 state = null;
40 return;
41 }
42
43 if (hasBounds() && state.displayBounds) {
44 // Check if the display where the window was last open is still available
45 var displayBounds = screen.getDisplayMatching(state).bounds;
46 var sameBounds = deepEqual(state.displayBounds, displayBounds, {strict: true});
47 if (!sameBounds) {
48 if (displayBounds.width < state.displayBounds.width) {
49 if (state.x > displayBounds.width) {
50 state.x = 0;
51 }
52
53 if (state.width > displayBounds.width) {
54 state.width = displayBounds.width;
55 }
56 }
57
58 if (displayBounds.height < state.displayBounds.height) {
59 if (state.y > displayBounds.height) {
60 state.y = 0;
61 }
62
63 if (state.height > displayBounds.height) {
64 state.height = displayBounds.height;
65 }
66 }
67 }
68 }
69 }
70
71 function updateState(win) {
72 win = win || winRef;
73 if (!win) {
74 return;
75 }
76
77 var winBounds = win.getBounds();
78 if (isNormal(win)) {
79 state.x = winBounds.x;
80 state.y = winBounds.y;
81 state.width = winBounds.width;
82 state.height = winBounds.height;
83 }
84 state.isMaximized = win.isMaximized();
85 state.isFullScreen = win.isFullScreen();
86 state.displayBounds = screen.getDisplayMatching(winBounds).bounds;
87 }
88
89 function saveState(win) {
90 // Update window state only if it was provided
91 if (win) {
92 updateState(win);
93 }
94
95 // Save state
96 try {
97 mkdirp.sync(path.dirname(fullStoreFileName));
98 jsonfile.writeFileSync(fullStoreFileName, state);
99 } catch (err) {
100 // Don't care
101 }
102 }
103
104 function stateChangeHandler() {
105 // Handles both 'resize' and 'move'
106 clearTimeout(stateChangeTimer);
107 stateChangeTimer = setTimeout(updateState, eventHandlingDelay);
108 }
109
110 function closeHandler() {
111 updateState();
112 }
113
114 function closedHandler() {
115 // Unregister listeners and save state
116 unmanage();
117 saveState();
118 }
119
120 function manage(win) {
121 if (config.maximize && state.isMaximized) {
122 win.maximize();
123 }
124 if (config.fullScreen && state.isFullScreen) {
125 win.setFullScreen(true);
126 }
127 win.on('resize', stateChangeHandler);
128 win.on('move', stateChangeHandler);
129 win.on('close', closeHandler);
130 win.on('closed', closedHandler);
131 winRef = win;
132 }
133
134 function unmanage() {
135 if (winRef) {
136 winRef.removeListener('resize', stateChangeHandler);
137 winRef.removeListener('move', stateChangeHandler);
138 clearTimeout(stateChangeTimer);
139 winRef.removeListener('close', closeHandler);
140 winRef.removeListener('closed', closedHandler);
141 winRef = null;
142 }
143 }
144
145 // Load previous state
146 try {
147 state = jsonfile.readFileSync(fullStoreFileName);
148 } catch (err) {
149 // Don't care
150 }
151
152 // Check state validity
153 validateState();
154
155 // Set state fallback values
156 state = Object.assign({
157 width: config.defaultWidth || 800,
158 height: config.defaultHeight || 600
159 }, state);
160
161 return {
162 get x() { return state.x; },
163 get y() { return state.y; },
164 get width() { return state.width; },
165 get height() { return state.height; },
166 get isMaximized() { return state.isMaximized; },
167 get isFullScreen() { return state.isFullScreen; },
168 saveState: saveState,
169 unmanage: unmanage,
170 manage: manage
171 };
172};