@@ -8,22 +8,39 @@ import {
8
8
import { fork } from 'child_process' ;
9
9
import { AddressInfo } from 'net' ;
10
10
import { join } from 'path' ;
11
+ import * as fs from 'fs-extra' ;
11
12
import { initSplashScreen } from '../splash/splash-screen' ;
12
13
import { MaybePromise } from '@theia/core/lib/common/types' ;
13
14
import { ElectronSecurityToken } from '@theia/core/lib/electron-common/electron-token' ;
14
15
import { FrontendApplicationConfig } from '@theia/application-package/lib/application-props' ;
15
16
import {
16
17
ElectronMainApplication as TheiaElectronMainApplication ,
18
+ ElectronMainExecutionParams ,
17
19
TheiaBrowserWindowOptions ,
18
20
} from '@theia/core/lib/electron-main/electron-main-application' ;
19
21
import { SplashServiceImpl } from '../splash/splash-service-impl' ;
20
22
import { ipcMain } from '@theia/core/shared/electron' ;
23
+ import { URI } from '@theia/core/shared/vscode-uri' ;
21
24
22
25
app . commandLine . appendSwitch ( 'disable-http-cache' ) ;
23
26
27
+ interface WorkspaceOptions {
28
+ file : string
29
+ x : number
30
+ y : number
31
+ width : number
32
+ height : number
33
+ isMaximized : boolean
34
+ isFullScreen : boolean
35
+ time : number
36
+ }
37
+
38
+ const WORKSPACES = 'workspaces' ;
39
+
24
40
@injectable ( )
25
41
export class ElectronMainApplication extends TheiaElectronMainApplication {
26
42
protected _windows : BrowserWindow [ ] = [ ] ;
43
+ protected startup = false ;
27
44
28
45
@inject ( SplashServiceImpl )
29
46
protected readonly splashService : SplashServiceImpl ;
@@ -36,6 +53,45 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
36
53
return super . start ( config ) ;
37
54
}
38
55
56
+ protected async launch ( params : ElectronMainExecutionParams ) : Promise < void > {
57
+ this . startup = true ;
58
+ const workspaces : WorkspaceOptions [ ] | undefined = this . electronStore . get ( WORKSPACES ) ;
59
+ let useDefault = true ;
60
+ if ( workspaces && workspaces . length > 0 ) {
61
+ for ( const workspace of workspaces ) {
62
+ const file = workspace . file ;
63
+ if ( typeof file === 'string' && await fs . pathExists ( file ) ) {
64
+ useDefault = false ;
65
+ await this . openSketch ( workspace ) ;
66
+ }
67
+ }
68
+ }
69
+ this . startup = false ;
70
+ if ( useDefault ) {
71
+ super . launch ( params ) ;
72
+ }
73
+ }
74
+
75
+ protected async openSketch ( workspace : WorkspaceOptions ) : Promise < BrowserWindow > {
76
+ const options = await this . getLastWindowOptions ( ) ;
77
+ options . x = workspace . x ;
78
+ options . y = workspace . y ;
79
+ options . width = workspace . width ;
80
+ options . height = workspace . height ;
81
+ options . isMaximized = workspace . isMaximized ;
82
+ options . isFullScreen = workspace . isFullScreen ;
83
+ const [ uri , electronWindow ] = await Promise . all ( [ this . createWindowUri ( ) , this . createWindow ( options ) ] ) ;
84
+ electronWindow . loadURL ( uri . withFragment ( encodeURI ( workspace . file ) ) . toString ( true ) ) ;
85
+ return electronWindow ;
86
+ }
87
+
88
+ protected avoidOverlap ( options : TheiaBrowserWindowOptions ) : TheiaBrowserWindowOptions {
89
+ if ( this . startup ) {
90
+ return options ;
91
+ }
92
+ return super . avoidOverlap ( options ) ;
93
+ }
94
+
39
95
protected getTitleBarStyle ( ) : 'native' | 'custom' {
40
96
return 'native' ;
41
97
}
@@ -148,6 +204,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
148
204
}
149
205
}
150
206
} ) ;
207
+ this . attachClosedWorkspace ( electronWindow ) ;
151
208
this . attachReadyToShow ( electronWindow ) ;
152
209
this . attachSaveWindowState ( electronWindow ) ;
153
210
this . attachGlobalShortcuts ( electronWindow ) ;
@@ -218,6 +275,44 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
218
275
}
219
276
}
220
277
278
+ protected closedWorkspaces : WorkspaceOptions [ ] = [ ] ;
279
+
280
+ protected attachClosedWorkspace ( window : BrowserWindow ) : void {
281
+ // Since the `before-quit` event is only fired when closing the *last* window
282
+ // We need to keep track of recently closed windows/workspaces manually
283
+ window . on ( 'close' , ( ) => {
284
+ const url = window . webContents . getURL ( ) ;
285
+ const workspace = URI . parse ( url ) . fragment ;
286
+ if ( workspace ) {
287
+ const workspaceUri = URI . file ( workspace ) ;
288
+ const bounds = window . getNormalBounds ( ) ;
289
+ this . closedWorkspaces . push ( {
290
+ ...bounds ,
291
+ isMaximized : window . isMaximized ( ) ,
292
+ isFullScreen : window . isFullScreen ( ) ,
293
+ file : workspaceUri . fsPath ,
294
+ time : Date . now ( )
295
+ } )
296
+ }
297
+ } ) ;
298
+ }
299
+
300
+ protected onWillQuit ( event : Electron . Event ) : void {
301
+ // Only add workspaces which were closed within the last second (1000 milliseconds)
302
+ const threshold = Date . now ( ) - 1000 ;
303
+ const visited = new Set < string > ( ) ;
304
+ const workspaces = this . closedWorkspaces . filter ( e => {
305
+ if ( e . time < threshold || visited . has ( e . file ) ) {
306
+ return false ;
307
+ }
308
+ visited . add ( e . file ) ;
309
+ return true ;
310
+ } ) . sort ( ( a , b ) => a . file . localeCompare ( b . file ) ) ;
311
+ this . electronStore . set ( WORKSPACES , workspaces ) ;
312
+
313
+ super . onWillQuit ( event ) ;
314
+ }
315
+
221
316
get windows ( ) : BrowserWindow [ ] {
222
317
return this . _windows . slice ( ) ;
223
318
}
0 commit comments