@theia/core 1.46.0-next.106 → 1.46.0-next.144
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/i18n/nls.cs.json +4 -0
- package/i18n/nls.de.json +4 -0
- package/i18n/nls.es.json +4 -0
- package/i18n/nls.fr.json +4 -0
- package/i18n/nls.hu.json +4 -0
- package/i18n/nls.it.json +4 -0
- package/i18n/nls.ja.json +4 -0
- package/i18n/nls.json +4 -0
- package/i18n/nls.pl.json +4 -0
- package/i18n/nls.pt-br.json +4 -0
- package/i18n/nls.pt-pt.json +4 -0
- package/i18n/nls.ru.json +4 -0
- package/i18n/nls.zh-cn.json +4 -0
- package/lib/browser/color-application-contribution.d.ts +4 -2
- package/lib/browser/color-application-contribution.d.ts.map +1 -1
- package/lib/browser/color-application-contribution.js +11 -1
- package/lib/browser/color-application-contribution.js.map +1 -1
- package/lib/browser/command-open-handler.js +1 -1
- package/lib/browser/command-open-handler.js.map +1 -1
- package/lib/browser/common-frontend-contribution.d.ts +6 -0
- package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
- package/lib/browser/common-frontend-contribution.js +43 -1
- package/lib/browser/common-frontend-contribution.js.map +1 -1
- package/lib/browser/frontend-application-module.d.ts.map +1 -1
- package/lib/browser/frontend-application-module.js +2 -0
- package/lib/browser/frontend-application-module.js.map +1 -1
- package/lib/browser/index.d.ts +1 -0
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +1 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/keybinding.js +1 -1
- package/lib/browser/keybinding.js.map +1 -1
- package/lib/browser/menu/browser-context-menu-renderer.d.ts.map +1 -1
- package/lib/browser/menu/browser-context-menu-renderer.js +2 -1
- package/lib/browser/menu/browser-context-menu-renderer.js.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.d.ts +1 -1
- package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.js +2 -2
- package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
- package/lib/browser/open-with-service.d.ts +44 -0
- package/lib/browser/open-with-service.d.ts.map +1 -0
- package/lib/browser/open-with-service.js +66 -0
- package/lib/browser/open-with-service.js.map +1 -0
- package/lib/browser/secondary-window-handler.d.ts +12 -11
- package/lib/browser/secondary-window-handler.d.ts.map +1 -1
- package/lib/browser/secondary-window-handler.js +16 -23
- package/lib/browser/secondary-window-handler.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts +3 -1
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +28 -20
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts +1 -0
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +12 -7
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
- package/lib/browser/shell/view-contribution.d.ts.map +1 -1
- package/lib/browser/shell/view-contribution.js +2 -1
- package/lib/browser/shell/view-contribution.js.map +1 -1
- package/lib/browser/styling-service.d.ts +3 -2
- package/lib/browser/styling-service.d.ts.map +1 -1
- package/lib/browser/styling-service.js +11 -2
- package/lib/browser/styling-service.js.map +1 -1
- package/lib/browser/window/default-secondary-window-service.d.ts +1 -1
- package/lib/browser/window/default-secondary-window-service.d.ts.map +1 -1
- package/lib/browser/window/default-secondary-window-service.js +22 -25
- package/lib/browser/window/default-secondary-window-service.js.map +1 -1
- package/lib/browser/window/default-window-service.d.ts +1 -0
- package/lib/browser/window/default-window-service.d.ts.map +1 -1
- package/lib/browser/window/default-window-service.js +3 -0
- package/lib/browser/window/default-window-service.js.map +1 -1
- package/lib/browser/window/test/mock-window-service.d.ts +1 -0
- package/lib/browser/window/test/mock-window-service.d.ts.map +1 -1
- package/lib/browser/window/test/mock-window-service.js +1 -0
- package/lib/browser/window/test/mock-window-service.js.map +1 -1
- package/lib/browser/window/window-service.d.ts +4 -0
- package/lib/browser/window/window-service.d.ts.map +1 -1
- package/lib/common/event.d.ts +5 -0
- package/lib/common/event.d.ts.map +1 -1
- package/lib/common/event.js +14 -1
- package/lib/common/event.js.map +1 -1
- package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-context-menu-renderer.js +3 -1
- package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
- package/lib/electron-browser/preload.js +2 -2
- package/lib/electron-browser/preload.js.map +1 -1
- package/lib/electron-browser/window/electron-secondary-window-service.d.ts +1 -1
- package/lib/electron-browser/window/electron-secondary-window-service.d.ts.map +1 -1
- package/lib/electron-browser/window/electron-secondary-window-service.js +4 -8
- package/lib/electron-browser/window/electron-secondary-window-service.js.map +1 -1
- package/lib/electron-browser/window/electron-window-service.d.ts +1 -0
- package/lib/electron-browser/window/electron-window-service.d.ts.map +1 -1
- package/lib/electron-browser/window/electron-window-service.js +3 -0
- package/lib/electron-browser/window/electron-window-service.js.map +1 -1
- package/lib/electron-common/electron-api.d.ts +2 -2
- package/lib/electron-common/electron-api.d.ts.map +1 -1
- package/lib/electron-main/electron-api-main.d.ts.map +1 -1
- package/lib/electron-main/electron-api-main.js +12 -2
- package/lib/electron-main/electron-api-main.js.map +1 -1
- package/package.json +6 -6
- package/src/browser/color-application-contribution.ts +11 -2
- package/src/browser/command-open-handler.ts +1 -1
- package/src/browser/common-frontend-contribution.ts +44 -1
- package/src/browser/frontend-application-module.ts +3 -0
- package/src/browser/index.ts +1 -0
- package/src/browser/keybinding.ts +1 -1
- package/src/browser/menu/browser-context-menu-renderer.ts +2 -1
- package/src/browser/menu/browser-menu-plugin.ts +2 -2
- package/src/browser/open-with-service.ts +93 -0
- package/src/browser/secondary-window-handler.ts +21 -22
- package/src/browser/shell/application-shell.ts +25 -18
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +15 -10
- package/src/browser/shell/view-contribution.ts +3 -2
- package/src/browser/styling-service.ts +12 -3
- package/src/browser/window/default-secondary-window-service.ts +24 -26
- package/src/browser/window/default-window-service.ts +4 -0
- package/src/browser/window/test/mock-window-service.ts +1 -0
- package/src/browser/window/window-service.ts +5 -0
- package/src/common/event.ts +18 -0
- package/src/electron-browser/menu/electron-context-menu-renderer.ts +3 -1
- package/src/electron-browser/preload.ts +3 -3
- package/src/electron-browser/window/electron-secondary-window-service.ts +4 -8
- package/src/electron-browser/window/electron-window-service.ts +3 -0
- package/src/electron-common/electron-api.ts +2 -2
- package/src/electron-main/electron-api-main.ts +11 -2
|
@@ -44,6 +44,7 @@ import { SecondaryWindowHandler } from '../secondary-window-handler';
|
|
|
44
44
|
import URI from '../../common/uri';
|
|
45
45
|
import { OpenerService } from '../opener-service';
|
|
46
46
|
import { PreviewableWidget } from '../widgets/previewable-widget';
|
|
47
|
+
import { WindowService } from '../window/window-service';
|
|
47
48
|
|
|
48
49
|
/** The class name added to ApplicationShell instances. */
|
|
49
50
|
const APPLICATION_SHELL_CLASS = 'theia-ApplicationShell';
|
|
@@ -273,6 +274,7 @@ export class ApplicationShell extends Widget {
|
|
|
273
274
|
@inject(CorePreferences) protected readonly corePreferences: CorePreferences,
|
|
274
275
|
@inject(SaveResourceService) protected readonly saveResourceService: SaveResourceService,
|
|
275
276
|
@inject(SecondaryWindowHandler) protected readonly secondaryWindowHandler: SecondaryWindowHandler,
|
|
277
|
+
@inject(WindowService) protected readonly windowService: WindowService
|
|
276
278
|
) {
|
|
277
279
|
super(options as Widget.IOptions);
|
|
278
280
|
|
|
@@ -338,8 +340,8 @@ export class ApplicationShell extends Widget {
|
|
|
338
340
|
this.rightPanelHandler.dockPanel.widgetRemoved.connect((_, widget) => this.fireDidRemoveWidget(widget));
|
|
339
341
|
|
|
340
342
|
this.secondaryWindowHandler.init(this);
|
|
341
|
-
this.secondaryWindowHandler.onDidAddWidget(widget => this.fireDidAddWidget(widget));
|
|
342
|
-
this.secondaryWindowHandler.onDidRemoveWidget(widget => this.fireDidRemoveWidget(widget));
|
|
343
|
+
this.secondaryWindowHandler.onDidAddWidget(([widget, window]) => this.fireDidAddWidget(widget));
|
|
344
|
+
this.secondaryWindowHandler.onDidRemoveWidget(([widget, window]) => this.fireDidRemoveWidget(widget));
|
|
343
345
|
|
|
344
346
|
this.layout = this.createLayout();
|
|
345
347
|
|
|
@@ -1323,20 +1325,23 @@ export class ApplicationShell extends Widget {
|
|
|
1323
1325
|
let widget = find(this.mainPanel.widgets(), w => w.id === id);
|
|
1324
1326
|
if (widget) {
|
|
1325
1327
|
this.mainPanel.activateWidget(widget);
|
|
1326
|
-
return widget;
|
|
1327
1328
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1329
|
+
if (!widget) {
|
|
1330
|
+
widget = find(this.bottomPanel.widgets(), w => w.id === id);
|
|
1331
|
+
if (widget) {
|
|
1332
|
+
this.expandBottomPanel();
|
|
1333
|
+
this.bottomPanel.activateWidget(widget);
|
|
1334
|
+
}
|
|
1333
1335
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1336
|
+
if (!widget) {
|
|
1337
|
+
widget = this.leftPanelHandler.activate(id);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
if (!widget) {
|
|
1341
|
+
widget = this.rightPanelHandler.activate(id);
|
|
1337
1342
|
}
|
|
1338
|
-
widget = this.rightPanelHandler.activate(id);
|
|
1339
1343
|
if (widget) {
|
|
1344
|
+
this.windowService.focus();
|
|
1340
1345
|
return widget;
|
|
1341
1346
|
}
|
|
1342
1347
|
return this.secondaryWindowHandler.activateWidget(id);
|
|
@@ -1433,17 +1438,19 @@ export class ApplicationShell extends Widget {
|
|
|
1433
1438
|
if (tabBar) {
|
|
1434
1439
|
tabBar.currentTitle = widget.title;
|
|
1435
1440
|
}
|
|
1436
|
-
return widget;
|
|
1437
1441
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1442
|
+
if (!widget) {
|
|
1443
|
+
widget = this.leftPanelHandler.expand(id);
|
|
1444
|
+
}
|
|
1445
|
+
if (!widget) {
|
|
1446
|
+
widget = this.rightPanelHandler.expand(id);
|
|
1441
1447
|
}
|
|
1442
|
-
widget = this.rightPanelHandler.expand(id);
|
|
1443
1448
|
if (widget) {
|
|
1449
|
+
this.windowService.focus();
|
|
1444
1450
|
return widget;
|
|
1451
|
+
} else {
|
|
1452
|
+
return this.secondaryWindowHandler.revealWidget(id);
|
|
1445
1453
|
}
|
|
1446
|
-
return this.secondaryWindowHandler.revealWidget(id);
|
|
1447
1454
|
}
|
|
1448
1455
|
|
|
1449
1456
|
/**
|
|
@@ -70,11 +70,11 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
70
70
|
|
|
71
71
|
@postConstruct()
|
|
72
72
|
protected init(): void {
|
|
73
|
-
this.toDispose.push(this.keybindings.onKeybindingsChanged(() => this.
|
|
73
|
+
this.toDispose.push(this.keybindings.onKeybindingsChanged(() => this.maybeUpdate()));
|
|
74
74
|
|
|
75
75
|
this.toDispose.push(this.contextKeyService.onDidChange(e => {
|
|
76
76
|
if (e.affects(this.keybindingContextKeys)) {
|
|
77
|
-
this.
|
|
77
|
+
this.maybeUpdate();
|
|
78
78
|
}
|
|
79
79
|
}));
|
|
80
80
|
}
|
|
@@ -90,7 +90,7 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
90
90
|
if ('command' in item) {
|
|
91
91
|
this.commands.getAllHandlers(item.command).forEach(handler => {
|
|
92
92
|
if (handler.onDidChangeEnabled) {
|
|
93
|
-
this.toDisposeOnUpdateItems.push(handler.onDidChangeEnabled(() => this.
|
|
93
|
+
this.toDisposeOnUpdateItems.push(handler.onDidChangeEnabled(() => this.maybeUpdate()));
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
96
|
}
|
|
@@ -113,7 +113,7 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
113
113
|
} else {
|
|
114
114
|
this.hide();
|
|
115
115
|
}
|
|
116
|
-
this.
|
|
116
|
+
this.maybeUpdate();
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
updateTarget(current?: Widget): void {
|
|
@@ -130,7 +130,7 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
130
130
|
if (current) {
|
|
131
131
|
const resetCurrent = () => {
|
|
132
132
|
this.setCurrent(undefined);
|
|
133
|
-
this.
|
|
133
|
+
this.maybeUpdate();
|
|
134
134
|
};
|
|
135
135
|
current.disposed.connect(resetCurrent);
|
|
136
136
|
this.toDisposeOnSetCurrent.push(Disposable.create(() =>
|
|
@@ -144,7 +144,7 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
144
144
|
if (contextKeys.size > 0) {
|
|
145
145
|
this.contextKeyListener = this.contextKeyService.onDidChange(event => {
|
|
146
146
|
if (event.affects(contextKeys)) {
|
|
147
|
-
this.
|
|
147
|
+
this.maybeUpdate();
|
|
148
148
|
}
|
|
149
149
|
});
|
|
150
150
|
}
|
|
@@ -321,8 +321,8 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
321
321
|
protected renderMenuItem(item: TabBarToolbarItem & MenuToolbarItem): React.ReactNode {
|
|
322
322
|
const icon = typeof item.icon === 'function' ? item.icon() : item.icon ?? 'ellipsis';
|
|
323
323
|
return <div key={item.id}
|
|
324
|
-
|
|
325
|
-
|
|
324
|
+
className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM + ' enabled menu'}
|
|
325
|
+
onClick={this.showPopupMenu.bind(this, item.menuPath)}>
|
|
326
326
|
<div id={item.id} className={codicon(icon, true)}
|
|
327
327
|
title={item.text} />
|
|
328
328
|
<div className={codicon('chevron-down') + ' chevron'} />
|
|
@@ -397,9 +397,15 @@ export class TabBarToolbar extends ReactWidget {
|
|
|
397
397
|
} else if (item.menuPath) {
|
|
398
398
|
this.renderMoreContextMenu(this.toAnchor(e), item.menuPath);
|
|
399
399
|
}
|
|
400
|
-
this.
|
|
400
|
+
this.maybeUpdate();
|
|
401
401
|
};
|
|
402
402
|
|
|
403
|
+
protected maybeUpdate(): void {
|
|
404
|
+
if (!this.isDisposed) {
|
|
405
|
+
this.update();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
403
409
|
protected onMouseDownEvent = (e: React.MouseEvent<HTMLElement>) => {
|
|
404
410
|
if (e.button === 0) {
|
|
405
411
|
e.currentTarget.classList.add('active');
|
|
@@ -419,5 +425,4 @@ export namespace TabBarToolbar {
|
|
|
419
425
|
export const TAB_BAR_TOOLBAR_ITEM = 'item';
|
|
420
426
|
|
|
421
427
|
}
|
|
422
|
-
|
|
423
428
|
}
|
|
@@ -18,7 +18,7 @@ import { injectable, inject, interfaces, optional } from 'inversify';
|
|
|
18
18
|
import { Widget } from '@phosphor/widgets';
|
|
19
19
|
import {
|
|
20
20
|
MenuModelRegistry, Command, CommandContribution,
|
|
21
|
-
MenuContribution, CommandRegistry
|
|
21
|
+
MenuContribution, CommandRegistry, nls
|
|
22
22
|
} from '../../common';
|
|
23
23
|
import { KeybindingContribution, KeybindingRegistry } from '../keybinding';
|
|
24
24
|
import { WidgetManager } from '../widget-manager';
|
|
@@ -69,7 +69,8 @@ export abstract class AbstractViewContribution<T extends Widget> implements Comm
|
|
|
69
69
|
if (options.toggleCommandId) {
|
|
70
70
|
this.toggleCommand = {
|
|
71
71
|
id: options.toggleCommandId,
|
|
72
|
-
|
|
72
|
+
category: nls.localizeByDefault('View'),
|
|
73
|
+
label: nls.localizeByDefault('Toggle {0}', this.viewLabel)
|
|
73
74
|
};
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -21,7 +21,7 @@ import { ColorRegistry } from './color-registry';
|
|
|
21
21
|
import { DecorationStyle } from './decoration-style';
|
|
22
22
|
import { FrontendApplicationContribution } from './frontend-application-contribution';
|
|
23
23
|
import { ThemeService } from './theming';
|
|
24
|
-
import {
|
|
24
|
+
import { SecondaryWindowHandler } from './secondary-window-handler';
|
|
25
25
|
|
|
26
26
|
export const StylingParticipant = Symbol('StylingParticipant');
|
|
27
27
|
|
|
@@ -52,16 +52,25 @@ export class StylingService implements FrontendApplicationContribution {
|
|
|
52
52
|
@inject(ContributionProvider) @named(StylingParticipant)
|
|
53
53
|
protected readonly themingParticipants: ContributionProvider<StylingParticipant>;
|
|
54
54
|
|
|
55
|
+
@inject(SecondaryWindowHandler)
|
|
56
|
+
protected readonly secondaryWindowHandler: SecondaryWindowHandler;
|
|
57
|
+
|
|
55
58
|
onStart(): void {
|
|
56
59
|
this.registerWindow(window);
|
|
60
|
+
this.secondaryWindowHandler.onWillAddWidget(([widget, window]) => {
|
|
61
|
+
this.registerWindow(window);
|
|
62
|
+
});
|
|
63
|
+
this.secondaryWindowHandler.onWillRemoveWidget(([widget, window]) => {
|
|
64
|
+
this.cssElements.delete(window);
|
|
65
|
+
});
|
|
66
|
+
|
|
57
67
|
this.themeService.onDidColorThemeChange(e => this.applyStylingToWindows(e.newTheme));
|
|
58
68
|
}
|
|
59
69
|
|
|
60
|
-
registerWindow(win: Window):
|
|
70
|
+
registerWindow(win: Window): void {
|
|
61
71
|
const cssElement = DecorationStyle.createStyleElement('contributedColorTheme', win.document.head);
|
|
62
72
|
this.cssElements.set(win, cssElement);
|
|
63
73
|
this.applyStyling(this.themeService.getCurrentTheme(), cssElement);
|
|
64
|
-
return Disposable.create(() => this.cssElements.delete(win));
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
protected applyStylingToWindows(theme: Theme): void {
|
|
@@ -82,37 +82,14 @@ export class DefaultSecondaryWindowService implements SecondaryWindowService {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
createSecondaryWindow(widget: ExtractableWidget, shell: ApplicationShell): Window | undefined {
|
|
85
|
-
const win = this.doCreateSecondaryWindow(widget, shell);
|
|
86
|
-
if (win) {
|
|
87
|
-
this.secondaryWindows.push(win);
|
|
88
|
-
win.addEventListener('close', () => {
|
|
89
|
-
const extIndex = this.secondaryWindows.indexOf(win);
|
|
90
|
-
if (extIndex > -1) {
|
|
91
|
-
this.secondaryWindows.splice(extIndex, 1);
|
|
92
|
-
};
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
return win;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
protected findWindow<T>(windowName: string): Window | undefined {
|
|
99
|
-
for (const w of this.secondaryWindows) {
|
|
100
|
-
if (w.name === windowName) {
|
|
101
|
-
return w;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return undefined;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
protected doCreateSecondaryWindow(widget: ExtractableWidget, shell: ApplicationShell): Window | undefined {
|
|
108
|
-
let options;
|
|
109
85
|
const [height, width, left, top] = this.findSecondaryWindowCoordinates(widget);
|
|
110
|
-
options = `popup=1,width=${width},height=${height},left=${left},top=${top}`;
|
|
86
|
+
let options = `popup=1,width=${width},height=${height},left=${left},top=${top}`;
|
|
111
87
|
if (this.preferenceService.get('window.secondaryWindowAlwaysOnTop')) {
|
|
112
88
|
options += ',alwaysOnTop=true';
|
|
113
89
|
}
|
|
114
90
|
const newWindow = window.open(DefaultSecondaryWindowService.SECONDARY_WINDOW_URL, this.nextWindowId(), options) ?? undefined;
|
|
115
91
|
if (newWindow) {
|
|
92
|
+
this.secondaryWindows.push(newWindow);
|
|
116
93
|
newWindow.addEventListener('DOMContentLoaded', () => {
|
|
117
94
|
newWindow.addEventListener('beforeunload', evt => {
|
|
118
95
|
const saveable = Saveable.get(widget);
|
|
@@ -124,17 +101,38 @@ export class DefaultSecondaryWindowService implements SecondaryWindowService {
|
|
|
124
101
|
}
|
|
125
102
|
}, { capture: true });
|
|
126
103
|
|
|
127
|
-
newWindow.addEventListener('
|
|
104
|
+
newWindow.addEventListener('unload', () => {
|
|
128
105
|
const saveable = Saveable.get(widget);
|
|
129
106
|
shell.closeWidget(widget.id, {
|
|
130
107
|
save: !!saveable && saveable.dirty && saveable.autoSave !== 'off'
|
|
131
108
|
});
|
|
109
|
+
|
|
110
|
+
const extIndex = this.secondaryWindows.indexOf(newWindow);
|
|
111
|
+
if (extIndex > -1) {
|
|
112
|
+
this.secondaryWindows.splice(extIndex, 1);
|
|
113
|
+
};
|
|
132
114
|
});
|
|
115
|
+
this.windowCreated(newWindow, widget, shell);
|
|
133
116
|
});
|
|
134
117
|
}
|
|
135
118
|
return newWindow;
|
|
136
119
|
}
|
|
137
120
|
|
|
121
|
+
protected windowCreated(newWindow: Window, widget: ExtractableWidget, shell: ApplicationShell): void {
|
|
122
|
+
newWindow.addEventListener('unload', () => {
|
|
123
|
+
shell.closeWidget(widget.id);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
protected findWindow<T>(windowName: string): Window | undefined {
|
|
128
|
+
for (const w of this.secondaryWindows) {
|
|
129
|
+
if (w.name === windowName) {
|
|
130
|
+
return w;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
138
136
|
protected findSecondaryWindowCoordinates(widget: ExtractableWidget): (number | undefined)[] {
|
|
139
137
|
const clientBounds = widget.node.getBoundingClientRect();
|
|
140
138
|
const preference = this.preferenceService.get('window.secondaryWindowPlacement');
|
|
@@ -57,6 +57,10 @@ export class DefaultWindowService implements WindowService, FrontendApplicationC
|
|
|
57
57
|
this.openNewWindow(`#${DEFAULT_WINDOW_HASH}`);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
focus(): void {
|
|
61
|
+
window.focus();
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
/**
|
|
61
65
|
* Returns a list of actions that {@link FrontendApplicationContribution}s would like to take before shutdown
|
|
62
66
|
* It is expected that this will succeed - i.e. return an empty array - at most once per session. If no vetoes are received
|
|
@@ -21,6 +21,7 @@ import { WindowService } from '../window-service';
|
|
|
21
21
|
export class MockWindowService implements WindowService {
|
|
22
22
|
openNewWindow(): undefined { return undefined; }
|
|
23
23
|
openNewDefaultWindow(): void { }
|
|
24
|
+
focus(): void { }
|
|
24
25
|
reload(): void { }
|
|
25
26
|
isSafeToShutDown(): Promise<boolean> { return Promise.resolve(true); }
|
|
26
27
|
setSafeToShutDown(): void { }
|
|
@@ -42,6 +42,11 @@ export interface WindowService {
|
|
|
42
42
|
*/
|
|
43
43
|
openNewDefaultWindow(params?: WindowReloadOptions): void;
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Reveal and focuses the current window
|
|
47
|
+
*/
|
|
48
|
+
focus(): void;
|
|
49
|
+
|
|
45
50
|
/**
|
|
46
51
|
* Fires when the `window` unloads. The unload event is inevitable. On this event, the frontend application can save its state and release resource.
|
|
47
52
|
* Saving the state and releasing any resources must be a synchronous call. Any asynchronous calls invoked after emitting this event might be ignored.
|
package/src/common/event.ts
CHANGED
|
@@ -467,3 +467,21 @@ export class AsyncEmitter<T extends WaitUntilEvent> extends Emitter<T> {
|
|
|
467
467
|
}
|
|
468
468
|
|
|
469
469
|
}
|
|
470
|
+
|
|
471
|
+
export class QueueableEmitter<T> extends Emitter<T[]> {
|
|
472
|
+
|
|
473
|
+
currentQueue?: T[];
|
|
474
|
+
|
|
475
|
+
queue(...arg: T[]): void {
|
|
476
|
+
if (!this.currentQueue) {
|
|
477
|
+
this.currentQueue = [];
|
|
478
|
+
}
|
|
479
|
+
this.currentQueue.push(...arg);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
override fire(): void {
|
|
483
|
+
super.fire(this.currentQueue || []);
|
|
484
|
+
this.currentQueue = undefined;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
}
|
|
@@ -104,11 +104,13 @@ export class ElectronContextMenuRenderer extends BrowserContextMenuRenderer {
|
|
|
104
104
|
const menu = this.electronMenuFactory.createElectronContextMenu(menuPath, args, context, contextKeyService, skipSingleRootNode);
|
|
105
105
|
const { x, y } = coordinateFromAnchor(anchor);
|
|
106
106
|
|
|
107
|
+
const windowName = options.context?.ownerDocument.defaultView?.Window.name;
|
|
108
|
+
|
|
107
109
|
const menuHandle = window.electronTheiaCore.popup(menu, x, y, () => {
|
|
108
110
|
if (onHide) {
|
|
109
111
|
onHide();
|
|
110
112
|
}
|
|
111
|
-
});
|
|
113
|
+
}, windowName);
|
|
112
114
|
// native context menu stops the event loop, so there is no keyboard events
|
|
113
115
|
this.context.resetAltPressed();
|
|
114
116
|
return new ElectronContextMenuAccess(menuHandle);
|
|
@@ -75,17 +75,17 @@ const api: TheiaCoreAPI = {
|
|
|
75
75
|
ipcRenderer.send(CHANNEL_SET_MENU, mainMenuId, convertMenu(menu, handlers));
|
|
76
76
|
},
|
|
77
77
|
getSecurityToken: () => ipcRenderer.sendSync(CHANNEL_GET_SECURITY_TOKEN),
|
|
78
|
-
focusWindow: (name
|
|
78
|
+
focusWindow: (name?: string) => ipcRenderer.send(CHANNEL_FOCUS_WINDOW, name),
|
|
79
79
|
showItemInFolder: fsPath => {
|
|
80
80
|
ipcRenderer.send(CHANNEL_SHOW_ITEM_IN_FOLDER, fsPath);
|
|
81
81
|
},
|
|
82
82
|
attachSecurityToken: (endpoint: string) => ipcRenderer.invoke(CHANNEL_ATTACH_SECURITY_TOKEN, endpoint),
|
|
83
83
|
|
|
84
|
-
popup: async function (menu: MenuDto[], x: number, y: number, onClosed: () => void): Promise<number> {
|
|
84
|
+
popup: async function (menu: MenuDto[], x: number, y: number, onClosed: () => void, windowName?: string): Promise<number> {
|
|
85
85
|
const menuId = nextMenuId++;
|
|
86
86
|
const handlers = new Map<number, () => void>();
|
|
87
87
|
commandHandlers.set(menuId, handlers);
|
|
88
|
-
const handle = await ipcRenderer.invoke(CHANNEL_OPEN_POPUP, menuId, convertMenu(menu, handlers), x, y);
|
|
88
|
+
const handle = await ipcRenderer.invoke(CHANNEL_OPEN_POPUP, menuId, convertMenu(menu, handlers), x, y, windowName);
|
|
89
89
|
const closeListener = () => {
|
|
90
90
|
ipcRenderer.removeListener(CHANNEL_ON_CLOSE_POPUP, closeListener);
|
|
91
91
|
commandHandlers.delete(menuId);
|
|
@@ -24,16 +24,12 @@ export class ElectronSecondaryWindowService extends DefaultSecondaryWindowServic
|
|
|
24
24
|
window.electronTheiaCore.focusWindow(win.name);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
protected override
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
window.electronTheiaCore.setMenuBarVisible(false, w.name);
|
|
31
|
-
window.electronTheiaCore.setSecondaryWindowCloseRequestHandler(w.name, () => this.canClose(widget, shell));
|
|
32
|
-
}
|
|
33
|
-
return w;
|
|
27
|
+
protected override windowCreated(newWindow: Window, widget: ExtractableWidget, shell: ApplicationShell): void {
|
|
28
|
+
window.electronTheiaCore.setMenuBarVisible(false, newWindow.name);
|
|
29
|
+
window.electronTheiaCore.setSecondaryWindowCloseRequestHandler(newWindow.name, () => this.canClose(widget, shell));
|
|
34
30
|
}
|
|
35
31
|
private async canClose(widget: ExtractableWidget, shell: ApplicationShell): Promise<boolean> {
|
|
36
|
-
await shell.closeWidget(widget.id
|
|
32
|
+
await shell.closeWidget(widget.id);
|
|
37
33
|
return widget.isDisposed;
|
|
38
34
|
}
|
|
39
35
|
}
|
|
@@ -57,6 +57,9 @@ export class ElectronWindowService extends DefaultWindowService {
|
|
|
57
57
|
this.delegate.openNewDefaultWindow(params);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
override focus(): void {
|
|
61
|
+
window.electronTheiaCore.focusWindow();
|
|
62
|
+
}
|
|
60
63
|
@postConstruct()
|
|
61
64
|
protected init(): void {
|
|
62
65
|
// Update the default zoom level on startup when the preferences event is fired.
|
|
@@ -50,10 +50,10 @@ export interface TheiaCoreAPI {
|
|
|
50
50
|
setMenuBarVisible(visible: boolean, windowName?: string): void;
|
|
51
51
|
setMenu(menu: MenuDto[] | undefined): void;
|
|
52
52
|
|
|
53
|
-
popup(menu: MenuDto[], x: number, y: number, onClosed: () => void): Promise<number>;
|
|
53
|
+
popup(menu: MenuDto[], x: number, y: number, onClosed: () => void, windowName?: string): Promise<number>;
|
|
54
54
|
closePopup(handle: number): void;
|
|
55
55
|
|
|
56
|
-
focusWindow(name
|
|
56
|
+
focusWindow(name?: string): void;
|
|
57
57
|
|
|
58
58
|
showItemInFolder(fsPath: string): void;
|
|
59
59
|
|
|
@@ -115,7 +115,7 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
|
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
// popup menu
|
|
118
|
-
ipcMain.handle(CHANNEL_OPEN_POPUP, (event, menuId, menu, x, y) => {
|
|
118
|
+
ipcMain.handle(CHANNEL_OPEN_POPUP, (event, menuId, menu, x, y, windowName?: string) => {
|
|
119
119
|
const zoom = event.sender.getZoomFactor();
|
|
120
120
|
// TODO: Remove the offset once Electron fixes https://github.com/electron/electron/issues/31641
|
|
121
121
|
const offset = process.platform === 'win32' ? 0 : 2;
|
|
@@ -124,7 +124,14 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
|
|
|
124
124
|
y = Math.round(y * zoom) + offset;
|
|
125
125
|
const popup = Menu.buildFromTemplate(this.fromMenuDto(event.sender, menuId, menu));
|
|
126
126
|
this.openPopups.set(menuId, popup);
|
|
127
|
+
let electronWindow: BrowserWindow | undefined;
|
|
128
|
+
if (windowName) {
|
|
129
|
+
electronWindow = BrowserWindow.getAllWindows().find(win => win.webContents.mainFrame.name === windowName);
|
|
130
|
+
} else {
|
|
131
|
+
electronWindow = BrowserWindow.fromWebContents(event.sender) || undefined;
|
|
132
|
+
}
|
|
127
133
|
popup.popup({
|
|
134
|
+
window: electronWindow,
|
|
128
135
|
callback: () => {
|
|
129
136
|
this.openPopups.delete(menuId);
|
|
130
137
|
event.sender.send(CHANNEL_ON_CLOSE_POPUP, menuId);
|
|
@@ -140,7 +147,9 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
|
|
|
140
147
|
|
|
141
148
|
// focus windows for secondary window support
|
|
142
149
|
ipcMain.on(CHANNEL_FOCUS_WINDOW, (event, windowName) => {
|
|
143
|
-
const electronWindow =
|
|
150
|
+
const electronWindow = windowName
|
|
151
|
+
? BrowserWindow.getAllWindows().find(win => win.webContents.mainFrame.name === windowName)
|
|
152
|
+
: BrowserWindow.fromWebContents(event.sender);
|
|
144
153
|
if (electronWindow) {
|
|
145
154
|
if (electronWindow.isMinimized()) {
|
|
146
155
|
electronWindow.restore();
|