@theia/core 1.76.0 → 1.77.0-next.1

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 (38) hide show
  1. package/lib/browser/catalog.json +209 -7
  2. package/lib/browser/menu/browser-menu-plugin.d.ts +42 -1
  3. package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
  4. package/lib/browser/menu/browser-menu-plugin.js +152 -5
  5. package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
  6. package/lib/browser/shell/application-shell.js +1 -1
  7. package/lib/browser/shell/application-shell.js.map +1 -1
  8. package/lib/common/core-preferences.d.ts +1 -1
  9. package/lib/common/core-preferences.d.ts.map +1 -1
  10. package/lib/common/core-preferences.js +2 -1
  11. package/lib/common/core-preferences.js.map +1 -1
  12. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +5 -0
  13. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  14. package/lib/electron-browser/menu/electron-main-menu-factory.js +39 -8
  15. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  16. package/lib/electron-browser/menu/electron-menu-contribution.d.ts +8 -1
  17. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  18. package/lib/electron-browser/menu/electron-menu-contribution.js +50 -4
  19. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  20. package/lib/electron-browser/preload.d.ts.map +1 -1
  21. package/lib/electron-browser/preload.js +1 -0
  22. package/lib/electron-browser/preload.js.map +1 -1
  23. package/lib/electron-common/electron-api.d.ts +2 -0
  24. package/lib/electron-common/electron-api.d.ts.map +1 -1
  25. package/lib/electron-common/electron-api.js +2 -1
  26. package/lib/electron-common/electron-api.js.map +1 -1
  27. package/lib/electron-main/electron-api-main.d.ts.map +1 -1
  28. package/lib/electron-main/electron-api-main.js +15 -0
  29. package/lib/electron-main/electron-api-main.js.map +1 -1
  30. package/package.json +4 -4
  31. package/src/browser/menu/browser-menu-plugin.ts +169 -6
  32. package/src/browser/shell/application-shell.ts +1 -1
  33. package/src/common/core-preferences.ts +3 -2
  34. package/src/electron-browser/menu/electron-main-menu-factory.ts +45 -7
  35. package/src/electron-browser/menu/electron-menu-contribution.ts +50 -5
  36. package/src/electron-browser/preload.ts +3 -1
  37. package/src/electron-common/electron-api.ts +2 -0
  38. package/src/electron-main/electron-api-main.ts +16 -1
@@ -18,7 +18,7 @@ import { injectable, inject } from 'inversify';
18
18
  import { Menu, MenuBar, Menu as MenuWidget, Widget } from '@lumino/widgets';
19
19
  import { CommandRegistry as LuminoCommandRegistry } from '@lumino/commands';
20
20
  import {
21
- environment, DisposableCollection,
21
+ environment, Disposable, DisposableCollection,
22
22
  AcceleratorSource,
23
23
  ArrayUtils,
24
24
  PreferenceService
@@ -92,7 +92,7 @@ export class BrowserMainMenuFactory implements MenuWidgetFactory {
92
92
  }
93
93
 
94
94
  protected showMenuBar(menuBar: DynamicMenuBarWidget, preference = this.getMenuBarVisibility()): void {
95
- if (preference && ['classic', 'visible'].includes(preference)) {
95
+ if (preference && ['classic', 'visible', 'toggle'].includes(preference)) {
96
96
  menuBar.clearMenus();
97
97
  this.fillMenuBar(menuBar);
98
98
  } else {
@@ -432,6 +432,11 @@ export class BrowserMenuBarContribution implements FrontendApplicationContributi
432
432
  @inject(PreferenceService)
433
433
  protected readonly preferenceService: PreferenceService;
434
434
 
435
+ protected toggleModeListeners = new DisposableCollection();
436
+
437
+ protected menuWidget?: MenuBarWidget;
438
+ protected logoWidget?: Widget;
439
+
435
440
  constructor(
436
441
  @inject(BrowserMainMenuFactory) protected readonly factory: BrowserMainMenuFactory
437
442
  ) { }
@@ -449,20 +454,178 @@ export class BrowserMenuBarContribution implements FrontendApplicationContributi
449
454
  shell.addWidget(logo, { area: 'top' });
450
455
  const menu = this.factory.createMenuBar();
451
456
  shell.addWidget(menu, { area: 'top' });
452
- // Hiding the menu is only necessary in electron
453
- // In the browser we hide the whole top panel
457
+ this.menuWidget = menu;
458
+ this.logoWidget = logo;
454
459
  if (environment.electron.is()) {
455
460
  this.preferenceService.ready.then(() => {
456
- menu.setHidden(['compact', 'hidden'].includes(this.preferenceService.get('window.menuBarVisibility', '')));
461
+ this.updateElectronMenuToggleMode(menu, logo);
462
+ });
463
+ this.preferenceService.onPreferenceChanged(change => {
464
+ if (change.preferenceName === 'window.menuBarVisibility') {
465
+ this.updateElectronMenuToggleMode(menu, logo);
466
+ }
467
+ });
468
+ } else {
469
+ // In the browser, the whole top panel is hidden for compact/hidden/toggle
470
+ // (handled by ApplicationShell). For toggle mode, this installs an Alt-key
471
+ // listener that temporarily shows the top panel.
472
+ this.preferenceService.ready.then(() => {
473
+ this.updateBrowserMenuToggleMode(menu);
457
474
  });
458
475
  this.preferenceService.onPreferenceChanged(change => {
459
476
  if (change.preferenceName === 'window.menuBarVisibility') {
460
- menu.setHidden(['compact', 'hidden'].includes(this.preferenceService.get('window.menuBarVisibility', 'classic')));
477
+ this.updateBrowserMenuToggleMode(menu);
461
478
  }
462
479
  });
463
480
  }
464
481
  }
465
482
 
483
+ /**
484
+ * Manages Lumino menu bar visibility and Alt-key toggling in Electron.
485
+ *
486
+ * With native title bar, the native Electron menu bar handles toggle via
487
+ * `autoHideMenuBar`, so the Lumino menu bar is simply hidden.
488
+ *
489
+ * With custom title bar, the Lumino menu bar is the only menu bar visible
490
+ * to the user. For 'toggle' mode, an Alt-key listener is installed to
491
+ * show/hide the menu bar widget.
492
+ */
493
+ protected updateElectronMenuToggleMode(menu: MenuBarWidget, logo: Widget): void {
494
+ this.toggleModeListeners.dispose();
495
+ const pref = this.preferenceService.get<string>('window.menuBarVisibility', 'classic');
496
+ this.applyElectronMenuBarVisibility(menu, logo, pref);
497
+ if (pref === 'toggle') {
498
+ this.toggleModeListeners = this.installAltKeyToggle(menu, () => this.getElectronToggleTargets(menu, logo));
499
+ }
500
+ }
501
+
502
+ /**
503
+ * Establishes the resting visibility of the menu bar widgets in Electron, i.e. the state
504
+ * a clean Alt press toggles away from in 'toggle' mode.
505
+ */
506
+ protected applyElectronMenuBarVisibility(menu: MenuBarWidget, logo: Widget, pref: string): void {
507
+ const shouldHide = ['compact', 'hidden', 'toggle'].includes(pref);
508
+ menu.setHidden(shouldHide);
509
+ logo.setHidden(shouldHide);
510
+ }
511
+
512
+ /**
513
+ * The widgets a clean Alt press shows and hides in 'toggle' mode in Electron.
514
+ */
515
+ protected getElectronToggleTargets(menu: MenuBarWidget, logo: Widget): Widget[] {
516
+ return [menu, logo];
517
+ }
518
+
519
+ /**
520
+ * Manages Alt-key toggle behavior for 'toggle' mode in the browser.
521
+ * The top panel's initial visibility is handled by {@link ApplicationShell.setTopPanelVisibility};
522
+ * this method only installs or removes the Alt-key listener.
523
+ */
524
+ protected updateBrowserMenuToggleMode(menu: MenuBarWidget): void {
525
+ this.toggleModeListeners.dispose();
526
+ const pref = this.preferenceService.get<string>('window.menuBarVisibility', 'classic');
527
+ if (pref === 'toggle') {
528
+ this.toggleModeListeners = this.installAltKeyToggle(menu, () => [this.shell.topPanel]);
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Installs Alt-key listeners to toggle menu bar visibility.
534
+ * A clean Alt press (press and release without other keys) shows the
535
+ * given toggle targets and focuses the first menu. Pressing Alt again
536
+ * or clicking outside hides them.
537
+ *
538
+ * @param menu the menu bar widget to focus when shown
539
+ * @param toggleTargets supplies the widgets to show/hide on Alt toggle. It is consulted on
540
+ * each gesture, because the targets can depend on state that changes while the listener is
541
+ * installed, e.g. whether the window is in full screen.
542
+ */
543
+ protected installAltKeyToggle(menu: MenuBarWidget, toggleTargets: () => Widget[]): DisposableCollection {
544
+ const disposables = new DisposableCollection();
545
+ let altKeyPressed = false;
546
+ let lastKeyWasAlt = false;
547
+
548
+ const isHidden = (): boolean => toggleTargets().some(w => w.isHidden);
549
+
550
+ const hide = (): void => {
551
+ for (const w of toggleTargets()) {
552
+ w.setHidden(true);
553
+ }
554
+ };
555
+
556
+ const show = (): void => {
557
+ for (const w of toggleTargets()) {
558
+ w.setHidden(false);
559
+ }
560
+ };
561
+
562
+ const onKeyDown = (e: KeyboardEvent): void => {
563
+ if (e.key === 'Alt') {
564
+ if (!e.repeat) {
565
+ altKeyPressed = true;
566
+ lastKeyWasAlt = true;
567
+ }
568
+ } else {
569
+ // Any other key invalidates the Alt-only gesture
570
+ lastKeyWasAlt = false;
571
+ }
572
+ };
573
+
574
+ // Mouse interaction while Alt is held is a modifier gesture of its own, e.g. Alt+click to add a
575
+ // cursor or Alt+scroll to scroll faster, so it invalidates the Alt-only gesture as any other key does.
576
+ const onPointerInteraction = (): void => {
577
+ lastKeyWasAlt = false;
578
+ };
579
+
580
+ const onKeyUp = (e: KeyboardEvent): void => {
581
+ if (e.key !== 'Alt') {
582
+ return;
583
+ }
584
+ const wasCleanAltPress = altKeyPressed && lastKeyWasAlt;
585
+ altKeyPressed = false;
586
+ lastKeyWasAlt = false;
587
+ if (!wasCleanAltPress) {
588
+ return;
589
+ }
590
+ // Keep the browser from acting on the solitary Alt press itself: Firefox, for
591
+ // instance, focuses its own menu bar, which would then toggle along with ours.
592
+ e.preventDefault();
593
+ if (isHidden()) {
594
+ show();
595
+ menu.activeIndex = 0;
596
+ menu.node.focus();
597
+ } else {
598
+ hide();
599
+ }
600
+ };
601
+
602
+ // When a menu closes and focus leaves the menu bar, hide it again
603
+ const onFocusOut = (): void => {
604
+ // Use setTimeout to allow focus to settle (e.g. focus moving between menu items)
605
+ setTimeout(() => {
606
+ if (!isHidden() && !menu.node.contains(document.activeElement)) {
607
+ hide();
608
+ }
609
+ }, 100);
610
+ };
611
+
612
+ document.addEventListener('keydown', onKeyDown, true);
613
+ document.addEventListener('keyup', onKeyUp, true);
614
+ document.addEventListener('mousedown', onPointerInteraction, true);
615
+ document.addEventListener('wheel', onPointerInteraction, { capture: true, passive: true });
616
+ menu.node.addEventListener('focusout', onFocusOut);
617
+
618
+ disposables.push(Disposable.create(() => {
619
+ document.removeEventListener('keydown', onKeyDown, true);
620
+ document.removeEventListener('keyup', onKeyUp, true);
621
+ document.removeEventListener('mousedown', onPointerInteraction, true);
622
+ document.removeEventListener('wheel', onPointerInteraction, true);
623
+ menu.node.removeEventListener('focusout', onFocusOut);
624
+ }));
625
+
626
+ return disposables;
627
+ }
628
+
466
629
  protected createLogo(): Widget {
467
630
  const logo = new Widget();
468
631
  logo.id = 'theia:icon';
@@ -422,7 +422,7 @@ export class ApplicationShell extends Widget {
422
422
  }
423
423
 
424
424
  protected setTopPanelVisibility(preference: string): void {
425
- const hiddenPreferences = ['compact', 'hidden'];
425
+ const hiddenPreferences = ['compact', 'hidden', 'toggle'];
426
426
  this.topPanel.setHidden(hiddenPreferences.includes(preference));
427
427
  }
428
428
 
@@ -92,10 +92,11 @@ export const corePreferenceSchema: PreferenceSchema = {
92
92
  },
93
93
  'window.menuBarVisibility': {
94
94
  type: 'string',
95
- enum: ['classic', 'visible', 'hidden', 'compact'],
95
+ enum: ['classic', 'visible', 'toggle', 'hidden', 'compact'],
96
96
  markdownEnumDescriptions: [
97
97
  nls.localizeByDefault('Menu is displayed at the top of the window and only hidden in full screen mode.'),
98
98
  nls.localizeByDefault('Menu is always visible at the top of the window even in full screen mode.'),
99
+ nls.localizeByDefault('Menu is hidden but can be displayed at the top of the window via the Alt key.'),
99
100
  nls.localizeByDefault('Menu is always hidden.'),
100
101
  environment.electron.is()
101
102
  // we do not support the window.menuStyle setting yet, so we do not use the default string in this case yet
@@ -314,7 +315,7 @@ export interface CoreConfiguration {
314
315
  'files.encoding': string;
315
316
  'keyboard.dispatch': 'code' | 'keyCode';
316
317
  'window.tabbar.enhancedPreview': 'classic' | 'enhanced' | 'visual';
317
- 'window.menuBarVisibility': 'classic' | 'visible' | 'hidden' | 'compact';
318
+ 'window.menuBarVisibility': 'classic' | 'visible' | 'toggle' | 'hidden' | 'compact';
318
319
  'window.title': string;
319
320
  'window.titleSeparator': string;
320
321
  'window.tabCloseIconPlacement': 'end' | 'start';
@@ -91,6 +91,12 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
91
91
  @inject(PreferenceService)
92
92
  protected preferencesService: PreferenceService;
93
93
 
94
+ /**
95
+ * The title bar style ('native' or 'custom'). Set by {@link ElectronMenuContribution}
96
+ * after querying the main process for the active style.
97
+ */
98
+ titleBarStyle?: string;
99
+
94
100
  setMenuBar = debounce(() => this.doSetMenuBar(), 100);
95
101
 
96
102
  @postConstruct()
@@ -140,13 +146,45 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
140
146
 
141
147
  doSetMenuBar(): void {
142
148
  const preference = this.preferencesService.get<string>('window.menuBarVisibility') || 'classic';
143
- const shouldShowTop = !window.electronTheiaCore.isFullScreen() || preference === 'visible';
144
- if (shouldShowTop) {
145
- this.menu = this.createElectronMenuBar();
146
- window.electronTheiaCore.setMenu(this.menu);
147
- window.electronTheiaCore.setMenuBarVisible(true);
148
- } else {
149
- window.electronTheiaCore.setMenuBarVisible(false);
149
+ const isFullScreen = window.electronTheiaCore.isFullScreen();
150
+ const isCustomTitleBar = this.titleBarStyle === 'custom';
151
+
152
+ switch (preference) {
153
+ case 'visible':
154
+ this.menu = this.createElectronMenuBar();
155
+ window.electronTheiaCore.setMenu(this.menu);
156
+ window.electronTheiaCore.setMenuBarVisible(true);
157
+ window.electronTheiaCore.setAutoHideMenuBar(false);
158
+ break;
159
+ case 'toggle':
160
+ if (isCustomTitleBar) {
161
+ // With custom title bar, the Lumino menu bar handles toggle via Alt-key listener.
162
+ // Do not set autoHideMenuBar on the native window to prevent it from appearing.
163
+ window.electronTheiaCore.setMenuBarVisible(false);
164
+ window.electronTheiaCore.setAutoHideMenuBar(false);
165
+ } else {
166
+ // With native title bar, Electron's autoHideMenuBar handles Alt toggling.
167
+ this.menu = this.createElectronMenuBar();
168
+ window.electronTheiaCore.setMenu(this.menu);
169
+ window.electronTheiaCore.setMenuBarVisible(false);
170
+ window.electronTheiaCore.setAutoHideMenuBar(true);
171
+ }
172
+ break;
173
+ case 'hidden':
174
+ window.electronTheiaCore.setMenuBarVisible(false);
175
+ window.electronTheiaCore.setAutoHideMenuBar(false);
176
+ break;
177
+ case 'compact':
178
+ window.electronTheiaCore.setMenuBarVisible(false);
179
+ window.electronTheiaCore.setAutoHideMenuBar(false);
180
+ break;
181
+ case 'classic':
182
+ default:
183
+ this.menu = this.createElectronMenuBar();
184
+ window.electronTheiaCore.setMenu(this.menu);
185
+ window.electronTheiaCore.setMenuBarVisible(!isFullScreen);
186
+ window.electronTheiaCore.setAutoHideMenuBar(isFullScreen);
187
+ break;
150
188
  }
151
189
  }
152
190
 
@@ -27,7 +27,7 @@ import { ElectronMainMenuFactory } from './electron-main-menu-factory';
27
27
  import { FrontendApplicationStateService, FrontendApplicationState } from '../../browser/frontend-application-state';
28
28
  import { FrontendApplicationConfigProvider } from '../../browser/frontend-application-config-provider';
29
29
  import { PREF_WINDOW_ZOOM_LEVEL, ZoomLevel } from '../../electron-common/electron-window-preferences';
30
- import { BrowserMenuBarContribution } from '../../browser/menu/browser-menu-plugin';
30
+ import { BrowserMenuBarContribution, MenuBarWidget } from '../../browser/menu/browser-menu-plugin';
31
31
  import { WindowService } from '../../browser/window/window-service';
32
32
  import { WindowTitleService } from '../../browser/window/window-title-service';
33
33
 
@@ -152,8 +152,9 @@ export class ElectronMenuContribution extends BrowserMenuBarContribution impleme
152
152
 
153
153
  handleTitleBarStyling(app: FrontendApplication): void {
154
154
  this.hideTopPanel(app);
155
- window.electronTheiaCore.getTitleBarStyleAtStartup().then(style => {
155
+ const titleBarStyleAtStartup = window.electronTheiaCore.getTitleBarStyleAtStartup().then(style => {
156
156
  this.titleBarStyle = style;
157
+ this.factory.titleBarStyle = style;
157
158
  this.setMenu(app);
158
159
  this.preferenceService.ready.then(() => {
159
160
  const current = this.preferenceService.inspect('window.titleBarStyle');
@@ -171,8 +172,17 @@ export class ElectronMenuContribution extends BrowserMenuBarContribution impleme
171
172
  });
172
173
  });
173
174
 
174
- this.preferenceService.ready.then(() => {
175
- window.electronTheiaCore.setMenuBarVisible(['classic', 'visible'].includes(this.preferenceService.get('window.menuBarVisibility', 'classic')));
175
+ // `titleBarStyle` decides whether the native menu bar is used at all, so wait for it:
176
+ // preferences can become ready first, in which case it would still be `undefined` here.
177
+ Promise.all([titleBarStyleAtStartup, this.preferenceService.ready]).then(() => {
178
+ const pref = this.preferenceService.get<string>('window.menuBarVisibility', 'classic');
179
+ if (pref === 'toggle' && this.titleBarStyle !== 'custom') {
180
+ window.electronTheiaCore.setMenuBarVisible(false);
181
+ window.electronTheiaCore.setAutoHideMenuBar(true);
182
+ } else {
183
+ window.electronTheiaCore.setMenuBarVisible(['classic', 'visible'].includes(pref));
184
+ window.electronTheiaCore.setAutoHideMenuBar(false);
185
+ }
176
186
  });
177
187
 
178
188
  this.preferenceService.onPreferenceChanged(change => {
@@ -424,7 +434,19 @@ export class ElectronMenuContribution extends BrowserMenuBarContribution impleme
424
434
  protected handleFullScreen(menuBarVisibility: string): void {
425
435
  const shouldShowTop = !window.electronTheiaCore.isFullScreen() || menuBarVisibility === 'visible';
426
436
  if (this.titleBarStyle === 'native') {
427
- window.electronTheiaCore.setMenuBarVisible(shouldShowTop);
437
+ if (menuBarVisibility === 'toggle') {
438
+ window.electronTheiaCore.setMenuBarVisible(false);
439
+ window.electronTheiaCore.setAutoHideMenuBar(true);
440
+ } else {
441
+ window.electronTheiaCore.setMenuBarVisible(shouldShowTop);
442
+ // Match `ElectronMainMenuFactory.doSetMenuBar`: in 'classic' the menu is hidden in
443
+ // full screen but Alt still reveals it. Without this the two disagree and the
444
+ // effective behaviour depends on which of them ran last.
445
+ window.electronTheiaCore.setAutoHideMenuBar(!shouldShowTop && menuBarVisibility === 'classic');
446
+ }
447
+ } else if (menuBarVisibility === 'toggle' && this.menuWidget && this.logoWidget) {
448
+ // Which widget Alt reveals depends on the full screen state, so re-establish it.
449
+ this.updateElectronMenuToggleMode(this.menuWidget, this.logoWidget);
428
450
  } else if (shouldShowTop) {
429
451
  this.shell.topPanel.show();
430
452
  } else {
@@ -432,6 +454,29 @@ export class ElectronMenuContribution extends BrowserMenuBarContribution impleme
432
454
  }
433
455
  }
434
456
 
457
+ /**
458
+ * Outside of full screen the top panel also carries the window controls, so it has to stay
459
+ * visible and Alt toggles the menu widgets inside it. In full screen the panel is hidden
460
+ * altogether, so Alt toggles the panel itself and the widgets inside it stay visible.
461
+ */
462
+ protected override applyElectronMenuBarVisibility(menu: MenuBarWidget, logo: Widget, pref: string): void {
463
+ if (pref === 'toggle' && this.titleBarStyle === 'custom') {
464
+ const isFullScreen = window.electronTheiaCore.isFullScreen();
465
+ menu.setHidden(!isFullScreen);
466
+ logo.setHidden(!isFullScreen);
467
+ this.shell.topPanel.setHidden(isFullScreen);
468
+ return;
469
+ }
470
+ super.applyElectronMenuBarVisibility(menu, logo, pref);
471
+ }
472
+
473
+ protected override getElectronToggleTargets(menu: MenuBarWidget, logo: Widget): Widget[] {
474
+ if (this.titleBarStyle === 'custom' && window.electronTheiaCore.isFullScreen()) {
475
+ return [this.shell.topPanel];
476
+ }
477
+ return super.getElectronToggleTargets(menu, logo);
478
+ }
479
+
435
480
  protected handleThemeChange(e: ThemeChangeEvent): void {
436
481
  const backgroundColor = window.getComputedStyle(document.body).backgroundColor;
437
482
  window.electronTheiaCore.setBackgroundColor(backgroundColor);
@@ -28,7 +28,8 @@ import {
28
28
  CHANNEL_KEYBOARD_LAYOUT_CHANGED, CHANNEL_IPC_CONNECTION, InternalMenuDto, CHANNEL_REQUEST_SECONDARY_CLOSE, CHANNEL_SET_BACKGROUND_COLOR,
29
29
  CHANNEL_WC_METADATA, CHANNEL_ABOUT_TO_CLOSE, CHANNEL_OPEN_WITH_SYSTEM_APP,
30
30
  CHANNEL_OPEN_URL, CHANNEL_SET_THEME, CHANNEL_OPEN_DEVTOOLS_FOR_WINDOW,
31
- CHANNEL_UPDATE_RECENT_WORKSPACES
31
+ CHANNEL_UPDATE_RECENT_WORKSPACES,
32
+ CHANNEL_SET_AUTO_HIDE_MENU_BAR
32
33
  } from '../electron-common/electron-api';
33
34
 
34
35
  // eslint-disable-next-line import/no-extraneous-dependencies
@@ -80,6 +81,7 @@ function convertMenu(menu: MenuDto[] | undefined, handlerMap: Map<number, () =>
80
81
  const api: TheiaCoreAPI = {
81
82
  WindowMetadata: { webcontentId: 'none' },
82
83
  setMenuBarVisible: (visible: boolean, windowName?: string) => ipcRenderer.send(CHANNEL_SET_MENU_BAR_VISIBLE, visible, windowName),
84
+ setAutoHideMenuBar: (enabled: boolean, windowName?: string) => ipcRenderer.send(CHANNEL_SET_AUTO_HIDE_MENU_BAR, enabled, windowName),
83
85
  setMenu: (menu: MenuDto[] | undefined) => {
84
86
  commandHandlers.delete(mainMenuId);
85
87
  const handlers = new Map<number, () => void>();
@@ -59,6 +59,7 @@ export interface TheiaCoreAPI {
59
59
  attachSecurityToken: (endpoint: string) => Promise<void>;
60
60
 
61
61
  setMenuBarVisible(visible: boolean, windowName?: string): void;
62
+ setAutoHideMenuBar(enabled: boolean, windowName?: string): void;
62
63
  setMenu(menu: MenuDto[] | undefined): void;
63
64
 
64
65
  popup(menu: MenuDto[], x: number, y: number, onClosed: () => void, windowName?: string): Promise<number>;
@@ -127,6 +128,7 @@ declare global {
127
128
  export const CHANNEL_WC_METADATA = 'WebContentMetadata';
128
129
  export const CHANNEL_SET_MENU = 'SetMenu';
129
130
  export const CHANNEL_SET_MENU_BAR_VISIBLE = 'SetMenuBarVisible';
131
+ export const CHANNEL_SET_AUTO_HIDE_MENU_BAR = 'SetAutoHideMenuBar';
130
132
  export const CHANNEL_INVOKE_MENU = 'InvokeMenu';
131
133
  export const CHANNEL_OPEN_POPUP = 'OpenPopup';
132
134
  export const CHANNEL_ON_CLOSE_POPUP = 'OnClosePopup';
@@ -59,7 +59,8 @@ import {
59
59
  CHANNEL_OPEN_URL,
60
60
  CHANNEL_SET_THEME,
61
61
  CHANNEL_OPEN_DEVTOOLS_FOR_WINDOW,
62
- CHANNEL_UPDATE_RECENT_WORKSPACES
62
+ CHANNEL_UPDATE_RECENT_WORKSPACES,
63
+ CHANNEL_SET_AUTO_HIDE_MENU_BAR
63
64
  } from '../electron-common/electron-api';
64
65
  import { ElectronMainApplication, ElectronMainApplicationContribution } from './electron-main-application';
65
66
  import { Disposable, DisposableCollection, isOSX, isWindows, MaybePromise, URI } from '../common';
@@ -128,6 +129,20 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
128
129
  }
129
130
  });
130
131
 
132
+ ipcMain.on(CHANNEL_SET_AUTO_HIDE_MENU_BAR, (event, enabled: boolean, windowName: string | undefined) => {
133
+ let electronWindow;
134
+ if (windowName) {
135
+ electronWindow = BrowserWindow.getAllWindows().find(win => win.webContents.mainFrame.name === windowName);
136
+ } else {
137
+ electronWindow = BrowserWindow.fromWebContents(event.sender);
138
+ }
139
+ if (electronWindow) {
140
+ electronWindow.autoHideMenuBar = enabled;
141
+ } else {
142
+ console.warn(`There is no known secondary window '${windowName}'. Thus, autoHideMenuBar could not be set.`);
143
+ }
144
+ });
145
+
131
146
  // popup menu
132
147
  ipcMain.handle(CHANNEL_OPEN_POPUP, (event, menuId, menu, x, y, windowName?: string) => {
133
148
  const zoom = event.sender.getZoomFactor();