1 | 'use strict';
|
2 |
|
3 | var path = require('path');
|
4 | var electron = require('electron');
|
5 | var jsonfile = require('jsonfile');
|
6 | var mkdirp = require('mkdirp');
|
7 | var deepEqual = require('deep-equal');
|
8 |
|
9 | module.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 |
|
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 |
|
91 | if (win) {
|
92 | updateState(win);
|
93 | }
|
94 |
|
95 |
|
96 | try {
|
97 | mkdirp.sync(path.dirname(fullStoreFileName));
|
98 | jsonfile.writeFileSync(fullStoreFileName, state);
|
99 | } catch (err) {
|
100 |
|
101 | }
|
102 | }
|
103 |
|
104 | function stateChangeHandler() {
|
105 |
|
106 | clearTimeout(stateChangeTimer);
|
107 | stateChangeTimer = setTimeout(updateState, eventHandlingDelay);
|
108 | }
|
109 |
|
110 | function closeHandler() {
|
111 | updateState();
|
112 | }
|
113 |
|
114 | function closedHandler() {
|
115 |
|
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 |
|
146 | try {
|
147 | state = jsonfile.readFileSync(fullStoreFileName);
|
148 | } catch (err) {
|
149 |
|
150 | }
|
151 |
|
152 |
|
153 | validateState();
|
154 |
|
155 |
|
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 | };
|