Skip to content

Commit

Permalink
splash - include more parts with override support (#238691)
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero authored Jan 24, 2025
1 parent a1c6c50 commit baf5cf7
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 81 deletions.
174 changes: 106 additions & 68 deletions src/vs/code/electron-sandbox/workbench/workbench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,63 +102,67 @@
}

// ensure there is enough space
layoutInfo.sideBarWidth = Math.min(layoutInfo.sideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth));
layoutInfo.auxiliarySideBarWidth = Math.min(layoutInfo.auxiliarySideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth + layoutInfo.sideBarWidth));
layoutInfo.sideBarWidth = Math.min(layoutInfo.sideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth + layoutInfo.auxiliarySideBarWidth));

// part: title
const titleDiv = document.createElement('div');
titleDiv.style.position = 'absolute';
titleDiv.style.width = '100%';
titleDiv.style.height = `${layoutInfo.titleBarHeight}px`;
titleDiv.style.left = '0';
titleDiv.style.top = '0';
titleDiv.style.backgroundColor = `${colorInfo.titleBarBackground}`;
(titleDiv.style as any)['-webkit-app-region'] = 'drag';
splash.appendChild(titleDiv);

if (colorInfo.titleBarBorder && layoutInfo.titleBarHeight > 0) {
const titleBorder = document.createElement('div');
titleBorder.style.position = 'absolute';
titleBorder.style.width = '100%';
titleBorder.style.height = '1px';
titleBorder.style.left = '0';
titleBorder.style.bottom = '0';
titleBorder.style.borderBottom = `1px solid ${colorInfo.titleBarBorder}`;
titleDiv.appendChild(titleBorder);
if (layoutInfo.titleBarHeight > 0) {
const titleDiv = document.createElement('div');
titleDiv.style.position = 'absolute';
titleDiv.style.width = '100%';
titleDiv.style.height = `${layoutInfo.titleBarHeight}px`;
titleDiv.style.left = '0';
titleDiv.style.top = '0';
titleDiv.style.backgroundColor = `${colorInfo.titleBarBackground}`;
(titleDiv.style as any)['-webkit-app-region'] = 'drag';
splash.appendChild(titleDiv);

if (colorInfo.titleBarBorder) {
const titleBorder = document.createElement('div');
titleBorder.style.position = 'absolute';
titleBorder.style.width = '100%';
titleBorder.style.height = '1px';
titleBorder.style.left = '0';
titleBorder.style.bottom = '0';
titleBorder.style.borderBottom = `1px solid ${colorInfo.titleBarBorder}`;
titleDiv.appendChild(titleBorder);
}
}

// part: activity bar
const activityDiv = document.createElement('div');
activityDiv.style.position = 'absolute';
activityDiv.style.width = `${layoutInfo.activityBarWidth}px`;
activityDiv.style.height = `calc(100% - ${layoutInfo.titleBarHeight + layoutInfo.statusBarHeight}px)`;
activityDiv.style.top = `${layoutInfo.titleBarHeight}px`;
if (layoutInfo.sideBarSide === 'left') {
activityDiv.style.left = '0';
} else {
activityDiv.style.right = '0';
}
activityDiv.style.backgroundColor = `${colorInfo.activityBarBackground}`;
splash.appendChild(activityDiv);

if (colorInfo.activityBarBorder && layoutInfo.activityBarWidth > 0) {
const activityBorderDiv = document.createElement('div');
activityBorderDiv.style.position = 'absolute';
activityBorderDiv.style.width = '1px';
activityBorderDiv.style.height = '100%';
activityBorderDiv.style.top = '0';
if (layoutInfo.activityBarWidth > 0) {
const activityDiv = document.createElement('div');
activityDiv.style.position = 'absolute';
activityDiv.style.width = `${layoutInfo.activityBarWidth}px`;
activityDiv.style.height = `calc(100% - ${layoutInfo.titleBarHeight + layoutInfo.statusBarHeight}px)`;
activityDiv.style.top = `${layoutInfo.titleBarHeight}px`;
if (layoutInfo.sideBarSide === 'left') {
activityBorderDiv.style.right = '0';
activityBorderDiv.style.borderRight = `1px solid ${colorInfo.activityBarBorder}`;
activityDiv.style.left = '0';
} else {
activityBorderDiv.style.left = '0';
activityBorderDiv.style.borderLeft = `1px solid ${colorInfo.activityBarBorder}`;
activityDiv.style.right = '0';
}
activityDiv.style.backgroundColor = `${colorInfo.activityBarBackground}`;
splash.appendChild(activityDiv);

if (colorInfo.activityBarBorder) {
const activityBorderDiv = document.createElement('div');
activityBorderDiv.style.position = 'absolute';
activityBorderDiv.style.width = '1px';
activityBorderDiv.style.height = '100%';
activityBorderDiv.style.top = '0';
if (layoutInfo.sideBarSide === 'left') {
activityBorderDiv.style.right = '0';
activityBorderDiv.style.borderRight = `1px solid ${colorInfo.activityBarBorder}`;
} else {
activityBorderDiv.style.left = '0';
activityBorderDiv.style.borderLeft = `1px solid ${colorInfo.activityBarBorder}`;
}
activityDiv.appendChild(activityBorderDiv);
}
activityDiv.appendChild(activityBorderDiv);
}

// part: side bar (only when opening workspace/folder)
// folder or workspace -> status bar color, sidebar
if (configuration.workspace) {
if (configuration.workspace && layoutInfo.sideBarWidth > 0) {
const sideDiv = document.createElement('div');
sideDiv.style.position = 'absolute';
sideDiv.style.width = `${layoutInfo.sideBarWidth}px`;
Expand All @@ -172,7 +176,7 @@
sideDiv.style.backgroundColor = `${colorInfo.sideBarBackground}`;
splash.appendChild(sideDiv);

if (colorInfo.sideBarBorder && layoutInfo.sideBarWidth > 0) {
if (colorInfo.sideBarBorder) {
const sideBorderDiv = document.createElement('div');
sideBorderDiv.style.position = 'absolute';
sideBorderDiv.style.width = '1px';
Expand All @@ -189,28 +193,62 @@
}
}

// part: statusbar
const statusDiv = document.createElement('div');
statusDiv.style.position = 'absolute';
statusDiv.style.width = '100%';
statusDiv.style.height = `${layoutInfo.statusBarHeight}px`;
statusDiv.style.bottom = '0';
statusDiv.style.left = '0';
if (configuration.workspace && colorInfo.statusBarBackground) {
statusDiv.style.backgroundColor = colorInfo.statusBarBackground;
} else if (!configuration.workspace && colorInfo.statusBarNoFolderBackground) {
statusDiv.style.backgroundColor = colorInfo.statusBarNoFolderBackground;
// part: auxiliary sidebar
if (layoutInfo.auxiliarySideBarWidth > 0) {
const auxSideDiv = document.createElement('div');
auxSideDiv.style.position = 'absolute';
auxSideDiv.style.width = `${layoutInfo.auxiliarySideBarWidth}px`;
auxSideDiv.style.height = `calc(100% - ${layoutInfo.titleBarHeight + layoutInfo.statusBarHeight}px)`;
auxSideDiv.style.top = `${layoutInfo.titleBarHeight}px`;
if (layoutInfo.sideBarSide === 'left') {
auxSideDiv.style.right = '0';
} else {
auxSideDiv.style.left = '0';
}
auxSideDiv.style.backgroundColor = `${colorInfo.sideBarBackground}`;
splash.appendChild(auxSideDiv);

if (colorInfo.sideBarBorder) {
const auxSideBorderDiv = document.createElement('div');
auxSideBorderDiv.style.position = 'absolute';
auxSideBorderDiv.style.width = '1px';
auxSideBorderDiv.style.height = '100%';
auxSideBorderDiv.style.top = '0';
if (layoutInfo.sideBarSide === 'left') {
auxSideBorderDiv.style.left = '0';
auxSideBorderDiv.style.borderLeft = `1px solid ${colorInfo.sideBarBorder}`;
} else {
auxSideBorderDiv.style.right = '0';
auxSideBorderDiv.style.borderRight = `1px solid ${colorInfo.sideBarBorder}`;
}
auxSideDiv.appendChild(auxSideBorderDiv);
}
}
splash.appendChild(statusDiv);

if (colorInfo.statusBarBorder && layoutInfo.statusBarHeight > 0) {
const statusBorderDiv = document.createElement('div');
statusBorderDiv.style.position = 'absolute';
statusBorderDiv.style.width = '100%';
statusBorderDiv.style.height = '1px';
statusBorderDiv.style.top = '0';
statusBorderDiv.style.borderTop = `1px solid ${colorInfo.statusBarBorder}`;
statusDiv.appendChild(statusBorderDiv);

// part: statusbar
if (layoutInfo.statusBarHeight > 0) {
const statusDiv = document.createElement('div');
statusDiv.style.position = 'absolute';
statusDiv.style.width = '100%';
statusDiv.style.height = `${layoutInfo.statusBarHeight}px`;
statusDiv.style.bottom = '0';
statusDiv.style.left = '0';
if (configuration.workspace && colorInfo.statusBarBackground) {
statusDiv.style.backgroundColor = colorInfo.statusBarBackground;
} else if (!configuration.workspace && colorInfo.statusBarNoFolderBackground) {
statusDiv.style.backgroundColor = colorInfo.statusBarNoFolderBackground;
}
splash.appendChild(statusDiv);

if (colorInfo.statusBarBorder) {
const statusBorderDiv = document.createElement('div');
statusBorderDiv.style.position = 'absolute';
statusBorderDiv.style.width = '100%';
statusBorderDiv.style.height = '1px';
statusBorderDiv.style.top = '0';
statusBorderDiv.style.borderTop = `1px solid ${colorInfo.statusBarBorder}`;
statusDiv.appendChild(statusBorderDiv);
}
}

window.document.body.appendChild(splash);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,9 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
}

async saveWindowSplash(windowId: number | undefined, splash: IPartsSplash): Promise<void> {
this.themeMainService.saveWindowSplash(windowId, splash);
const window = this.codeWindowById(windowId);

this.themeMainService.saveWindowSplash(windowId, window?.openedWorkspace, splash);
}

async overrideDefaultTitlebarStyle(windowId: number | undefined, style: 'custom' | undefined): Promise<void> {
Expand Down
7 changes: 7 additions & 0 deletions src/vs/platform/theme/common/themeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,15 @@ export interface IPartsSplash {
titleBarHeight: number;
activityBarWidth: number;
sideBarWidth: number;
auxiliarySideBarWidth: number;
statusBarHeight: number;
windowBorder: boolean;
windowBorderRadius: string | undefined;
} | undefined;
}

export interface IPartsSplashWorkspaceOverride {
layoutInfo: {
auxiliarySideBarWidth: [number, string[] /* workspace identifier the override applies to */];
};
}
84 changes: 74 additions & 10 deletions src/vs/platform/theme/electron-main/themeMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import { isLinux, isMacintosh, isWindows } from '../../../base/common/platform.j
import { IConfigurationService } from '../../configuration/common/configuration.js';
import { createDecorator } from '../../instantiation/common/instantiation.js';
import { IStateService } from '../../state/node/state.js';
import { IPartsSplash } from '../common/themeService.js';
import { IPartsSplash, IPartsSplashWorkspaceOverride } from '../common/themeService.js';
import { IColorScheme } from '../../window/common/window.js';
import { ThemeTypeSelector } from '../common/theme.js';
import { IBaseWorkspaceIdentifier } from '../../workspace/common/workspace.js';
import { coalesce } from '../../../base/common/arrays.js';

// These default colors match our default themes
// editor background color ("Dark Modern", etc...)
Expand All @@ -23,7 +25,9 @@ const DEFAULT_BG_HC_LIGHT = '#FFFFFF';

const THEME_STORAGE_KEY = 'theme';
const THEME_BG_STORAGE_KEY = 'themeBackground';
const THEME_WINDOW_SPLASH = 'windowSplash';

const THEME_WINDOW_SPLASH_KEY = 'windowSplash';
const THEME_WINDOW_SPLASH_WORKSPACE_OVERRIDE_KEY = 'windowSplashWorkspaceOverride';

namespace ThemeSettings {
export const DETECT_COLOR_SCHEME = 'window.autoDetectColorScheme';
Expand All @@ -41,8 +45,8 @@ export interface IThemeMainService {

getBackgroundColor(): string;

saveWindowSplash(windowId: number | undefined, splash: IPartsSplash): void;
getWindowSplash(): IPartsSplash | undefined;
saveWindowSplash(windowId: number | undefined, workspace: IBaseWorkspaceIdentifier | undefined, splash: IPartsSplash): void;
getWindowSplash(workspace: IBaseWorkspaceIdentifier | undefined): IPartsSplash | undefined;

getColorScheme(): IColorScheme;
}
Expand Down Expand Up @@ -163,14 +167,18 @@ export class ThemeMainService extends Disposable implements IThemeMainService {
}
}

saveWindowSplash(windowId: number | undefined, splash: IPartsSplash): void {
saveWindowSplash(windowId: number | undefined, workspace: IBaseWorkspaceIdentifier | undefined, splash: IPartsSplash): void {

// Update override as needed
const splashOverride = this.updateWindowSplashOverride(workspace, splash);

// Update in storage
this.stateService.setItems([
this.stateService.setItems(coalesce([
{ key: THEME_STORAGE_KEY, data: splash.baseTheme },
{ key: THEME_BG_STORAGE_KEY, data: splash.colorInfo.background },
{ key: THEME_WINDOW_SPLASH, data: splash }
]);
{ key: THEME_WINDOW_SPLASH_KEY, data: splash },
splashOverride ? { key: THEME_WINDOW_SPLASH_WORKSPACE_OVERRIDE_KEY, data: splashOverride } : undefined
]));

// Update in opened windows
if (typeof windowId === 'number') {
Expand All @@ -181,6 +189,35 @@ export class ThemeMainService extends Disposable implements IThemeMainService {
this.updateSystemColorTheme();
}

private updateWindowSplashOverride(workspace: IBaseWorkspaceIdentifier | undefined, splash: IPartsSplash): IPartsSplashWorkspaceOverride | undefined {
let splashOverride: IPartsSplashWorkspaceOverride | undefined = undefined;
let changed = false;
if (workspace) {
splashOverride = { ...this.getWindowSplashOverride() }; // make a copy for modifications

const [auxiliarySideBarWidth, workspaceIds] = splashOverride.layoutInfo.auxiliarySideBarWidth;
if (splash.layoutInfo?.auxiliarySideBarWidth) {
if (auxiliarySideBarWidth !== splash.layoutInfo.auxiliarySideBarWidth) {
splashOverride.layoutInfo.auxiliarySideBarWidth[0] = splash.layoutInfo.auxiliarySideBarWidth;
changed = true;
}

if (!workspaceIds.includes(workspace.id)) {
workspaceIds.push(workspace.id);
changed = true;
}
} else {
const index = workspaceIds.indexOf(workspace.id);
if (index > -1) {
workspaceIds.splice(index, 1);
changed = true;
}
}
}

return changed ? splashOverride : undefined;
}

private updateBackgroundColor(windowId: number, splash: IPartsSplash): void {
for (const window of electron.BrowserWindow.getAllWindows()) {
if (window.id === windowId) {
Expand All @@ -190,7 +227,34 @@ export class ThemeMainService extends Disposable implements IThemeMainService {
}
}

getWindowSplash(): IPartsSplash | undefined {
return this.stateService.getItem<IPartsSplash>(THEME_WINDOW_SPLASH);
getWindowSplash(workspace: IBaseWorkspaceIdentifier | undefined): IPartsSplash | undefined {
const partSplash = this.stateService.getItem<IPartsSplash>(THEME_WINDOW_SPLASH_KEY);
if (!partSplash?.layoutInfo) {
return partSplash; // return early: overrides currently only apply to layout info
}

// Apply workspace specific overrides
let auxiliarySideBarWidthOverride: number | undefined;
if (workspace) {
const [auxiliarySideBarWidth, workspaceIds] = this.getWindowSplashOverride().layoutInfo.auxiliarySideBarWidth;
if (workspaceIds.includes(workspace.id)) {
auxiliarySideBarWidthOverride = auxiliarySideBarWidth;
}
}

return {
...partSplash,
layoutInfo: {
...partSplash.layoutInfo,
// Only apply an auxiliary bar width when we have a workspace specific
// override. Auxiliary bar is not visible by default unless explicitly
// opened in a workspace.
auxiliarySideBarWidth: typeof auxiliarySideBarWidthOverride === 'number' ? auxiliarySideBarWidthOverride : 0
}
};
}

private getWindowSplashOverride(): IPartsSplashWorkspaceOverride {
return this.stateService.getItem<IPartsSplashWorkspaceOverride>(THEME_WINDOW_SPLASH_WORKSPACE_OVERRIDE_KEY, { layoutInfo: { auxiliarySideBarWidth: [0, []] } });
}
}
2 changes: 1 addition & 1 deletion src/vs/platform/windows/electron-main/windowImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
}
configuration.fullscreen = this.isFullScreen;
configuration.maximized = this._win.isMaximized();
configuration.partsSplash = this.themeMainService.getWindowSplash();
configuration.partsSplash = this.themeMainService.getWindowSplash(configuration.workspace);
configuration.zoomLevel = this.getZoomLevel();
configuration.isCustomZoomLevel = typeof this.customZoomLevel === 'number';
if (configuration.isCustomZoomLevel && configuration.partsSplash) {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/platform/windows/electron-main/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowSt
// to use on initialization, but prefer to keep things
// simple as it is temporary and not noticeable

const titleBarColor = themeMainService.getWindowSplash()?.colorInfo.titleBarBackground ?? themeMainService.getBackgroundColor();
const titleBarColor = themeMainService.getWindowSplash(undefined)?.colorInfo.titleBarBackground ?? themeMainService.getBackgroundColor();
const symbolColor = Color.fromHex(titleBarColor).isDarker() ? '#FFFFFF' : '#000000';

options.titleBarOverlay = {
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/contrib/splash/browser/partsSplash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export class PartsSplash {
titleBarHeight: this._layoutService.isVisible(Parts.TITLEBAR_PART, mainWindow) ? dom.getTotalHeight(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.TITLEBAR_PART))) : 0,
activityBarWidth: this._layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? dom.getTotalWidth(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.ACTIVITYBAR_PART))) : 0,
sideBarWidth: this._layoutService.isVisible(Parts.SIDEBAR_PART) ? dom.getTotalWidth(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.SIDEBAR_PART))) : 0,
auxiliarySideBarWidth: this._layoutService.isVisible(Parts.AUXILIARYBAR_PART) ? dom.getTotalWidth(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.AUXILIARYBAR_PART))) : 0,
statusBarHeight: this._layoutService.isVisible(Parts.STATUSBAR_PART, mainWindow) ? dom.getTotalHeight(assertIsDefined(this._layoutService.getContainer(mainWindow, Parts.STATUSBAR_PART))) : 0,
windowBorder: this._layoutService.hasMainWindowBorder(),
windowBorderRadius: this._layoutService.getMainWindowBorderRadius()
Expand Down
Loading

0 comments on commit baf5cf7

Please sign in to comment.