@@ -10,103 +10,111 @@ export interface WindowState {
1010 displayBounds : Electron . Rectangle
1111}
1212
13+ function isWithinBounds ( bounds : Electron . Rectangle , state : Partial < Electron . Rectangle > ) : boolean {
14+ return (
15+ ! ! state &&
16+ ! ! bounds &&
17+ state . x >= bounds . x &&
18+ state . y >= bounds . y &&
19+ state . x + state . width <= bounds . x + bounds . width &&
20+ state . y + state . height <= bounds . y + bounds . height
21+ )
22+ }
23+
24+ function isRectangle ( bounds : Partial < Electron . Rectangle > ) : bounds is Electron . Rectangle {
25+ return (
26+ ! ! bounds &&
27+ Number . isInteger ( bounds . x ) &&
28+ Number . isInteger ( bounds . y ) &&
29+ Number . isInteger ( bounds . width ) &&
30+ bounds . width > 0 &&
31+ Number . isInteger ( bounds . height ) &&
32+ bounds . height > 0
33+ )
34+ }
35+
36+ function isStateValid ( state : Partial < WindowState > ) {
37+ if ( ! state ) {
38+
39+ return false
40+ }
41+ if ( ! isRectangle ( state . displayBounds ) ) {
42+
43+ return false
44+ }
45+ if ( ! isRectangle ( state ) ) {
46+ return false
47+ }
48+ const display = screen . getAllDisplays ( ) . find ( ( it ) => isWithinBounds ( it . bounds , state ) )
49+ return ! ! display
50+ }
51+
52+ function createDefaultState ( bounds : Partial < Electron . Rectangle > ) : WindowState {
53+ return {
54+ width : 800 ,
55+ height : 600 ,
56+ x : 0 ,
57+ y : 0 ,
58+ displayBounds : screen . getPrimaryDisplay ( ) . bounds ,
59+ ...( bounds || { } ) ,
60+ }
61+ }
62+
1363export function windowState ( options : {
14- defaultWidth : number
15- defaultHeight : number
64+ defaultWidth ? : number
65+ defaultHeight ? : number
1666 save : ( state : Partial < WindowState > ) => void
1767 load : ( ) => Partial < WindowState >
1868} ) {
1969 let state : Partial < WindowState > = { }
2070 let winRef : BrowserWindow
21- let stateChangeTimer
71+ let stateChangeTimer : any
2272 const eventHandlingDelay = 100
2373 const config = {
2474 maximize : true ,
2575 fullScreen : true ,
26- defaultWidth : options . defaultWidth ,
27- defaultHeight : options . defaultHeight ,
76+ defaultWidth : options . defaultWidth || 800 ,
77+ defaultHeight : options . defaultHeight || 600 ,
2878 }
2979
30- function isNormal ( win ) {
31- return ! win . isMaximized ( ) && ! win . isMinimized ( ) && ! win . isFullScreen ( )
32- }
33-
34- function hasBounds ( ) {
35- return (
36- state &&
37- Number . isInteger ( state . x ) &&
38- Number . isInteger ( state . y ) &&
39- Number . isInteger ( state . width ) &&
40- state . width > 0 &&
41- Number . isInteger ( state . height ) &&
42- state . height > 0
43- )
44- }
45-
46- function resetStateToDefault ( ) {
47- const displayBounds = screen . getPrimaryDisplay ( ) . bounds
48-
49- // Reset state to default values on the primary display
50- state = {
51- width : config . defaultWidth || 800 ,
52- height : config . defaultHeight || 600 ,
53- x : 0 ,
54- y : 0 ,
55- displayBounds,
56- }
80+ // Load previous state
81+ try {
82+ state = ( options . load ( ) || { } ) as any
83+ } catch ( err ) {
84+ console . error ( err )
85+ state = { }
5786 }
5887
59- function windowWithinBounds ( bounds ) : boolean {
60- return (
61- ! ! state && ! ! bounds &&
62- state . x >= bounds . x &&
63- state . y >= bounds . y &&
64- state . x + state . width <= bounds . x + bounds . width &&
65- state . y + state . height <= bounds . y + bounds . height
66- )
88+ // Set state fallback values
89+ state = {
90+ width : config . defaultWidth || 800 ,
91+ height : config . defaultHeight || 600 ,
92+ ...( state || { } ) ,
6793 }
6894
69- function ensureWindowVisibleOnSomeDisplay ( ) {
70- const visible = screen . getAllDisplays ( ) . some ( ( display ) => {
71- return windowWithinBounds ( display . bounds )
95+ function resetState ( ) {
96+ state = createDefaultState ( {
97+ width : config . defaultWidth ,
98+ height : config . defaultHeight ,
7299 } )
73-
74- if ( ! visible ) {
75- // Window is partially or fully not visible now.
76- // Reset it to safe defaults.
77- return resetStateToDefault ( )
78- }
79100 }
80101
81- function validateState ( ) {
82- const isValid = state && ( hasBounds ( ) || state . isMaximized || state . isFullScreen )
83- if ( ! isValid ) {
84- state = { }
85- return
86- }
87-
88- if ( hasBounds ( ) && state . displayBounds ) {
89- ensureWindowVisibleOnSomeDisplay ( )
90- }
91- }
92-
93- function updateState ( win ?: BrowserWindow ) {
94- win = win || winRef
102+ function updateState ( win : BrowserWindow = winRef ) {
95103 if ( ! win ) {
96104 return
97105 }
98106 // Don't throw an error when window was closed
99107 try {
100- const winBounds = win . getBounds ( )
101- if ( isNormal ( win ) ) {
102- state . x = winBounds . x
103- state . y = winBounds . y
104- state . width = winBounds . width
105- state . height = winBounds . height
108+ const bounds = win . getBounds ( )
109+ if ( ! win . isMaximized ( ) && ! win . isMinimized ( ) && ! win . isFullScreen ( ) ) {
110+ state . x = bounds . x
111+ state . y = bounds . y
112+ state . width = bounds . width
113+ state . height = bounds . height
106114 }
107115 state . isMaximized = win . isMaximized ( )
108116 state . isFullScreen = win . isFullScreen ( )
109- state . displayBounds = screen . getDisplayMatching ( winBounds ) . bounds
117+ state . displayBounds = screen . getDisplayMatching ( bounds ) . bounds
110118 } catch ( err ) { }
111119 }
112120
@@ -121,7 +129,6 @@ export function windowState(options: {
121129 options . save ( state )
122130 } catch ( err ) {
123131 console . log ( err )
124- // Don't care
125132 }
126133 }
127134
@@ -142,10 +149,19 @@ export function windowState(options: {
142149 }
143150
144151 function manage ( win : BrowserWindow ) {
145- if ( config . maximize && state ?. isMaximized ) {
152+ if ( ! isStateValid ( state ) ) {
153+ resetState ( )
154+ win . setBounds ( {
155+ x : state . x ,
156+ y : state . y ,
157+ width : state . width ,
158+ height : state . height
159+ } , true )
160+ }
161+ if ( config . maximize && state . isMaximized ) {
146162 win . maximize ( )
147163 }
148- if ( config . fullScreen && state ? .isFullScreen ) {
164+ if ( config . fullScreen && state . isFullScreen ) {
149165 win . setFullScreen ( true )
150166 }
151167 win . on ( 'resize' , stateChangeHandler )
@@ -175,53 +191,31 @@ export function windowState(options: {
175191 }
176192 }
177193
178- // Load previous state
179- try {
180- state = ( options . load ( ) || { } ) as any
181- } catch ( err ) {
182- state = { }
183- }
184-
185- // Check state validity
186- app . whenReady ( ) . then ( ( ) => {
187- validateState ( )
188- } )
189-
190-
191- // Set state fallback values
192- state = Object . assign (
193- {
194- width : config . defaultWidth || 800 ,
195- height : config . defaultHeight || 600 ,
196- } ,
197- state
198- )
199-
200194 return {
201195 get x ( ) {
202- return state ? .x
196+ return state . x
203197 } ,
204198 get y ( ) {
205- return state ? .y
199+ return state . y
206200 } ,
207201 get width ( ) {
208- return state ? .width
202+ return state . width
209203 } ,
210204 get height ( ) {
211- return state ? .height
205+ return state . height
212206 } ,
213207 get displayBounds ( ) {
214- return state ? .displayBounds
208+ return state . displayBounds
215209 } ,
216210 get isMaximized ( ) {
217- return state ? .isMaximized
211+ return state . isMaximized
218212 } ,
219213 get isFullScreen ( ) {
220- return state ? .isFullScreen
214+ return state . isFullScreen
221215 } ,
222216 saveState,
223217 unmanage,
224218 manage,
225- resetStateToDefault,
219+ resetStateToDefault : resetState ,
226220 }
227221}
0 commit comments