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