Skip to content

Commit

Permalink
Enable custom titlebar on Linux by default as experiment (fix microso…
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero authored Jan 8, 2025
1 parent d4a589e commit 62aabbc
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 54 deletions.
2 changes: 1 addition & 1 deletion src/vs/code/electron-main/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ export class CodeApplication extends Disposable {
// Linux (stable only): custom title default style override
if (isLinux && this.productService.quality === 'stable') {
const titleBarDefaultStyleOverride = this.stateService.getItem('window.titleBarStyleOverride');
if (titleBarDefaultStyleOverride === TitlebarStyle.CUSTOM || titleBarDefaultStyleOverride === TitlebarStyle.NATIVE) {
if (titleBarDefaultStyleOverride === TitlebarStyle.CUSTOM) {
overrideDefaultTitlebarStyle(titleBarDefaultStyleOverride);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/vs/platform/native/common/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export interface ICommonNativeHostService {
focusWindow(options?: INativeHostOptions & { force?: boolean }): Promise<void>;

// Titlebar default style override
overrideDefaultTitlebarStyle(style: 'native' | 'custom' | undefined): Promise<void>;
overrideDefaultTitlebarStyle(style: 'custom' | undefined): Promise<void>;

// Dialogs
showMessageBox(options: MessageBoxOptions & INativeHostOptions): Promise<MessageBoxReturnValue>;
Expand Down
7 changes: 3 additions & 4 deletions src/vs/platform/native/electron-main/nativeHostMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { IProductService } from '../../product/common/productService.js';
import { IPartsSplash } from '../../theme/common/themeService.js';
import { IThemeMainService } from '../../theme/electron-main/themeMainService.js';
import { defaultWindowState, ICodeWindow } from '../../window/electron-main/window.js';
import { IColorScheme, IOpenedAuxiliaryWindow, IOpenedMainWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IPoint, IRectangle, IWindowOpenable, overrideDefaultTitlebarStyle } from '../../window/common/window.js';
import { IColorScheme, IOpenedAuxiliaryWindow, IOpenedMainWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IPoint, IRectangle, IWindowOpenable } from '../../window/common/window.js';
import { defaultBrowserWindowOptions, IWindowsMainService, OpenContext } from '../../windows/electron-main/windows.js';
import { isWorkspaceIdentifier, toWorkspaceIdentifier } from '../../workspace/common/workspace.js';
import { IWorkspacesManagementMainService } from '../../workspaces/electron-main/workspacesManagementMainService.js';
Expand Down Expand Up @@ -326,13 +326,12 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
this.themeMainService.saveWindowSplash(windowId, splash);
}

async overrideDefaultTitlebarStyle(windowId: number | undefined, style: 'native' | 'custom' | undefined): Promise<void> {
if (typeof style === 'string') {
async overrideDefaultTitlebarStyle(windowId: number | undefined, style: 'custom' | undefined): Promise<void> {
if (style === 'custom') {
this.stateService.setItem('window.titleBarStyleOverride', style);
} else {
this.stateService.removeItem('window.titleBarStyleOverride');
}
overrideDefaultTitlebarStyle(style);
}

//#endregion
Expand Down
20 changes: 6 additions & 14 deletions src/vs/platform/window/common/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,18 +187,9 @@ export const enum CustomTitleBarVisibility {
NEVER = 'never',
}

export let titlebarStyleDefaultOverride: TitlebarStyle | undefined = undefined;
export function overrideDefaultTitlebarStyle(style: 'native' | 'custom' | undefined): void {
switch (style) {
case 'native':
titlebarStyleDefaultOverride = TitlebarStyle.NATIVE;
break;
case 'custom':
titlebarStyleDefaultOverride = TitlebarStyle.CUSTOM;
break;
default:
titlebarStyleDefaultOverride = undefined;
}
export let titlebarStyleDefaultOverride: 'custom' | undefined = undefined;
export function overrideDefaultTitlebarStyle(style: 'custom'): void {
titlebarStyleDefaultOverride = style;
}

export function hasCustomTitlebar(configurationService: IConfigurationService, titleBarStyle?: TitlebarStyle): boolean {
Expand Down Expand Up @@ -238,8 +229,8 @@ export function getTitleBarStyle(configurationService: IConfigurationService): T
}
}

if (titlebarStyleDefaultOverride) {
return titlebarStyleDefaultOverride;
if (titlebarStyleDefaultOverride === 'custom') {
return TitlebarStyle.CUSTOM;
}

return isLinux && product.quality === 'stable' ? TitlebarStyle.NATIVE : TitlebarStyle.CUSTOM; // default to custom on all OS except Linux stable (for now)
Expand Down Expand Up @@ -413,6 +404,7 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native
autoDetectHighContrast?: boolean;
autoDetectColorScheme?: boolean;
isCustomZoomLevel?: boolean;
overrideDefaultTitlebarStyle?: 'custom';

perfMarks: PerformanceMark[];

Expand Down
3 changes: 2 additions & 1 deletion src/vs/platform/windows/electron-main/windowsMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import product from '../../product/common/product.js';
import { IProtocolMainService } from '../../protocol/electron-main/protocol.js';
import { getRemoteAuthority } from '../../remote/common/remoteHosts.js';
import { IStateService } from '../../state/node/state.js';
import { IAddRemoveFoldersRequest, INativeOpenFileRequest, INativeWindowConfiguration, IOpenEmptyWindowOptions, IPath, IPathsToWaitFor, isFileToOpen, isFolderToOpen, isWorkspaceToOpen, IWindowOpenable, IWindowSettings } from '../../window/common/window.js';
import { IAddRemoveFoldersRequest, INativeOpenFileRequest, INativeWindowConfiguration, IOpenEmptyWindowOptions, IPath, IPathsToWaitFor, isFileToOpen, isFolderToOpen, isWorkspaceToOpen, IWindowOpenable, IWindowSettings, titlebarStyleDefaultOverride } from '../../window/common/window.js';
import { CodeWindow } from './windowImpl.js';
import { IOpenConfiguration, IOpenEmptyConfiguration, IWindowsCountChangedEvent, IWindowsMainService, OpenContext, getLastFocused } from './windows.js';
import { findWindowOnExtensionDevelopmentPath, findWindowOnFile, findWindowOnWorkspaceOrFolder } from './windowsFinder.js';
Expand Down Expand Up @@ -1507,6 +1507,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic

autoDetectHighContrast: windowConfig?.autoDetectHighContrast ?? true,
autoDetectColorScheme: windowConfig?.autoDetectColorScheme ?? false,
overrideDefaultTitlebarStyle: titlebarStyleDefaultOverride,
accessibilitySupport: app.accessibilitySupportEnabled,
colorScheme: this.themeMainService.getColorScheme(),
policiesData: this.policyService.serialize(),
Expand Down
6 changes: 5 additions & 1 deletion src/vs/workbench/electron-sandbox/desktop.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import { ModifierKeyEmitter } from '../../base/browser/dom.js';
import { applicationConfigurationNodeBase, securityConfigurationNodeBase } from '../common/configuration.js';
import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL } from '../../platform/window/electron-sandbox/window.js';
import product from '../../platform/product/common/product.js';
import { registerWorkbenchContribution2, WorkbenchPhase } from '../common/contributions.js';
import { LinuxCustomTitlebarExperiment } from './parts/titlebar/titlebarPart.js';

// Actions
(function registerActions(): void {
Expand Down Expand Up @@ -234,7 +236,6 @@ import product from '../../platform/product/common/product.js';
'type': 'string',
'enum': ['native', 'custom'],
'default': isLinux && product.quality === 'stable' ? 'native' : 'custom',
'tags': isLinux && product.quality === 'stable' ? ['onExP'] : undefined,
'scope': ConfigurationScope.APPLICATION,
'description': localize('titleBarStyle', "Adjust the appearance of the window title bar to be native by the OS or custom. On Linux and Windows, this setting also affects the application and context menu appearances. Changes require a full restart to apply."),
},
Expand Down Expand Up @@ -424,3 +425,6 @@ import product from '../../platform/product/common/product.js';

jsonRegistry.registerSchema(argvDefinitionFileSchemaId, schema);
})();

// Workbench Contributions
registerWorkbenchContribution2(LinuxCustomTitlebarExperiment.ID, LinuxCustomTitlebarExperiment, WorkbenchPhase.Eventually);
10 changes: 9 additions & 1 deletion src/vs/workbench/electron-sandbox/desktop.main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import { WorkspaceTrustEnablementService, WorkspaceTrustManagementService } from
import { IWorkspaceTrustEnablementService, IWorkspaceTrustManagementService } from '../../platform/workspace/common/workspaceTrust.js';
import { safeStringify } from '../../base/common/objects.js';
import { IUtilityProcessWorkerWorkbenchService, UtilityProcessWorkerWorkbenchService } from '../services/utilityProcess/electron-sandbox/utilityProcessWorkerWorkbenchService.js';
import { isBigSurOrNewer, isCI, isMacintosh } from '../../base/common/platform.js';
import { isBigSurOrNewer, isCI, isLinux, isMacintosh } from '../../base/common/platform.js';
import { Schemas } from '../../base/common/network.js';
import { DiskFileSystemProvider } from '../services/files/electron-sandbox/diskFileSystemProvider.js';
import { FileUserDataProvider } from '../../platform/userData/common/fileUserDataProvider.js';
Expand All @@ -61,6 +61,8 @@ import { ElectronRemoteResourceLoader } from '../../platform/remote/electron-san
import { IConfigurationService } from '../../platform/configuration/common/configuration.js';
import { applyZoom } from '../../platform/window/electron-sandbox/window.js';
import { mainWindow } from '../../base/browser/window.js';
import { Registry } from '../../platform/registry/common/platform.js';
import { IConfigurationRegistry, Extensions } from '../../platform/configuration/common/configurationRegistry.js';

export class DesktopMain extends Disposable {

Expand All @@ -79,6 +81,12 @@ export class DesktopMain extends Disposable {

// Apply fullscreen early if configured
setFullscreen(!!this.configuration.fullscreen, mainWindow);

// Apply custom title override to defaults if any
if (isLinux && product.quality === 'stable' && this.configuration.overrideDefaultTitlebarStyle === 'custom') {
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
configurationRegistry.registerDefaultConfigurations([{ overrides: { 'window.titleBarStyle': 'custom' } }]);
}
}

private reviveUris() {
Expand Down
83 changes: 52 additions & 31 deletions src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import { IEditorService } from '../../../services/editor/common/editorService.js
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
import { CodeWindow, mainWindow } from '../../../../base/browser/window.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { IWorkbenchContribution } from '../../../common/contributions.js';
import { IWorkbenchAssignmentService } from '../../../services/assignment/common/assignmentService.js';
import { Disposable } from '../../../../base/common/lifecycle.js';

export class NativeTitlebarPart extends BrowserTitlebarPart {

Expand Down Expand Up @@ -71,7 +74,7 @@ export class NativeTitlebarPart extends BrowserTitlebarPart {
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IContextKeyService contextKeyService: IContextKeyService,
@IHostService hostService: IHostService,
@INativeHostService protected readonly nativeHostService: INativeHostService,
@INativeHostService private readonly nativeHostService: INativeHostService,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IEditorService editorService: IEditorService,
@IMenuService menuService: IMenuService,
Expand Down Expand Up @@ -288,38 +291,9 @@ export class MainNativeTitlebarPart extends NativeTitlebarPart {
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IEditorService editorService: IEditorService,
@IMenuService menuService: IMenuService,
@IKeybindingService keybindingService: IKeybindingService,
@IProductService productService: IProductService
@IKeybindingService keybindingService: IKeybindingService
) {
super(Parts.TITLEBAR_PART, mainWindow, 'main', contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, nativeHostService, editorGroupService, editorService, menuService, keybindingService);

if (isLinux && productService.quality === 'stable') {
this.handleDefaultTitlebarStyle(); // TODO@bpasero remove me eventually once settled
}
}

private handleDefaultTitlebarStyle(): void {
this.updateDefaultTitlebarStyle();
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('window.titleBarStyle')) {
this.updateDefaultTitlebarStyle();
}
}));
}

private updateDefaultTitlebarStyle(): void {
const titleBarStyle = this.configurationService.inspect('window.titleBarStyle');

let titleBarStyleOverride: 'custom' | undefined;
if (titleBarStyle.applicationValue || titleBarStyle.userValue || titleBarStyle.userLocalValue) {
// configured by user or application: clear override
titleBarStyleOverride = undefined;
} else {
// not configured: set override if experiment is active
titleBarStyleOverride = titleBarStyle.defaultValue === 'native' ? undefined : 'custom';
}

this.nativeHostService.overrideDefaultTitlebarStyle(titleBarStyleOverride);
}
}

Expand Down Expand Up @@ -374,3 +348,50 @@ export class NativeTitleService extends BrowserTitleService {
return this.instantiationService.createInstance(AuxiliaryNativeTitlebarPart, container, editorGroupsContainer, this.mainPart);
}
}

export class LinuxCustomTitlebarExperiment extends Disposable implements IWorkbenchContribution {

static readonly ID = 'workbench.contrib.linuxCustomTitlebarExperiment';

private readonly treatment = this.assignmentService.getTreatment('config.window.experimentalTitleBarStyle');

constructor(
@IProductService productService: IProductService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@INativeHostService private readonly nativeHostService: INativeHostService,
@IWorkbenchAssignmentService private readonly assignmentService: IWorkbenchAssignmentService
) {
super();

if (isLinux && productService.quality === 'stable') {
this.handleDefaultTitlebarStyle(); // TODO@bpasero remove me eventually once settled
}
}

private handleDefaultTitlebarStyle(): void {
this.updateDefaultTitlebarStyle();
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('window.titleBarStyle')) {
this.updateDefaultTitlebarStyle();
}
}));
}

private async updateDefaultTitlebarStyle(): Promise<void> {
const titleBarStyle = this.configurationService.inspect('window.titleBarStyle');

let titleBarStyleOverride: 'custom' | undefined;
if (titleBarStyle.applicationValue || titleBarStyle.userValue) {
// configured by user or application: clear override
titleBarStyleOverride = undefined;
} else {
// not configured: set override if experiment is active
const value = await this.treatment;
if (value === 'custom') {
titleBarStyleOverride = 'custom';
}
}

await this.nativeHostService.overrideDefaultTitlebarStyle(titleBarStyleOverride);
}
}

0 comments on commit 62aabbc

Please sign in to comment.