@@ -3,22 +3,40 @@ import { app, BrowserWindow, BrowserWindowConstructorOptions, ipcMain, screen }
33import { fork } from 'child_process' ;
44import { AddressInfo } from 'net' ;
55import { join } from 'path' ;
6+ import * as fs from 'fs-extra' ;
67import { initSplashScreen } from '../splash/splash-screen' ;
78import { MaybePromise } from '@theia/core/lib/common/types' ;
89import { ElectronSecurityToken } from '@theia/core/lib/electron-common/electron-token' ;
910import { FrontendApplicationConfig } from '@theia/application-package/lib/application-props' ;
1011import {
1112 ElectronMainApplication as TheiaElectronMainApplication ,
13+ ElectronMainExecutionParams ,
1214 TheiaBrowserWindowOptions ,
1315} from '@theia/core/lib/electron-main/electron-main-application' ;
1416import { SplashServiceImpl } from '../splash/splash-service-impl' ;
17+ import { ipcMain } from '@theia/core/shared/electron' ;
18+ import { URI } from '@theia/core/shared/vscode-uri' ;
1519import * as electronRemoteMain from '@theia/core/electron-shared/@electron/remote/main' ;
1620
1721app . commandLine . appendSwitch ( 'disable-http-cache' ) ;
1822
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+
1936@injectable ( )
2037export class ElectronMainApplication extends TheiaElectronMainApplication {
2138 protected _windows : BrowserWindow [ ] = [ ] ;
39+ protected startup = false ;
2240
2341 @inject ( SplashServiceImpl )
2442 protected readonly splashService : SplashServiceImpl ;
@@ -31,6 +49,45 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
3149 return super . start ( config ) ;
3250 }
3351
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+
3491 protected getTitleBarStyle ( ) : 'native' | 'custom' {
3592 return 'native' ;
3693 }
@@ -143,6 +200,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
143200 }
144201 }
145202 } ) ;
203+ this . attachClosedWorkspace ( electronWindow ) ;
146204 this . attachReadyToShow ( electronWindow ) ;
147205 this . attachSaveWindowState ( electronWindow ) ;
148206 this . attachGlobalShortcuts ( electronWindow ) ;
@@ -214,6 +272,44 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
214272 }
215273 }
216274
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+
217313 get windows ( ) : BrowserWindow [ ] {
218314 return this . _windows . slice ( ) ;
219315 }
0 commit comments