Allow custom titlebar on Linux as experiment (microsoft/vscode-internalbacklog#4857) (#237337)
parent
292d0bd51a
commit
b7f437d2a1
|
@ -83,7 +83,7 @@ import { NativeURLService } from '../../platform/url/common/urlService.js';
|
|||
import { ElectronURLListener } from '../../platform/url/electron-main/electronUrlListener.js';
|
||||
import { IWebviewManagerService } from '../../platform/webview/common/webviewManagerService.js';
|
||||
import { WebviewMainService } from '../../platform/webview/electron-main/webviewMainService.js';
|
||||
import { isFolderToOpen, isWorkspaceToOpen, IWindowOpenable } from '../../platform/window/common/window.js';
|
||||
import { isFolderToOpen, isWorkspaceToOpen, IWindowOpenable, TitlebarStyle, overrideDefaultTitlebarStyle } from '../../platform/window/common/window.js';
|
||||
import { IWindowsMainService, OpenContext } from '../../platform/windows/electron-main/windows.js';
|
||||
import { ICodeWindow } from '../../platform/window/electron-main/window.js';
|
||||
import { WindowsMainService } from '../../platform/windows/electron-main/windowsMainService.js';
|
||||
|
@ -593,6 +593,14 @@ export class CodeApplication extends Disposable {
|
|||
// Services
|
||||
const appInstantiationService = await this.initServices(machineId, sqmId, devDeviceId, sharedProcessReady);
|
||||
|
||||
// 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) {
|
||||
overrideDefaultTitlebarStyle(titleBarDefaultStyleOverride);
|
||||
}
|
||||
}
|
||||
|
||||
// Auth Handler
|
||||
appInstantiationService.invokeFunction(accessor => accessor.get(IProxyAuthService));
|
||||
|
||||
|
@ -605,7 +613,7 @@ export class CodeApplication extends Disposable {
|
|||
// Setup Protocol URL Handlers
|
||||
const initialProtocolUrls = await appInstantiationService.invokeFunction(accessor => this.setupProtocolUrlHandlers(accessor, mainProcessElectronServer));
|
||||
|
||||
// Setup vscode-remote-resource protocol handler.
|
||||
// Setup vscode-remote-resource protocol handler
|
||||
this.setupManagedRemoteResourceUrlHandler(mainProcessElectronServer);
|
||||
|
||||
// Signal phase: ready - before opening first window
|
||||
|
|
|
@ -113,6 +113,9 @@ export interface ICommonNativeHostService {
|
|||
*/
|
||||
focusWindow(options?: INativeHostOptions & { force?: boolean }): Promise<void>;
|
||||
|
||||
// Titlebar default style override
|
||||
overrideDefaultTitlebarStyle(style: 'native' | 'custom' | undefined): Promise<void>;
|
||||
|
||||
// Dialogs
|
||||
showMessageBox(options: MessageBoxOptions & INativeHostOptions): Promise<MessageBoxReturnValue>;
|
||||
showSaveDialog(options: SaveDialogOptions & INativeHostOptions): Promise<SaveDialogReturnValue>;
|
||||
|
@ -143,10 +146,6 @@ export interface ICommonNativeHostService {
|
|||
hasWSLFeatureInstalled(): Promise<boolean>;
|
||||
|
||||
// Screenshots
|
||||
|
||||
/**
|
||||
* Gets a screenshot of the currently active Electron window.
|
||||
*/
|
||||
getScreenshot(): Promise<ArrayBufferLike | undefined>;
|
||||
|
||||
// Process
|
||||
|
@ -199,7 +198,7 @@ export interface ICommonNativeHostService {
|
|||
loadCertificates(): Promise<string[]>;
|
||||
findFreePort(startPort: number, giveUpAfter: number, timeout: number, stride?: number): Promise<number>;
|
||||
|
||||
// Registry (windows only)
|
||||
// Registry (Windows only)
|
||||
windowsGetStringRegKey(hive: 'HKEY_CURRENT_USER' | 'HKEY_LOCAL_MACHINE' | 'HKEY_CLASSES_ROOT' | 'HKEY_USERS' | 'HKEY_CURRENT_CONFIG', path: string, name: string): Promise<string | undefined>;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 } from '../../window/common/window.js';
|
||||
import { IColorScheme, IOpenedAuxiliaryWindow, IOpenedMainWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IPoint, IRectangle, IWindowOpenable, overrideDefaultTitlebarStyle } 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';
|
||||
|
@ -48,6 +48,7 @@ import { IConfigurationService } from '../../configuration/common/configuration.
|
|||
import { IProxyAuthService } from './auth.js';
|
||||
import { AuthInfo, Credentials, IRequestService } from '../../request/common/request.js';
|
||||
import { randomPath } from '../../../base/common/extpath.js';
|
||||
import { IStateService } from '../../state/node/state.js';
|
||||
|
||||
export interface INativeHostMainService extends AddFirstParameterToFunctions<ICommonNativeHostService, Promise<unknown> /* only methods, not events */, number | undefined /* window ID */> { }
|
||||
|
||||
|
@ -70,7 +71,8 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
|
|||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IRequestService private readonly requestService: IRequestService,
|
||||
@IProxyAuthService private readonly proxyAuthService: IProxyAuthService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IStateService private readonly stateService: IStateService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -324,6 +326,15 @@ 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') {
|
||||
this.stateService.setItem('window.titleBarStyleOverride', style);
|
||||
} else {
|
||||
this.stateService.removeItem('window.titleBarStyleOverride');
|
||||
}
|
||||
overrideDefaultTitlebarStyle(style);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
@ -697,6 +708,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
|
|||
async getScreenshot(windowId: number | undefined, options?: INativeHostOptions): Promise<ArrayBufferLike | undefined> {
|
||||
const window = this.windowById(options?.targetWindowId, windowId);
|
||||
const captured = await window?.win?.webContents.capturePage();
|
||||
|
||||
return captured?.toJPEG(95);
|
||||
}
|
||||
|
||||
|
|
|
@ -187,10 +187,23 @@ 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 function hasCustomTitlebar(configurationService: IConfigurationService, titleBarStyle?: TitlebarStyle): boolean {
|
||||
// Returns if it possible to have a custom title bar in the curren session
|
||||
// Does not imply that the title bar is visible
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -198,6 +211,7 @@ export function hasNativeTitlebar(configurationService: IConfigurationService, t
|
|||
if (!titleBarStyle) {
|
||||
titleBarStyle = getTitleBarStyle(configurationService);
|
||||
}
|
||||
|
||||
return titleBarStyle === TitlebarStyle.NATIVE;
|
||||
}
|
||||
|
||||
|
@ -224,6 +238,10 @@ export function getTitleBarStyle(configurationService: IConfigurationService): T
|
|||
}
|
||||
}
|
||||
|
||||
if (titlebarStyleDefaultOverride) {
|
||||
return titlebarStyleDefaultOverride;
|
||||
}
|
||||
|
||||
return isLinux && product.quality === 'stable' ? TitlebarStyle.NATIVE : TitlebarStyle.CUSTOM; // default to custom on all OS except Linux stable (for now)
|
||||
}
|
||||
|
||||
|
|
|
@ -234,6 +234,7 @@ 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."),
|
||||
},
|
||||
|
|
|
@ -27,6 +27,7 @@ import { IEditorGroupsContainer, IEditorGroupsService } from '../../../services/
|
|||
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';
|
||||
|
||||
export class NativeTitlebarPart extends BrowserTitlebarPart {
|
||||
|
||||
|
@ -70,7 +71,7 @@ export class NativeTitlebarPart extends BrowserTitlebarPart {
|
|||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IHostService hostService: IHostService,
|
||||
@INativeHostService private readonly nativeHostService: INativeHostService,
|
||||
@INativeHostService protected readonly nativeHostService: INativeHostService,
|
||||
@IEditorGroupsService editorGroupService: IEditorGroupsService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
|
@ -287,9 +288,38 @@ export class MainNativeTitlebarPart extends NativeTitlebarPart {
|
|||
@IEditorGroupsService editorGroupService: IEditorGroupsService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IKeybindingService keybindingService: IKeybindingService
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IProductService productService: IProductService
|
||||
) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -162,6 +162,7 @@ export class TestNativeHostService implements INativeHostService {
|
|||
async windowsGetStringRegKey(hive: 'HKEY_CURRENT_USER' | 'HKEY_LOCAL_MACHINE' | 'HKEY_CLASSES_ROOT' | 'HKEY_USERS' | 'HKEY_CURRENT_CONFIG', path: string, name: string): Promise<string | undefined> { return undefined; }
|
||||
async profileRenderer(): Promise<any> { throw new Error(); }
|
||||
async getScreenshot(): Promise<ArrayBufferLike | undefined> { return undefined; }
|
||||
async overrideDefaultTitlebarStyle(style: 'native' | 'custom' | undefined): Promise<void> { }
|
||||
}
|
||||
|
||||
export class TestExtensionTipsService extends AbstractNativeExtensionTipsService {
|
||||
|
|
Loading…
Reference in New Issue