Skip to content

Commit 7b8538e

Browse files
author
Akos Kitta
committed
fix: restored window.titleBarStyle
Ref: #1733 Signed-off-by: Akos Kitta <[email protected]>
1 parent 65add68 commit 7b8538e

9 files changed

+230
-63
lines changed

arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+6
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,8 @@ import { ValidateSketch } from './contributions/validate-sketch';
348348
import { RenameCloudSketch } from './contributions/rename-cloud-sketch';
349349
import { CreateFeatures } from './create/create-features';
350350
import { NativeImageCache } from './native-image-cache';
351+
import { rebindWindowPreferences } from '../electron-browser/theia/core/electron-window-preferences';
352+
import { rebindCorePreferences } from './theia/core/core-preferences';
351353

352354
export default new ContainerModule((bind, unbind, isBound, rebind) => {
353355
// Commands and toolbar items
@@ -1019,4 +1021,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
10191021
// manages native images for the electron menu icons
10201022
bind(NativeImageCache).toSelf().inSingletonScope();
10211023
bind(FrontendApplicationContribution).toService(NativeImageCache);
1024+
// enable `'window.titleBarStyle'` on all supported OSs
1025+
rebindWindowPreferences(bind, rebind);
1026+
// enable `'window.menuBarVisibility'` on all supported OSs
1027+
rebindCorePreferences(bind, rebind);
10221028
});

arduino-ide-extension/src/browser/style/main.css

+13
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,19 @@
100100
background-color: var(--theia-titleBar-activeBackground);
101101
}
102102

103+
#arduino-toolbar-panel {
104+
background: var(--theia-titleBar-activeBackground);
105+
color: var(--theia-titleBar-activeForeground);
106+
display: flex;
107+
min-height: var(--theia-private-menubar-height);
108+
border-bottom: 1px solid var(--theia-titleBar-border);
109+
}
110+
#arduino-toolbar-panel:window-inactive,
111+
#arduino-toolbar-panel:-moz-window-inactive {
112+
background: var(--theia-titleBar-inactiveBackground);
113+
color: var(--theia-titleBar-inactiveForeground);
114+
}
115+
103116
#arduino-toolbar-container {
104117
display: flex;
105118
width: 100%;

arduino-ide-extension/src/browser/theia/core/application-shell.ts

+58-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
SHELL_TABBAR_CONTEXT_MENU,
88
TabBar,
99
Widget,
10+
Layout,
11+
SplitPanel,
1012
} from '@theia/core/lib/browser';
1113
import {
1214
ConnectionStatus,
@@ -17,17 +19,23 @@ import { MessageService } from '@theia/core/lib/common/message-service';
1719
import { inject, injectable } from '@theia/core/shared/inversify';
1820
import { ToolbarAwareTabBar } from './tab-bars';
1921

22+
interface WidgetOptions
23+
extends Omit<TheiaApplicationShell.WidgetOptions, 'area'> {
24+
area?: TheiaApplicationShell.Area | 'toolbar';
25+
}
26+
2027
@injectable()
2128
export class ApplicationShell extends TheiaApplicationShell {
2229
@inject(MessageService)
2330
private readonly messageService: MessageService;
2431

2532
@inject(ConnectionStatusService)
2633
private readonly connectionStatusService: ConnectionStatusService;
34+
private toolbarPanel: Panel;
2735

2836
override async addWidget(
2937
widget: Widget,
30-
options: Readonly<TheiaApplicationShell.WidgetOptions> = {}
38+
options: Readonly<WidgetOptions> = {}
3139
): Promise<void> {
3240
// By default, Theia open a widget **next** to the currently active in the target area.
3341
// Instead of this logic, we want to open the new widget after the last of the target area.
@@ -37,8 +45,12 @@ export class ApplicationShell extends TheiaApplicationShell {
3745
);
3846
return;
3947
}
48+
if (options.area === 'toolbar') {
49+
this.toolbarPanel.addWidget(widget);
50+
return;
51+
}
52+
const area = options.area || 'main';
4053
let ref: Widget | undefined = options.ref;
41-
const area: TheiaApplicationShell.Area = options.area || 'main';
4254
if (!ref && (area === 'main' || area === 'bottom')) {
4355
const tabBar = this.getTabBarFor(area);
4456
if (tabBar) {
@@ -48,14 +60,57 @@ export class ApplicationShell extends TheiaApplicationShell {
4860
}
4961
}
5062
}
51-
return super.addWidget(widget, { ...options, ref });
63+
return super.addWidget(widget, {
64+
...(<TheiaApplicationShell.WidgetOptions>options),
65+
ref,
66+
});
5267
}
5368

5469
override handleEvent(): boolean {
5570
// NOOP, dragging has been disabled
5671
return false;
5772
}
5873

74+
protected override initializeShell(): void {
75+
this.toolbarPanel = this.createToolbarPanel();
76+
super.initializeShell();
77+
}
78+
79+
private createToolbarPanel(): Panel {
80+
const toolbarPanel = new Panel();
81+
toolbarPanel.id = 'arduino-toolbar-panel';
82+
toolbarPanel.show();
83+
return toolbarPanel;
84+
}
85+
86+
protected override createLayout(): Layout {
87+
const bottomSplitLayout = this.createSplitLayout(
88+
[this.mainPanel, this.bottomPanel],
89+
[1, 0],
90+
{ orientation: 'vertical', spacing: 0 }
91+
);
92+
const panelForBottomArea = new SplitPanel({ layout: bottomSplitLayout });
93+
panelForBottomArea.id = 'theia-bottom-split-panel';
94+
95+
const leftRightSplitLayout = this.createSplitLayout(
96+
[
97+
this.leftPanelHandler.container,
98+
panelForBottomArea,
99+
this.rightPanelHandler.container,
100+
],
101+
[0, 1, 0],
102+
{ orientation: 'horizontal', spacing: 0 }
103+
);
104+
const panelForSideAreas = new SplitPanel({ layout: leftRightSplitLayout });
105+
panelForSideAreas.id = 'theia-left-right-split-panel';
106+
107+
return this.createBoxLayout(
108+
[this.topPanel, this.toolbarPanel, panelForSideAreas, this.statusBar],
109+
[0, 0, 1, 0],
110+
{ direction: 'top-to-bottom', spacing: 0 }
111+
);
112+
}
113+
59114
// Avoid hiding top panel as we use it for arduino toolbar
60115
protected override createTopPanel(): Panel {
61116
const topPanel = super.createTopPanel();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {
2+
CorePreferenceContribution,
3+
CorePreferences,
4+
corePreferenceSchema,
5+
createCorePreferences,
6+
} from '@theia/core/lib/browser/core-preferences';
7+
import { PreferenceContribution } from '@theia/core/lib/browser/preferences/preference-contribution';
8+
import { PreferenceService } from '@theia/core/lib/browser/preferences/preference-service';
9+
import { deepClone } from '@theia/core/lib/common/objects';
10+
import { PreferenceSchema } from '@theia/core/lib/common/preferences/preference-schema';
11+
import { interfaces } from '@theia/core/shared/inversify';
12+
13+
const copy = deepClone(corePreferenceSchema);
14+
copy.properties['window.menuBarVisibility'].included = true; // https://github.com/arduino/arduino-ide/issues/1733#issuecomment-1424186676
15+
const corePreferencesSchema: PreferenceSchema = copy;
16+
17+
export function rebindCorePreferences(
18+
bind: interfaces.Bind,
19+
rebind: interfaces.Rebind
20+
): void {
21+
rebind(CorePreferences)
22+
.toDynamicValue((ctx) => {
23+
const preferences =
24+
ctx.container.get<PreferenceService>(PreferenceService);
25+
const contribution = ctx.container.get<PreferenceContribution>(
26+
CorePreferenceContribution
27+
);
28+
return createCorePreferences(preferences, contribution.schema);
29+
})
30+
.inSingletonScope();
31+
rebind(CorePreferenceContribution).toConstantValue({
32+
schema: corePreferencesSchema,
33+
});
34+
}

arduino-ide-extension/src/browser/toolbar/arduino-toolbar-contribution.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ export class ArduinoToolbarContainer extends Widget {
1919
this.toolbars = toolbars;
2020
}
2121

22-
override onAfterAttach(msg: Message) {
22+
override onAfterAttach(msg: Message): void {
23+
super.onAfterAttach(msg);
2324
for (const toolbar of this.toolbars) {
2425
Widget.attach(toolbar, this.node);
2526
}
@@ -56,9 +57,11 @@ export class ArduinoToolbarContribution
5657
);
5758
}
5859

59-
onStart(app: FrontendApplication) {
60-
app.shell.addWidget(this.arduinoToolbarContainer, {
61-
area: 'top',
62-
});
60+
onStart(app: FrontendApplication): void {
61+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
62+
const options = <any>{
63+
area: 'toolbar',
64+
};
65+
app.shell.addWidget(this.arduinoToolbarContainer, options);
6366
}
6467
}

arduino-ide-extension/src/electron-browser/theia/core/electron-main-menu-factory.ts

+4-20
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
CommandMenuNode,
88
CompoundMenuNode,
99
CompoundMenuNodeRole,
10-
MAIN_MENU_BAR,
1110
MenuNode,
1211
MenuPath,
1312
} from '@theia/core/lib/common/menu';
@@ -28,7 +27,7 @@ export class ElectronMainMenuFactory extends TheiaElectronMainMenuFactory {
2827
@inject(FrontendApplicationStateService)
2928
private readonly appStateService: FrontendApplicationStateService;
3029

31-
private appReady = false;
30+
appReady = false;
3231
private updateWhenReady = false;
3332

3433
override postConstruct(): void {
@@ -41,18 +40,9 @@ export class ElectronMainMenuFactory extends TheiaElectronMainMenuFactory {
4140
});
4241
}
4342

44-
override createElectronMenuBar(): Electron.Menu {
43+
override createElectronMenuBar(): Electron.Menu | null {
4544
this._toggledCommands.clear(); // https://github.com/eclipse-theia/theia/issues/8977
46-
const menuModel = this.menuProvider.getMenu(MAIN_MENU_BAR);
47-
const template = this.fillMenuTemplate([], menuModel, [], {
48-
rootMenuPath: MAIN_MENU_BAR,
49-
});
50-
if (isOSX) {
51-
template.unshift(this.createOSXMenu());
52-
}
53-
const menu = remote.Menu.buildFromTemplate(this.escapeAmpersand(template));
54-
this._menu = menu;
55-
return menu;
45+
return super.createElectronMenuBar();
5646
}
5747

5848
override async setMenuBar(): Promise<void> {
@@ -63,13 +53,7 @@ export class ElectronMainMenuFactory extends TheiaElectronMainMenuFactory {
6353
this.updateWhenReady = true;
6454
return;
6555
}
66-
await this.preferencesService.ready;
67-
const createdMenuBar = this.createElectronMenuBar();
68-
if (isOSX) {
69-
remote.Menu.setApplicationMenu(createdMenuBar);
70-
} else {
71-
remote.getCurrentWindow().setMenu(createdMenuBar);
72-
}
56+
return super.setMenuBar();
7357
}
7458

7559
override createElectronContextMenu(

arduino-ide-extension/src/electron-browser/theia/core/electron-menu-contribution.ts

+39-31
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,61 @@
1-
import { inject, injectable } from '@theia/core/shared/inversify';
1+
import {
2+
getCurrentWebContents,
3+
getCurrentWindow,
4+
Menu,
5+
} from '@theia/core/electron-shared/@electron/remote';
6+
import {
7+
BrowserWindow,
8+
Menu as ElectronMenu,
9+
} from '@theia/core/electron-shared/electron';
10+
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
11+
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
12+
import { PreferenceScope } from '@theia/core/lib/browser/preferences/preference-scope';
213
import { CommandRegistry } from '@theia/core/lib/common/command';
314
import { MenuModelRegistry } from '@theia/core/lib/common/menu';
4-
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
15+
import { isOSX } from '@theia/core/lib/common/os';
516
import {
6-
ElectronMenuContribution as TheiaElectronMenuContribution,
717
ElectronCommands,
18+
ElectronMenuContribution as TheiaElectronMenuContribution,
819
} from '@theia/core/lib/electron-browser/menu/electron-menu-contribution';
9-
import { MainMenuManager } from '../../../common/main-menu-manager';
10-
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
11-
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
1220
import { ZoomLevel } from '@theia/core/lib/electron-browser/window/electron-window-preferences';
13-
import { PreferenceScope } from '@theia/core/lib/browser/preferences/preference-scope';
14-
import {
15-
getCurrentWindow,
16-
getCurrentWebContents,
17-
} from '@theia/core/electron-shared/@electron/remote';
21+
import { injectable } from '@theia/core/shared/inversify';
22+
import { MainMenuManager } from '../../../common/main-menu-manager';
1823

1924
@injectable()
2025
export class ElectronMenuContribution
2126
extends TheiaElectronMenuContribution
2227
implements MainMenuManager
2328
{
24-
@inject(FrontendApplicationStateService)
25-
private readonly appStateService: FrontendApplicationStateService;
26-
27-
// private appReady = false;
28-
// private updateWhenReady = false;
29+
private app: FrontendApplication;
2930

3031
override onStart(app: FrontendApplication): void {
32+
this.app = app;
3133
super.onStart(app);
32-
this.appStateService.reachedState('ready').then(() => {
33-
// this.appReady = true;
34-
// if (this.updateWhenReady) {
35-
// this.update();
36-
// }
37-
});
3834
}
3935

40-
protected override hideTopPanel(): void {
41-
// NOOP
42-
// We reuse the `div` for the Arduino toolbar.
36+
update(): void {
37+
// no menu updates before `onStart`
38+
if (!this.app) {
39+
return;
40+
}
41+
this.setMenu(this.app);
4342
}
4443

45-
update(): void {
46-
// if (this.appReady) {
47-
(this as any).setMenu();
48-
// } else {
49-
// this.updateWhenReady = true;
50-
// }
44+
protected override setMenu(
45+
app: FrontendApplication,
46+
electronMenu: ElectronMenu | null = this.factory.createElectronMenuBar(),
47+
electronWindow: BrowserWindow = getCurrentWindow()
48+
): void {
49+
this.hideTopPanel(app); // Updates the top panel's visibility on all operating systems.
50+
if (this.titleBarStyle === 'custom' && !this.menuBar) {
51+
this.createCustomTitleBar(app, electronWindow);
52+
}
53+
if (isOSX) {
54+
Menu.setApplicationMenu(electronMenu);
55+
} else {
56+
// Unix/Windows: Set the per-window menus
57+
electronWindow.setMenu(electronMenu);
58+
}
5159
}
5260

5361
override registerCommands(registry: CommandRegistry): void {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { PreferenceContribution } from '@theia/core/lib/browser/preferences/preference-contribution';
2+
import { PreferenceService } from '@theia/core/lib/browser/preferences/preference-service';
3+
import { deepClone } from '@theia/core/lib/common/objects';
4+
import { PreferenceSchema } from '@theia/core/lib/common/preferences/preference-schema';
5+
import {
6+
createElectronWindowPreferences,
7+
ElectronWindowPreferenceContribution,
8+
ElectronWindowPreferences,
9+
electronWindowPreferencesSchema as theiaElectronWindowPreferencesSchema,
10+
} from '@theia/core/lib/electron-browser/window/electron-window-preferences';
11+
import { interfaces } from '@theia/core/shared/inversify';
12+
13+
const copy = deepClone(theiaElectronWindowPreferencesSchema);
14+
copy.properties['window.titleBarStyle'].included = true; // https://github.com/eclipse-theia/theia/pull/10044#issuecomment-1423841453
15+
copy.properties['window.titleBarStyle'].default = 'custom';
16+
const electronWindowPreferencesSchema: PreferenceSchema = copy;
17+
18+
export function rebindWindowPreferences(
19+
bind: interfaces.Bind,
20+
rebind: interfaces.Rebind
21+
): void {
22+
rebind(ElectronWindowPreferences)
23+
.toDynamicValue((ctx) => {
24+
const preferences =
25+
ctx.container.get<PreferenceService>(PreferenceService);
26+
const contribution = ctx.container.get<PreferenceContribution>(
27+
ElectronWindowPreferenceContribution
28+
);
29+
return createElectronWindowPreferences(preferences, contribution.schema);
30+
})
31+
.inSingletonScope();
32+
rebind(ElectronWindowPreferenceContribution).toConstantValue({
33+
schema: electronWindowPreferencesSchema,
34+
});
35+
}

0 commit comments

Comments
 (0)