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