Skip to content

Commit 36ac47b

Browse files
Akos Kittakittaakos
Akos Kitta
authored andcommitted
Can check if the current window is the first one.
Closes arduino#1070 Signed-off-by: Akos Kitta <[email protected]>
1 parent bf193b1 commit 36ac47b

13 files changed

+191
-69
lines changed

arduino-ide-extension/package.json

+4
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@
150150
"frontend": "lib/browser/theia/core/browser-menu-module",
151151
"frontendElectron": "lib/electron-browser/theia/core/electron-menu-module"
152152
},
153+
{
154+
"frontend": "lib/browser/theia/core/browser-window-module",
155+
"frontendElectron": "lib/electron-browser/theia/core/electron-window-module"
156+
},
153157
{
154158
"electronMain": "lib/electron-main/arduino-electron-main-module"
155159
}

arduino-ide-extension/src/browser/contributions/first-startup-installer.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class FirstStartupInstaller extends Contribution {
4343
// If arduino:avr installation fails because it's already installed we don't want to retry on next start-up
4444
console.error(e);
4545
} else {
46-
// But if there is any other error (e.g.: no interntet cconnection), we want to retry next time
46+
// But if there is any other error (e.g.: no Internet connection), we want to retry next time
4747
avrPackageError = e;
4848
}
4949
}
@@ -64,7 +64,7 @@ export class FirstStartupInstaller extends Contribution {
6464
// If Arduino_BuiltIn installation fails because it's already installed we don't want to retry on next start-up
6565
console.log('error installing core', e);
6666
} else {
67-
// But if there is any other error (e.g.: no interntet cconnection), we want to retry next time
67+
// But if there is any other error (e.g.: no Internet connection), we want to retry next time
6868
builtInLibraryError = e;
6969
}
7070
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { DefaultWindowService as TheiaDefaultWindowService } from '@theia/core/lib/browser/window/default-window-service';
2+
import { ContainerModule } from '@theia/core/shared/inversify';
3+
import { DefaultWindowService } from './default-window-service';
4+
import { WindowServiceExt } from './window-service-ext';
5+
6+
export default new ContainerModule((bind, unbind, isBound, rebind) => {
7+
bind(DefaultWindowService).toSelf().inSingletonScope();
8+
rebind(TheiaDefaultWindowService).toService(DefaultWindowService);
9+
bind(WindowServiceExt).toService(DefaultWindowService);
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { DefaultWindowService as TheiaDefaultWindowService } from '@theia/core/lib/browser/window/default-window-service';
2+
import { injectable } from '@theia/core/shared/inversify';
3+
import { WindowServiceExt } from './window-service-ext';
4+
5+
@injectable()
6+
export class DefaultWindowService
7+
extends TheiaDefaultWindowService
8+
implements WindowServiceExt
9+
{
10+
/**
11+
* The default implementation always resolves to `true`.
12+
* IDE2 does not use it. It's currently an electron-only app.
13+
*/
14+
async isFirstWindow(): Promise<boolean> {
15+
return true;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const WindowServiceExt = Symbol('WindowServiceExt');
2+
export interface WindowServiceExt {
3+
/**
4+
* Returns with a promise that resolves to `true` if the current window is the first window.
5+
*/
6+
isFirstWindow(): Promise<boolean>;
7+
}
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,33 @@
11
import { ContainerModule } from '@theia/core/shared/inversify';
2-
import { WindowService } from '@theia/core/lib/browser/window/window-service';
32
import { ElectronMainMenuFactory as TheiaElectronMainMenuFactory } from '@theia/core/lib/electron-browser/menu/electron-main-menu-factory';
43
import { ElectronMenuContribution as TheiaElectronMenuContribution } from '@theia/core/lib/electron-browser/menu/electron-menu-contribution';
5-
import { ElectronIpcConnectionProvider } from '@theia/core/lib/electron-browser/messaging/electron-ipc-connection-provider';
6-
import {
7-
SplashService,
8-
splashServicePath,
9-
} from '../../../electron-common/splash-service';
104
import { MainMenuManager } from '../../../common/main-menu-manager';
11-
import { ElectronWindowService } from '../../electron-window-service';
125
import { ElectronMainMenuFactory } from './electron-main-menu-factory';
136
import { ElectronMenuContribution } from './electron-menu-contribution';
147
import { nls } from '@theia/core/lib/common/nls';
158

169
import * as remote from '@theia/core/electron-shared/@electron/remote';
1710
import * as dialogs from '@theia/core/lib/browser/dialogs';
1811

19-
2012
Object.assign(dialogs, {
2113
confirmExit: async () => {
2214
const messageBoxResult = await remote.dialog.showMessageBox(
2315
remote.getCurrentWindow(),
2416
{
25-
message: nls.localize('theia/core/quitMessage', 'Any unsaved changes will not be saved.'),
26-
title: nls.localize('theia/core/quitTitle', 'Are you sure you want to quit?'),
17+
message: nls.localize(
18+
'theia/core/quitMessage',
19+
'Any unsaved changes will not be saved.'
20+
),
21+
title: nls.localize(
22+
'theia/core/quitTitle',
23+
'Are you sure you want to quit?'
24+
),
2725
type: 'question',
28-
buttons: [
29-
dialogs.Dialog.CANCEL,
30-
dialogs.Dialog.YES,
31-
],
26+
buttons: [dialogs.Dialog.CANCEL, dialogs.Dialog.YES],
3227
}
33-
)
28+
);
3429
return messageBoxResult.response === 1;
35-
}
30+
},
3631
});
3732

3833
export default new ContainerModule((bind, unbind, isBound, rebind) => {
@@ -41,14 +36,4 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
4136
rebind(TheiaElectronMenuContribution).toService(ElectronMenuContribution);
4237
bind(ElectronMainMenuFactory).toSelf().inSingletonScope();
4338
rebind(TheiaElectronMainMenuFactory).toService(ElectronMainMenuFactory);
44-
bind(ElectronWindowService).toSelf().inSingletonScope();
45-
rebind(WindowService).toService(ElectronWindowService);
46-
bind(SplashService)
47-
.toDynamicValue((context) =>
48-
ElectronIpcConnectionProvider.createProxy(
49-
context.container,
50-
splashServicePath
51-
)
52-
)
53-
.inSingletonScope();
5439
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { WindowService } from '@theia/core/lib/browser/window/window-service';
2+
import { ElectronIpcConnectionProvider } from '@theia/core/lib/electron-browser/messaging/electron-ipc-connection-provider';
3+
import { ContainerModule } from '@theia/core/shared/inversify';
4+
import { WindowServiceExt } from '../../../browser/theia/core/window-service-ext';
5+
import {
6+
ElectronMainWindowServiceExt,
7+
electronMainWindowServiceExtPath,
8+
} from '../../../electron-common/electron-main-window-service-ext';
9+
import {
10+
SplashService,
11+
splashServicePath,
12+
} from '../../../electron-common/splash-service';
13+
import { ElectronWindowService } from './electron-window-service';
14+
15+
export default new ContainerModule((bind, unbind, isBound, rebind) => {
16+
bind(ElectronWindowService).toSelf().inSingletonScope();
17+
rebind(WindowService).toService(ElectronWindowService);
18+
bind(WindowServiceExt).toService(ElectronWindowService);
19+
bind(ElectronMainWindowServiceExt)
20+
.toDynamicValue(({ container }) =>
21+
ElectronIpcConnectionProvider.createProxy(
22+
container,
23+
electronMainWindowServiceExtPath
24+
)
25+
)
26+
.inSingletonScope();
27+
bind(SplashService)
28+
.toDynamicValue(({ container }) =>
29+
ElectronIpcConnectionProvider.createProxy(container, splashServicePath)
30+
)
31+
.inSingletonScope();
32+
});

arduino-ide-extension/src/electron-browser/electron-window-service.ts renamed to arduino-ide-extension/src/electron-browser/theia/core/electron-window-service.ts

+29-6
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
1-
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
1+
import {
2+
inject,
3+
injectable,
4+
postConstruct,
5+
} from '@theia/core/shared/inversify';
26
import * as remote from '@theia/core/electron-shared/@electron/remote';
37
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
48
import {
59
ConnectionStatus,
610
ConnectionStatusService,
711
} from '@theia/core/lib/browser/connection-status-service';
812
import { ElectronWindowService as TheiaElectronWindowService } from '@theia/core/lib/electron-browser/window/electron-window-service';
9-
import { SplashService } from '../electron-common/splash-service';
13+
import { SplashService } from '../../../electron-common/splash-service';
1014
import { nls } from '@theia/core/lib/common';
15+
import { WindowServiceExt } from '../../../browser/theia/core/window-service-ext';
16+
import { ElectronMainWindowServiceExt } from '../../../electron-common/electron-main-window-service-ext';
1117

1218
@injectable()
13-
export class ElectronWindowService extends TheiaElectronWindowService {
19+
export class ElectronWindowService
20+
extends TheiaElectronWindowService
21+
implements WindowServiceExt
22+
{
1423
@inject(ConnectionStatusService)
15-
protected readonly connectionStatusService: ConnectionStatusService;
24+
private readonly connectionStatusService: ConnectionStatusService;
1625

1726
@inject(SplashService)
18-
protected readonly splashService: SplashService;
27+
private readonly splashService: SplashService;
1928

2029
@inject(FrontendApplicationStateService)
21-
protected readonly appStateService: FrontendApplicationStateService;
30+
private readonly appStateService: FrontendApplicationStateService;
31+
32+
@inject(ElectronMainWindowServiceExt)
33+
private readonly mainWindowServiceExt: ElectronMainWindowServiceExt;
2234

2335
@postConstruct()
2436
protected override init(): void {
@@ -55,4 +67,15 @@ export class ElectronWindowService extends TheiaElectronWindowService {
5567
});
5668
return response === 0; // 'Yes', close the window.
5769
}
70+
71+
private _firstWindow: boolean | undefined;
72+
async isFirstWindow(): Promise<boolean> {
73+
if (this._firstWindow === undefined) {
74+
const windowId = remote.getCurrentWindow().id; // This is expensive and synchronous so we check it once per FE.
75+
this._firstWindow = await this.mainWindowServiceExt.isFirstWindow(
76+
windowId
77+
);
78+
}
79+
return this._firstWindow;
80+
}
5881
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const electronMainWindowServiceExtPath = '/services/electron-window-ext';
2+
export const ElectronMainWindowServiceExt = Symbol(
3+
'ElectronMainWindowServiceExt'
4+
);
5+
export interface ElectronMainWindowServiceExt {
6+
isFirstWindow(windowId: number): Promise<boolean>;
7+
}

arduino-ide-extension/src/electron-main/arduino-electron-main-module.ts

+19-24
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
1-
import { ContainerModule } from '@theia/core/shared/inversify';
21
import { JsonRpcConnectionHandler } from '@theia/core/lib/common/messaging/proxy-factory';
3-
import { ElectronConnectionHandler } from '@theia/core/lib/electron-common/messaging/electron-connection-handler';
42
import { ElectronMainWindowService } from '@theia/core/lib/electron-common/electron-main-window-service';
3+
import { ElectronConnectionHandler } from '@theia/core/lib/electron-common/messaging/electron-connection-handler';
54
import {
65
ElectronMainApplication as TheiaElectronMainApplication,
76
ElectronMainApplicationContribution,
87
} from '@theia/core/lib/electron-main/electron-main-application';
8+
import { TheiaElectronWindow as DefaultTheiaElectronWindow } from '@theia/core/lib/electron-main/theia-electron-window';
9+
import { ContainerModule } from '@theia/core/shared/inversify';
10+
import {
11+
IDEUpdater,
12+
IDEUpdaterClient,
13+
IDEUpdaterPath,
14+
} from '../common/protocol/ide-updater';
15+
import {
16+
ElectronMainWindowServiceExt,
17+
electronMainWindowServiceExtPath,
18+
} from '../electron-common/electron-main-window-service-ext';
919
import {
1020
SplashService,
1121
splashServicePath,
1222
} from '../electron-common/splash-service';
23+
import { ElectronMainWindowServiceExtImpl } from './electron-main-window-service-ext-impl';
24+
import { IDEUpdaterImpl } from './ide-updater/ide-updater-impl';
1325
import { SplashServiceImpl } from './splash/splash-service-impl';
1426
import { ElectronMainApplication } from './theia/electron-main-application';
1527
import { ElectronMainWindowServiceImpl } from './theia/electron-main-window-service';
16-
import {
17-
IDEUpdater,
18-
IDEUpdaterClient,
19-
IDEUpdaterPath,
20-
} from '../common/protocol/ide-updater';
21-
import { IDEUpdaterImpl } from './ide-updater/ide-updater-impl';
2228
import { TheiaElectronWindow } from './theia/theia-electron-window';
23-
import { TheiaElectronWindow as DefaultTheiaElectronWindow } from '@theia/core/lib/electron-main/theia-electron-window';
24-
import { SurveyNotificationServiceImpl } from '../node/survey-service-impl';
25-
import {
26-
SurveyNotificationService,
27-
SurveyNotificationServicePath,
28-
} from '../common/protocol/survey-service';
2929

3030
export default new ContainerModule((bind, unbind, isBound, rebind) => {
3131
bind(ElectronMainApplication).toSelf().inSingletonScope();
@@ -67,19 +67,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
6767
bind(TheiaElectronWindow).toSelf();
6868
rebind(DefaultTheiaElectronWindow).toService(TheiaElectronWindow);
6969

70-
// Survey notification bindings
71-
bind(SurveyNotificationServiceImpl).toSelf().inSingletonScope();
72-
bind(SurveyNotificationService).toService(SurveyNotificationServiceImpl);
73-
bind(ElectronMainApplicationContribution).toService(
74-
SurveyNotificationService
75-
);
70+
bind(ElectronMainWindowServiceExt)
71+
.to(ElectronMainWindowServiceExtImpl)
72+
.inSingletonScope();
7673
bind(ElectronConnectionHandler)
7774
.toDynamicValue(
7875
(context) =>
79-
new JsonRpcConnectionHandler(SurveyNotificationServicePath, () =>
80-
context.container.get<SurveyNotificationService>(
81-
SurveyNotificationService
82-
)
76+
new JsonRpcConnectionHandler(electronMainWindowServiceExtPath, () =>
77+
context.container.get(ElectronMainWindowServiceExt)
8378
)
8479
)
8580
.inSingletonScope();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { inject, injectable } from '@theia/core/shared/inversify';
2+
import { ElectronMainWindowServiceExt } from '../electron-common/electron-main-window-service-ext';
3+
import { ElectronMainApplication } from './theia/electron-main-application';
4+
5+
@injectable()
6+
export class ElectronMainWindowServiceExtImpl
7+
implements ElectronMainWindowServiceExt
8+
{
9+
@inject(ElectronMainApplication)
10+
private readonly app: ElectronMainApplication;
11+
12+
async isFirstWindow(windowId: number): Promise<boolean> {
13+
return this.app.firstWindowId === windowId;
14+
}
15+
}

0 commit comments

Comments
 (0)