@theia/core 1.38.0 → 1.39.0-next.11

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.
Files changed (129) hide show
  1. package/README.md +7 -7
  2. package/lib/browser/about-dialog.d.ts +2 -1
  3. package/lib/browser/about-dialog.d.ts.map +1 -1
  4. package/lib/browser/about-dialog.js +5 -2
  5. package/lib/browser/about-dialog.js.map +1 -1
  6. package/lib/browser/dialogs.d.ts +15 -9
  7. package/lib/browser/dialogs.d.ts.map +1 -1
  8. package/lib/browser/dialogs.js +67 -54
  9. package/lib/browser/dialogs.js.map +1 -1
  10. package/lib/browser/frontend-application-bindings.js +1 -1
  11. package/lib/browser/frontend-application-bindings.js.map +1 -1
  12. package/lib/browser/frontend-application-module.js +1 -1
  13. package/lib/browser/frontend-application-module.js.map +1 -1
  14. package/lib/browser/keyboard/browser-keyboard-layout-provider.d.ts +2 -1
  15. package/lib/browser/keyboard/browser-keyboard-layout-provider.d.ts.map +1 -1
  16. package/lib/browser/keyboard/browser-keyboard-layout-provider.js +6 -3
  17. package/lib/browser/keyboard/browser-keyboard-layout-provider.js.map +1 -1
  18. package/lib/browser/preferences/injectable-preference-proxy.d.ts +1 -1
  19. package/lib/browser/preferences/injectable-preference-proxy.d.ts.map +1 -1
  20. package/lib/browser/preferences/injectable-preference-proxy.js +5 -4
  21. package/lib/browser/preferences/injectable-preference-proxy.js.map +1 -1
  22. package/lib/browser/saveable.d.ts.map +1 -1
  23. package/lib/browser/saveable.js +4 -2
  24. package/lib/browser/saveable.js.map +1 -1
  25. package/lib/browser/secondary-window-handler.d.ts +2 -2
  26. package/lib/browser/secondary-window-handler.d.ts.map +1 -1
  27. package/lib/browser/secondary-window-handler.js +8 -34
  28. package/lib/browser/secondary-window-handler.js.map +1 -1
  29. package/lib/browser/styling-service.d.ts +5 -2
  30. package/lib/browser/styling-service.d.ts.map +1 -1
  31. package/lib/browser/styling-service.js +15 -5
  32. package/lib/browser/styling-service.js.map +1 -1
  33. package/lib/browser/widgets/widget.d.ts +1 -0
  34. package/lib/browser/widgets/widget.d.ts.map +1 -1
  35. package/lib/browser/widgets/widget.js +7 -3
  36. package/lib/browser/widgets/widget.js.map +1 -1
  37. package/lib/browser/window/default-secondary-window-service.d.ts +5 -3
  38. package/lib/browser/window/default-secondary-window-service.d.ts.map +1 -1
  39. package/lib/browser/window/default-secondary-window-service.js +62 -18
  40. package/lib/browser/window/default-secondary-window-service.js.map +1 -1
  41. package/lib/browser/window/secondary-window-service.d.ts +3 -1
  42. package/lib/browser/window/secondary-window-service.d.ts.map +1 -1
  43. package/lib/browser/window/secondary-window-service.js.map +1 -1
  44. package/lib/common/logger.d.ts +3 -6
  45. package/lib/common/logger.d.ts.map +1 -1
  46. package/lib/common/logger.js +29 -22
  47. package/lib/common/logger.js.map +1 -1
  48. package/lib/common/message-rpc/rpc-message-encoder.d.ts +3 -3
  49. package/lib/common/message-rpc/rpc-message-encoder.d.ts.map +1 -1
  50. package/lib/common/message-rpc/rpc-message-encoder.js +2 -2
  51. package/lib/common/message-rpc/rpc-message-encoder.js.map +1 -1
  52. package/lib/common/message-rpc/rpc-protocol.d.ts +1 -1
  53. package/lib/common/message-rpc/rpc-protocol.d.ts.map +1 -1
  54. package/lib/common/message-rpc/rpc-protocol.js +8 -4
  55. package/lib/common/message-rpc/rpc-protocol.js.map +1 -1
  56. package/lib/common/messaging/proxy-factory.d.ts +6 -6
  57. package/lib/common/messaging/proxy-factory.d.ts.map +1 -1
  58. package/lib/common/messaging/proxy-factory.js +15 -10
  59. package/lib/common/messaging/proxy-factory.js.map +1 -1
  60. package/lib/common/performance/stopwatch.d.ts +1 -1
  61. package/lib/common/performance/stopwatch.d.ts.map +1 -1
  62. package/lib/common/performance/stopwatch.js.map +1 -1
  63. package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.d.ts +1 -1
  64. package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.d.ts.map +1 -1
  65. package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.js +2 -2
  66. package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.js.map +1 -1
  67. package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts +2 -1
  68. package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts.map +1 -1
  69. package/lib/electron-browser/menu/electron-context-menu-renderer.js +5 -2
  70. package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
  71. package/lib/electron-browser/preload.d.ts.map +1 -1
  72. package/lib/electron-browser/preload.js +21 -16
  73. package/lib/electron-browser/preload.js.map +1 -1
  74. package/lib/electron-browser/window/electron-secondary-window-service.d.ts +3 -1
  75. package/lib/electron-browser/window/electron-secondary-window-service.d.ts.map +1 -1
  76. package/lib/electron-browser/window/electron-secondary-window-service.js +7 -2
  77. package/lib/electron-browser/window/electron-secondary-window-service.js.map +1 -1
  78. package/lib/electron-common/electron-api.d.ts +3 -1
  79. package/lib/electron-common/electron-api.d.ts.map +1 -1
  80. package/lib/electron-common/electron-api.js +2 -1
  81. package/lib/electron-common/electron-api.js.map +1 -1
  82. package/lib/electron-main/electron-api-main.d.ts +1 -0
  83. package/lib/electron-main/electron-api-main.d.ts.map +1 -1
  84. package/lib/electron-main/electron-api-main.js +19 -1
  85. package/lib/electron-main/electron-api-main.js.map +1 -1
  86. package/lib/electron-main/theia-electron-window.d.ts +1 -0
  87. package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
  88. package/lib/electron-main/theia-electron-window.js +32 -0
  89. package/lib/electron-main/theia-electron-window.js.map +1 -1
  90. package/lib/electron-node/token/electron-token-validator.d.ts +1 -1
  91. package/lib/electron-node/token/electron-token-validator.d.ts.map +1 -1
  92. package/lib/electron-node/token/electron-token-validator.js +2 -2
  93. package/lib/electron-node/token/electron-token-validator.js.map +1 -1
  94. package/lib/node/backend-application.d.ts +1 -0
  95. package/lib/node/backend-application.d.ts.map +1 -1
  96. package/lib/node/backend-application.js +5 -2
  97. package/lib/node/backend-application.js.map +1 -1
  98. package/lib/node/hosting/backend-application-hosts.d.ts +1 -1
  99. package/lib/node/hosting/backend-application-hosts.d.ts.map +1 -1
  100. package/lib/node/hosting/backend-application-hosts.js +2 -2
  101. package/lib/node/hosting/backend-application-hosts.js.map +1 -1
  102. package/package.json +5 -5
  103. package/src/browser/about-dialog.tsx +5 -1
  104. package/src/browser/dialogs.ts +69 -52
  105. package/src/browser/frontend-application-bindings.ts +1 -1
  106. package/src/browser/frontend-application-module.ts +2 -2
  107. package/src/browser/keyboard/browser-keyboard-layout-provider.ts +5 -1
  108. package/src/browser/preferences/injectable-preference-proxy.ts +5 -4
  109. package/src/browser/saveable.ts +4 -2
  110. package/src/browser/secondary-window-handler.ts +7 -38
  111. package/src/browser/styling-service.ts +17 -6
  112. package/src/browser/widgets/widget.ts +4 -0
  113. package/src/browser/window/default-secondary-window-service.ts +67 -18
  114. package/src/browser/window/secondary-window-service.ts +4 -1
  115. package/src/common/logger.ts +12 -14
  116. package/src/common/message-rpc/rpc-message-encoder.ts +4 -4
  117. package/src/common/message-rpc/rpc-protocol.ts +8 -4
  118. package/src/common/messaging/proxy-factory.ts +17 -15
  119. package/src/common/performance/stopwatch.ts +1 -1
  120. package/src/electron-browser/keyboard/electron-keyboard-layout-change-notifier.ts +1 -1
  121. package/src/electron-browser/menu/electron-context-menu-renderer.ts +5 -1
  122. package/src/electron-browser/preload.ts +22 -2
  123. package/src/electron-browser/window/electron-secondary-window-service.ts +8 -2
  124. package/src/electron-common/electron-api.ts +5 -1
  125. package/src/electron-main/electron-api-main.ts +22 -2
  126. package/src/electron-main/theia-electron-window.ts +30 -0
  127. package/src/electron-node/token/electron-token-validator.ts +1 -1
  128. package/src/node/backend-application.ts +4 -0
  129. package/src/node/hosting/backend-application-hosts.ts +1 -1
@@ -13,6 +13,7 @@
13
13
  //
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  //
16
+ import { IpcRendererEvent } from '@theia/electron/shared/electron';
16
17
  import { Disposable } from '../common/disposable';
17
18
  import { StopReason } from '../common/frontend-application-state';
18
19
  import { NativeKeyboardLayout } from '../common/keyboard/keyboard-layout-provider';
@@ -24,7 +25,7 @@ import {
24
25
  CHANNEL_ON_WINDOW_EVENT, CHANNEL_GET_ZOOM_LEVEL, CHANNEL_SET_ZOOM_LEVEL, CHANNEL_IS_FULL_SCREENABLE, CHANNEL_TOGGLE_FULL_SCREEN,
25
26
  CHANNEL_IS_FULL_SCREEN, CHANNEL_SET_MENU_BAR_VISIBLE, CHANNEL_REQUEST_CLOSE, CHANNEL_SET_TITLE_STYLE, CHANNEL_RESTART,
26
27
  CHANNEL_REQUEST_RELOAD, CHANNEL_APP_STATE_CHANGED, CHANNEL_SHOW_ITEM_IN_FOLDER, CHANNEL_READ_CLIPBOARD, CHANNEL_WRITE_CLIPBOARD,
27
- CHANNEL_KEYBOARD_LAYOUT_CHANGED, CHANNEL_IPC_CONNECTION, InternalMenuDto
28
+ CHANNEL_KEYBOARD_LAYOUT_CHANGED, CHANNEL_IPC_CONNECTION, InternalMenuDto, CHANNEL_REQUEST_SECONDARY_CLOSE
28
29
  } from '../electron-common/electron-api';
29
30
 
30
31
  // eslint-disable-next-line import/no-extraneous-dependencies
@@ -71,7 +72,7 @@ const api: TheiaCoreAPI = {
71
72
  commandHandlers.set(mainMenuId, handlers);
72
73
  ipcRenderer.send(CHANNEL_SET_MENU, mainMenuId, convertMenu(menu, handlers));
73
74
  },
74
- getSecurityToken: () => ipcRenderer.invoke(CHANNEL_GET_SECURITY_TOKEN),
75
+ getSecurityToken: () => ipcRenderer.sendSync(CHANNEL_GET_SECURITY_TOKEN),
75
76
  focusWindow: (name: string) => ipcRenderer.send(CHANNEL_FOCUS_WINDOW, name),
76
77
  showItemInFolder: fsPath => {
77
78
  ipcRenderer.send(CHANNEL_SHOW_ITEM_IN_FOLDER, fsPath);
@@ -138,6 +139,25 @@ const api: TheiaCoreAPI = {
138
139
  });
139
140
  },
140
141
 
142
+ setSecondaryWindowCloseRequestHandler(windowName: string, handler: () => Promise<boolean>): void {
143
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
144
+ const listener: (event: IpcRendererEvent, ...args: any[]) => void = async (event, name, confirmChannel, cancelChannel) => {
145
+ if (name === windowName) {
146
+ try {
147
+ if (await handler()) {
148
+ event.sender.send(confirmChannel);
149
+ ipcRenderer.removeListener(CHANNEL_REQUEST_SECONDARY_CLOSE, listener);
150
+ return;
151
+ };
152
+ } catch (e) {
153
+ console.warn('exception in close handler ', e);
154
+ }
155
+ event.sender.send(cancelChannel);
156
+ }
157
+ };
158
+ ipcRenderer.on(CHANNEL_REQUEST_SECONDARY_CLOSE, listener);
159
+ },
160
+
141
161
  toggleDevTools: function (): void {
142
162
  ipcRenderer.send(CHANNEL_TOGGLE_DEVTOOLS);
143
163
  },
@@ -16,6 +16,7 @@
16
16
 
17
17
  import { injectable } from 'inversify';
18
18
  import { DefaultSecondaryWindowService } from '../../browser/window/default-secondary-window-service';
19
+ import { ApplicationShell, ExtractableWidget } from 'src/browser';
19
20
 
20
21
  @injectable()
21
22
  export class ElectronSecondaryWindowService extends DefaultSecondaryWindowService {
@@ -23,11 +24,16 @@ export class ElectronSecondaryWindowService extends DefaultSecondaryWindowServic
23
24
  window.electronTheiaCore.focusWindow(win.name);
24
25
  }
25
26
 
26
- protected override doCreateSecondaryWindow(onClose?: (closedWin: Window) => void): Window | undefined {
27
- const w = super.doCreateSecondaryWindow(onClose);
27
+ protected override doCreateSecondaryWindow(widget: ExtractableWidget, shell: ApplicationShell): Window | undefined {
28
+ const w = super.doCreateSecondaryWindow(widget, shell);
28
29
  if (w) {
29
30
  window.electronTheiaCore.setMenuBarVisible(false, w.name);
31
+ window.electronTheiaCore.setSecondaryWindowCloseRequestHandler(w.name, () => this.canClose(widget, shell));
30
32
  }
31
33
  return w;
32
34
  }
35
+ private async canClose(widget: ExtractableWidget, shell: ApplicationShell): Promise<boolean> {
36
+ await shell.closeWidget(widget.id, undefined);
37
+ return widget.isDisposed;
38
+ }
33
39
  }
@@ -41,7 +41,7 @@ export type InternalMenuDto = Omit<MenuDto, 'execute' | 'submenu'> & {
41
41
  export type WindowEvent = 'maximize' | 'unmaximize' | 'focus';
42
42
 
43
43
  export interface TheiaCoreAPI {
44
- getSecurityToken: () => Promise<string>;
44
+ getSecurityToken: () => string;
45
45
  attachSecurityToken: (endpoint: string) => Promise<void>;
46
46
 
47
47
  setMenuBarVisible(visible: boolean, windowName?: string): void;
@@ -64,6 +64,8 @@ export interface TheiaCoreAPI {
64
64
  onWindowEvent(event: WindowEvent, handler: () => void): Disposable;
65
65
  setCloseRequestHandler(handler: (reason: StopReason) => Promise<boolean>): void;
66
66
 
67
+ setSecondaryWindowCloseRequestHandler(windowName: string, handler: () => Promise<boolean>): void;
68
+
67
69
  toggleDevTools(): void;
68
70
  getZoomLevel(): Promise<number>;
69
71
  setZoomLevel(desired: number): void;
@@ -121,6 +123,8 @@ export const CHANNEL_IS_FULL_SCREENABLE = 'IsFullScreenable';
121
123
  export const CHANNEL_IS_FULL_SCREEN = 'IsFullScreen';
122
124
  export const CHANNEL_TOGGLE_FULL_SCREEN = 'ToggleFullScreen';
123
125
 
126
+ export const CHANNEL_REQUEST_SECONDARY_CLOSE = 'RequestSecondaryClose';
127
+
124
128
  export const CHANNEL_REQUEST_CLOSE = 'RequestClose';
125
129
  export const CHANNEL_REQUEST_RELOAD = 'RequestReload';
126
130
  export const CHANNEL_RESTART = 'Restart';
@@ -49,7 +49,8 @@ import {
49
49
  InternalMenuDto,
50
50
  CHANNEL_SET_MENU_BAR_VISIBLE,
51
51
  CHANNEL_TOGGLE_FULL_SCREEN,
52
- CHANNEL_IS_MAXIMIZED
52
+ CHANNEL_IS_MAXIMIZED,
53
+ CHANNEL_REQUEST_SECONDARY_CLOSE
53
54
  } from '../electron-common/electron-api';
54
55
  import { ElectronMainApplication, ElectronMainApplicationContribution } from './electron-main-application';
55
56
  import { Disposable, DisposableCollection, isOSX, MaybePromise } from '../common';
@@ -64,7 +65,9 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
64
65
 
65
66
  onStart(application: ElectronMainApplication): MaybePromise<void> {
66
67
  // electron security token
67
- ipcMain.handle(CHANNEL_GET_SECURITY_TOKEN, () => this.electronSecurityToken.value);
68
+ ipcMain.on(CHANNEL_GET_SECURITY_TOKEN, event => {
69
+ event.returnValue = this.electronSecurityToken.value;
70
+ });
68
71
 
69
72
  ipcMain.handle(CHANNEL_ATTACH_SECURITY_TOKEN, (event, endpoint) => session.defaultSession.cookies.set({
70
73
  url: endpoint,
@@ -265,6 +268,23 @@ export namespace TheiaRendererAPI {
265
268
  }).finally(() => disposables.dispose());
266
269
  }
267
270
 
271
+ export function requestSecondaryClose(mainWindow: WebContents, secondaryWindow: WebContents): Promise<boolean> {
272
+ const channelNr = nextReplyChannel++;
273
+ const confirmChannel = `confirm-${channelNr}`;
274
+ const cancelChannel = `cancel-${channelNr}`;
275
+ const disposables = new DisposableCollection();
276
+
277
+ return new Promise<boolean>(resolve => {
278
+ mainWindow.send(CHANNEL_REQUEST_SECONDARY_CLOSE, secondaryWindow.mainFrame.name, confirmChannel, cancelChannel);
279
+ createDisposableListener(ipcMain, confirmChannel, e => {
280
+ resolve(true);
281
+ }, disposables);
282
+ createDisposableListener(ipcMain, cancelChannel, e => {
283
+ resolve(false);
284
+ }, disposables);
285
+ }).finally(() => disposables.dispose());
286
+ }
287
+
268
288
  export function onRequestReload(wc: WebContents, handler: () => void): Disposable {
269
289
  return createWindowListener(wc, CHANNEL_REQUEST_RELOAD, handler);
270
290
  }
@@ -44,6 +44,12 @@ export const TheiaBrowserWindowOptions = Symbol('TheiaBrowserWindowOptions');
44
44
  export const WindowApplicationConfig = Symbol('WindowApplicationConfig');
45
45
  export type WindowApplicationConfig = FrontendApplicationConfig;
46
46
 
47
+ enum ClosingState {
48
+ initial,
49
+ inProgress,
50
+ readyToClose
51
+ }
52
+
47
53
  @injectable()
48
54
  export class TheiaElectronWindow {
49
55
  @inject(TheiaBrowserWindowOptions) protected readonly options: TheiaBrowserWindowOptions;
@@ -75,8 +81,32 @@ export class TheiaElectronWindow {
75
81
  this.attachCloseListeners();
76
82
  this.trackApplicationState();
77
83
  this.attachReloadListener();
84
+ this.attachSecondaryWindowListener();
78
85
  }
79
86
 
87
+ protected attachSecondaryWindowListener(): void {
88
+ createDisposableListener(this._window.webContents, 'did-create-window', (newWindow: BrowserWindow) => {
89
+ let closingState = ClosingState.initial;
90
+ newWindow.on('close', event => {
91
+ if (closingState === ClosingState.initial) {
92
+ closingState = ClosingState.inProgress;
93
+ event.preventDefault();
94
+ TheiaRendererAPI.requestSecondaryClose(this._window.webContents, newWindow.webContents).then(shouldClose => {
95
+ if (shouldClose) {
96
+ closingState = ClosingState.readyToClose;
97
+ newWindow.close();
98
+ } else {
99
+ closingState = ClosingState.initial;
100
+ }
101
+ });
102
+ } else if (closingState === ClosingState.inProgress) {
103
+ // When the extracted widget is disposed programmatically, a dispose listener on it will try to close the window.
104
+ // if we dispose the widget because of closing the window, we'll get a recursive call to window.close()
105
+ event.preventDefault();
106
+ }
107
+ });
108
+ });
109
+ }
80
110
  /**
81
111
  * Only show the window when the content is ready.
82
112
  */
@@ -31,7 +31,7 @@ export class ElectronTokenValidator implements WsRequestValidatorContribution {
31
31
  protected electronSecurityToken: ElectronSecurityToken;
32
32
 
33
33
  @postConstruct()
34
- protected postConstruct(): void {
34
+ protected init(): void {
35
35
  this.electronSecurityToken = this.getToken();
36
36
  }
37
37
 
@@ -196,6 +196,10 @@ export class BackendApplication {
196
196
  }
197
197
 
198
198
  @postConstruct()
199
+ protected init(): void {
200
+ this.configure();
201
+ }
202
+
199
203
  protected async configure(): Promise<void> {
200
204
  // Do not await the initialization because contributions are expected to handle
201
205
  // concurrent initialize/configure in undefined order if they provide both
@@ -39,7 +39,7 @@ export class BackendApplicationHosts {
39
39
  }
40
40
 
41
41
  @postConstruct()
42
- protected postConstruct(): void {
42
+ protected init(): void {
43
43
  const theiaHostsEnv = process.env['THEIA_HOSTS'];
44
44
  if (theiaHostsEnv) {
45
45
  theiaHostsEnv.split(',').forEach(host => {