@theia/core 1.46.0-next.153 → 1.46.0-next.196

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 (45) hide show
  1. package/README.md +7 -7
  2. package/i18n/nls.cs.json +5 -2
  3. package/i18n/nls.de.json +5 -2
  4. package/i18n/nls.es.json +5 -2
  5. package/i18n/nls.fr.json +5 -2
  6. package/i18n/nls.hu.json +5 -2
  7. package/i18n/nls.it.json +5 -2
  8. package/i18n/nls.ja.json +5 -2
  9. package/i18n/nls.json +5 -2
  10. package/i18n/nls.pl.json +5 -2
  11. package/i18n/nls.pt-br.json +5 -2
  12. package/i18n/nls.pt-pt.json +5 -2
  13. package/i18n/nls.ru.json +5 -2
  14. package/i18n/nls.zh-cn.json +5 -2
  15. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  16. package/lib/browser/tree/tree-widget.js +6 -1
  17. package/lib/browser/tree/tree-widget.js.map +1 -1
  18. package/lib/electron-browser/preload.d.ts.map +1 -1
  19. package/lib/electron-browser/preload.js +3 -0
  20. package/lib/electron-browser/preload.js.map +1 -1
  21. package/lib/electron-common/electron-api.d.ts +2 -0
  22. package/lib/electron-common/electron-api.d.ts.map +1 -1
  23. package/lib/electron-common/electron-api.js +2 -1
  24. package/lib/electron-common/electron-api.js.map +1 -1
  25. package/lib/electron-main/electron-api-main.d.ts.map +1 -1
  26. package/lib/electron-main/electron-api-main.js +3 -0
  27. package/lib/electron-main/electron-api-main.js.map +1 -1
  28. package/lib/electron-main/electron-main-application.d.ts +17 -1
  29. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  30. package/lib/electron-main/electron-main-application.js +84 -4
  31. package/lib/electron-main/electron-main-application.js.map +1 -1
  32. package/lib/electron-main/theia-electron-window.d.ts +6 -0
  33. package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
  34. package/lib/electron-main/theia-electron-window.js +3 -1
  35. package/lib/electron-main/theia-electron-window.js.map +1 -1
  36. package/lib/node/application-server.js +3 -3
  37. package/lib/node/application-server.js.map +1 -1
  38. package/package.json +6 -6
  39. package/src/browser/tree/tree-widget.tsx +7 -1
  40. package/src/electron-browser/preload.ts +4 -1
  41. package/src/electron-common/electron-api.ts +2 -0
  42. package/src/electron-main/electron-api-main.ts +6 -1
  43. package/src/electron-main/electron-main-application.ts +102 -7
  44. package/src/electron-main/theia-electron-window.ts +9 -1
  45. package/src/node/application-server.ts +3 -3
@@ -56,6 +56,7 @@ export interface TheiaCoreAPI {
56
56
  focusWindow(name?: string): void;
57
57
 
58
58
  showItemInFolder(fsPath: string): void;
59
+ openWithSystemApp(fsPath: string): void;
59
60
 
60
61
  getTitleBarStyleAtStartup(): Promise<string>;
61
62
  setTitleBarStyle(style: string): void;
@@ -112,6 +113,7 @@ export const CHANNEL_FOCUS_WINDOW = 'FocusWindow';
112
113
  export const CHANNEL_SHOW_OPEN = 'ShowOpenDialog';
113
114
  export const CHANNEL_SHOW_SAVE = 'ShowSaveDialog';
114
115
  export const CHANNEL_SHOW_ITEM_IN_FOLDER = 'ShowItemInFolder';
116
+ export const CHANNEL_OPEN_WITH_SYSTEM_APP = 'OpenWithSystemApp';
115
117
  export const CHANNEL_ATTACH_SECURITY_TOKEN = 'AttachSecurityToken';
116
118
 
117
119
  export const CHANNEL_GET_TITLE_STYLE_AT_STARTUP = 'GetTitleStyleAtStartup';
@@ -53,7 +53,8 @@ import {
53
53
  CHANNEL_REQUEST_SECONDARY_CLOSE,
54
54
  CHANNEL_SET_BACKGROUND_COLOR,
55
55
  CHANNEL_WC_METADATA,
56
- CHANNEL_ABOUT_TO_CLOSE
56
+ CHANNEL_ABOUT_TO_CLOSE,
57
+ CHANNEL_OPEN_WITH_SYSTEM_APP
57
58
  } from '../electron-common/electron-api';
58
59
  import { ElectronMainApplication, ElectronMainApplicationContribution } from './electron-main-application';
59
60
  import { Disposable, DisposableCollection, isOSX, MaybePromise } from '../common';
@@ -164,6 +165,10 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
164
165
  shell.showItemInFolder(fsPath);
165
166
  });
166
167
 
168
+ ipcMain.on(CHANNEL_OPEN_WITH_SYSTEM_APP, (event, fsPath) => {
169
+ shell.openPath(fsPath);
170
+ });
171
+
167
172
  ipcMain.handle(CHANNEL_GET_TITLE_STYLE_AT_STARTUP, event => application.getTitleBarStyleAtStartup(event.sender));
168
173
 
169
174
  ipcMain.on(CHANNEL_SET_TITLE_STYLE, (event, style) => application.setTitleBarStyle(event.sender, style));
@@ -22,16 +22,16 @@ import { AddressInfo } from 'net';
22
22
  import { promises as fs } from 'fs';
23
23
  import { existsSync, mkdirSync } from 'fs-extra';
24
24
  import { fork, ForkOptions } from 'child_process';
25
- import { DefaultTheme, FrontendApplicationConfig } from '@theia/application-package/lib/application-props';
25
+ import { DefaultTheme, ElectronFrontendApplicationConfig, FrontendApplicationConfig } from '@theia/application-package/lib/application-props';
26
26
  import URI from '../common/uri';
27
27
  import { FileUri } from '../common/file-uri';
28
- import { Deferred } from '../common/promise-util';
28
+ import { Deferred, timeout } from '../common/promise-util';
29
29
  import { MaybePromise } from '../common/types';
30
30
  import { ContributionProvider } from '../common/contribution-provider';
31
31
  import { ElectronSecurityTokenService } from './electron-security-token-service';
32
32
  import { ElectronSecurityToken } from '../electron-common/electron-token';
33
33
  import Storage = require('electron-store');
34
- import { Disposable, DisposableCollection, isOSX, isWindows } from '../common';
34
+ import { CancellationTokenSource, Disposable, DisposableCollection, isOSX, isWindows } from '../common';
35
35
  import { DEFAULT_WINDOW_HASH, WindowSearchParams } from '../common/window';
36
36
  import { TheiaBrowserWindowOptions, TheiaElectronWindow, TheiaElectronWindowFactory } from './theia-electron-window';
37
37
  import { ElectronMainApplicationGlobals } from './electron-main-constants';
@@ -182,6 +182,7 @@ export class ElectronMainApplication {
182
182
  protected windows = new Map<number, TheiaElectronWindow>();
183
183
  protected restarting = false;
184
184
 
185
+ /** Used to temporarily store the reference to an early created main window */
185
186
  protected initialWindow?: BrowserWindow;
186
187
 
187
188
  get config(): FrontendApplicationConfig {
@@ -287,16 +288,109 @@ export class ElectronMainApplication {
287
288
  return this.didUseNativeWindowFrameOnStart.get(webContents.id) ? 'native' : 'custom';
288
289
  }
289
290
 
291
+ protected async determineSplashScreenBounds(initialWindowBounds: { x: number, y: number, width: number, height: number }):
292
+ Promise<{ x: number, y: number, width: number, height: number }> {
293
+ const splashScreenOptions = this.getSplashScreenOptions();
294
+ const width = splashScreenOptions?.width ?? 640;
295
+ const height = splashScreenOptions?.height ?? 480;
296
+
297
+ // determine the screen on which to show the splash screen via the center of the window to show
298
+ const windowCenterPoint = { x: initialWindowBounds.x + (initialWindowBounds.width / 2), y: initialWindowBounds.y + (initialWindowBounds.height / 2) };
299
+ const { bounds } = screen.getDisplayNearestPoint(windowCenterPoint);
300
+
301
+ // place splash screen center of screen
302
+ const screenCenterPoint = { x: bounds.x + (bounds.width / 2), y: bounds.y + (bounds.height / 2) };
303
+ const x = screenCenterPoint.x - (width / 2);
304
+ const y = screenCenterPoint.y - (height / 2);
305
+
306
+ return {
307
+ x, y, width, height
308
+ };
309
+ }
310
+
311
+ protected isShowWindowEarly(): boolean {
312
+ return !!this.config.electron.showWindowEarly &&
313
+ !('THEIA_ELECTRON_NO_EARLY_WINDOW' in process.env && process.env.THEIA_ELECTRON_NO_EARLY_WINDOW === '1');
314
+ }
315
+
290
316
  protected showInitialWindow(): void {
291
- if (this.config.electron.showWindowEarly &&
292
- !('THEIA_ELECTRON_NO_EARLY_WINDOW' in process.env && process.env.THEIA_ELECTRON_NO_EARLY_WINDOW === '1')) {
293
- console.log('Showing main window early');
317
+ if (this.isShowWindowEarly() || this.isShowSplashScreen()) {
294
318
  app.whenReady().then(async () => {
295
319
  const options = await this.getLastWindowOptions();
320
+ // If we want to show a splash screen, don't auto open the main window
321
+ if (this.isShowSplashScreen()) {
322
+ options.preventAutomaticShow = true;
323
+ }
296
324
  this.initialWindow = await this.createWindow({ ...options });
297
- this.initialWindow.show();
325
+
326
+ if (this.isShowSplashScreen()) {
327
+ console.log('Showing splash screen');
328
+ this.configureAndShowSplashScreen(this.initialWindow);
329
+ }
330
+
331
+ // Show main window early if windows shall be shown early and splash screen is not configured
332
+ if (this.isShowWindowEarly() && !this.isShowSplashScreen()) {
333
+ console.log('Showing main window early');
334
+ this.initialWindow.show();
335
+ }
336
+ });
337
+ }
338
+ }
339
+
340
+ protected async configureAndShowSplashScreen(mainWindow: BrowserWindow): Promise<BrowserWindow> {
341
+ const splashScreenOptions = this.getSplashScreenOptions()!;
342
+ console.debug('SplashScreen options', splashScreenOptions);
343
+
344
+ const splashScreenBounds = await this.determineSplashScreenBounds(mainWindow.getBounds());
345
+ const splashScreenWindow = new BrowserWindow({
346
+ ...splashScreenBounds,
347
+ frame: false,
348
+ alwaysOnTop: true,
349
+ show: false,
350
+ transparent: true,
351
+ });
352
+
353
+ if (this.isShowWindowEarly()) {
354
+ console.log('Showing splash screen early');
355
+ splashScreenWindow.show();
356
+ } else {
357
+ splashScreenWindow.on('ready-to-show', () => {
358
+ splashScreenWindow.show();
298
359
  });
299
360
  }
361
+
362
+ splashScreenWindow.loadFile(path.resolve(this.globals.THEIA_APP_PROJECT_PATH, splashScreenOptions.content!).toString());
363
+
364
+ // close splash screen and show main window once frontend is ready or a timeout is hit
365
+ const cancelTokenSource = new CancellationTokenSource();
366
+ const minTime = timeout(splashScreenOptions.minDuration ?? 0, cancelTokenSource.token);
367
+ const maxTime = timeout(splashScreenOptions.maxDuration ?? 30000, cancelTokenSource.token);
368
+
369
+ const showWindowAndCloseSplashScreen = () => {
370
+ cancelTokenSource.cancel();
371
+ if (!mainWindow.isVisible()) {
372
+ mainWindow.show();
373
+ }
374
+ splashScreenWindow.close();
375
+ };
376
+ TheiaRendererAPI.onApplicationStateChanged(mainWindow.webContents, state => {
377
+ if (state === 'ready') {
378
+ minTime.then(() => showWindowAndCloseSplashScreen());
379
+ }
380
+ });
381
+ maxTime.then(() => showWindowAndCloseSplashScreen());
382
+ return splashScreenWindow;
383
+ }
384
+
385
+ protected isShowSplashScreen(): boolean {
386
+ return typeof this.config.electron.splashScreenOptions === 'object' && !!this.config.electron.splashScreenOptions.content;
387
+ }
388
+
389
+ protected getSplashScreenOptions(): ElectronFrontendApplicationConfig.SplashScreenOptions | undefined {
390
+ if (this.isShowSplashScreen()) {
391
+ return this.config.electron.splashScreenOptions;
392
+ }
393
+ return undefined;
300
394
  }
301
395
 
302
396
  /**
@@ -316,6 +410,7 @@ export class ElectronMainApplication {
316
410
  electronWindow.window.on('focus', () => TheiaRendererAPI.sendWindowEvent(electronWindow.window.webContents, 'focus'));
317
411
  this.attachSaveWindowState(electronWindow.window);
318
412
  this.configureNativeSecondaryWindowCreation(electronWindow.window);
413
+
319
414
  return electronWindow.window;
320
415
  }
321
416
 
@@ -37,6 +37,12 @@ export interface TheiaBrowserWindowOptions extends BrowserWindowConstructorOptio
37
37
  * in which case we want to invalidate the stored options and use the default options instead.
38
38
  */
39
39
  screenLayout?: string;
40
+ /**
41
+ * By default, the window will be shown as soon as the content is ready to render.
42
+ * This can be prevented by handing over preventAutomaticShow: `true`.
43
+ * Use this for fine-grained control over when to show the window, e.g. to coordinate with a splash screen.
44
+ */
45
+ preventAutomaticShow?: boolean;
40
46
  }
41
47
 
42
48
  export const TheiaBrowserWindowOptions = Symbol('TheiaBrowserWindowOptions');
@@ -76,7 +82,9 @@ export class TheiaElectronWindow {
76
82
  protected init(): void {
77
83
  this._window = new BrowserWindow(this.options);
78
84
  this._window.setMenuBarVisibility(false);
79
- this.attachReadyToShow();
85
+ if (!this.options.preventAutomaticShow) {
86
+ this.attachReadyToShow();
87
+ }
80
88
  this.restoreMaximizedState();
81
89
  this.attachCloseListeners();
82
90
  this.trackApplicationState();
@@ -26,9 +26,9 @@ export class ApplicationServerImpl implements ApplicationServer {
26
26
  protected readonly applicationPackage: ApplicationPackage;
27
27
 
28
28
  getExtensionsInfos(): Promise<ExtensionInfo[]> {
29
- const extensions = this.applicationPackage.extensionPackages;
30
- const infos: ExtensionInfo[] = extensions.map(extension => ({ name: extension.name, version: extension.version }));
31
- return Promise.resolve(infos);
29
+ // @ts-expect-error
30
+ const appInfo: ExtensionInfo[] = globalThis.extensionInfo;
31
+ return Promise.resolve(appInfo);
32
32
  }
33
33
 
34
34
  getApplicationInfo(): Promise<ApplicationInfo | undefined> {