Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows, macOS and Linux transparency #52707

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c8410a6
Add WIP transparency implementation
sylveon Jun 20, 2018
f2a6835
Move windows-swca to dev dependencies
sylveon Jun 20, 2018
80e2134
Make Linux transparency functional, add macOS vibrancy
sylveon Jun 21, 2018
7b0758a
Add Windows 10 check
sylveon Jun 21, 2018
49b2ae6
Simplify Windows transparency check
sylveon Jun 21, 2018
57dd9bd
Add relauncher contributions, Windows 7 blur behind and version gate …
sylveon Jun 22, 2018
e0425aa
Add enumDescriptions for window.compositionAttribute
sylveon Jun 22, 2018
bcc6279
Fix various rendering bugs
sylveon Jun 23, 2018
b948bb0
Merge branch 'master' of https://github.com/Microsoft/vscode
sylveon Jun 23, 2018
005b173
Use app.getPath instead of getUserDataPath
sylveon Jun 23, 2018
05d04d3
Merge branch 'master' into swca
sylveon Aug 31, 2018
759338d
Add missing comma, fix build issue
sylveon Sep 7, 2018
cabf2a0
Fix build errors
sylveon Oct 1, 2018
c28bb4a
Merge branch 'master' of https://github.com/Microsoft/vscode into swca
sylveon Oct 1, 2018
e2c723f
Merge branch 'master' into swca
sylveon Oct 26, 2018
f7761cf
Fix build error
sylveon Nov 3, 2018
702ebd4
Merge branch 'master' into swca
sylveon Dec 1, 2018
2c30a0a
Fix hygiene checks
sylveon Dec 2, 2018
ba9fc59
Merge branch 'master' into swca
sylveon Dec 4, 2018
6649a25
Merge branch 'master' of https://github.com/Microsoft/vscode into swca
sylveon Jan 24, 2019
759afda
Merge branch 'master' of https://github.com/Microsoft/vscode into swca
sylveon Jan 25, 2019
4453508
Update windows-swca to latest version, drop windows 7 support
sylveon Mar 3, 2019
7e22533
Merge branch 'master' of https://github.com/Microsoft/vscode into swca
sylveon Mar 3, 2019
36b1ce2
Merge branch 'master' of https://github.com/Microsoft/vscode into swca
sylveon Apr 17, 2019
24f56c3
Just send 0 to SetWindowCompositionAttribute
sylveon Apr 17, 2019
c29d4c8
Fix build errors
sylveon Apr 17, 2019
23b9813
Merge branch 'master' of https://github.com/Microsoft/vscode into swca
sylveon Jul 2, 2019
dd3a6ac
Update acrylic effect description
sylveon Jul 2, 2019
cc027c4
Add hot reload of vibrancy and composition attribute
sylveon Jul 2, 2019
77f386e
Rename setWindowsCompositionAttribute
sylveon Jul 2, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
"vscode-windows-registry": "1.0.1",
"windows-foreground-love": "0.1.0",
"windows-mutex": "0.2.1",
"windows-process-tree": "0.2.3"
"windows-process-tree": "0.2.3",
"windows-swca": "2.0.1"
}
}
12 changes: 12 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,18 @@ function configureCommandlineSwitches(cliArgs, nodeCachedDataDir) {
if (cliArgs['disable-smooth-scrolling']) {
app.commandLine.appendSwitch('disable-smooth-scrolling');
}

// Linux: disable hardware acceleration when transparent window is enabled
if (process.platform === 'linux') {
const configFile = path.join(app.getPath('userData'), 'User', 'settings.json');
bootstrap.readFile(configFile).then(content => {
const config = JSON.parse(stripComments(content));
if (config['window.transparent']) {
app.commandLine.appendSwitch('enable-transparent-visuals');
app.disableHardwareAcceleration();
}
});
}
}

/**
Expand Down
83 changes: 70 additions & 13 deletions src/vs/code/electron-main/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import * as path from 'vs/base/common/path';
import * as objects from 'vs/base/common/objects';
import * as os from 'os';
import * as nls from 'vs/nls';
import { URI } from 'vs/base/common/uri';
import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display } from 'electron';
Expand Down Expand Up @@ -116,9 +117,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
const [state, hasMultipleDisplays] = this.restoreWindowState(config.state);
this.windowState = state;

// in case we are maximized or fullscreen, only show later after the call to maximize/fullscreen (see below)
const isFullscreenOrMaximized = (this.windowState.mode === WindowMode.Maximized || this.windowState.mode === WindowMode.Fullscreen);

const options: Electron.BrowserWindowConstructorOptions = {
width: this.windowState.width,
height: this.windowState.height,
Expand All @@ -127,7 +125,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
backgroundColor: this.themeMainService.getBackgroundColor(),
minWidth: CodeWindow.MIN_WIDTH,
minHeight: CodeWindow.MIN_HEIGHT,
show: !isFullscreenOrMaximized,
show: false,
title: product.nameLong,
webPreferences: {
// By default if Code is in the background, intervals and timeouts get throttled, so we
Expand All @@ -140,14 +138,20 @@ export class CodeWindow extends Disposable implements ICodeWindow {

if (isLinux) {
options.icon = path.join(this.environmentService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s)
}

const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
// Make sure hardware acceleration is actually disabled.
//options.transparent = windowConfig && windowConfig.transparent && app.getGPUFeatureStatus().gpu_compositing !== 'enabled';
//if (options.transparent) {
// options.backgroundColor = '#00000000';
//}
}

if (isMacintosh && !this.useNativeFullScreen()) {
options.fullscreenable = false; // enables simple fullscreen mode
}

const windowConfig = this.configurationService.getValue<IWindowSettings>('window');

if (isMacintosh) {
options.acceptFirstMouse = true; // enabled by default

Expand Down Expand Up @@ -178,6 +182,8 @@ export class CodeWindow extends Disposable implements ICodeWindow {
this._win.setSheetOffset(22); // offset dialogs by the height of the custom title bar if we have any
}

this.applyTransparency(windowConfig);

// TODO@Ben (Electron 4 regression): when running on multiple displays where the target display
// to open the window has a larger resolution than the primary display, the window will not size
// correctly unless we set the bounds again (https://github.com/microsoft/vscode/issues/74872)
Expand All @@ -196,19 +202,68 @@ export class CodeWindow extends Disposable implements ICodeWindow {
}
}

if (isFullscreenOrMaximized) {
if (this.windowState.mode === WindowMode.Maximized) {
this._win.maximize();
} else if (this.windowState.mode === WindowMode.Fullscreen) {
this.setFullScreen(true);
}

if (this.windowState.mode === WindowMode.Fullscreen) {
this.setFullScreen(true);
}
// to reduce flicker from the default window size to maximize, we only show after maximize
// also prevents temporary background flash when transparency is set.
this._win.show();

if (!this._win.isVisible()) {
this._win.show(); // to reduce flicker from the default window size to maximize, we only show after maximize
this._lastFocusTime = Date.now(); // since we show directly, we need to set the last focus time too
}

private setCompositionAttribute(attribute: 'acrylic' | 'blur' | 'transparent' | 'none'): void {
const { ACCENT_STATE, SetWindowCompositionAttribute } = require.__$__nodeRequire('windows-swca');
let attribValue = ACCENT_STATE.ACCENT_DISABLED;
switch (attribute) {
case 'acrylic':
// Fluent/acrylic flag was introduced in Windows 10 build 17063 (between FCU and April 2018 update)
if (parseInt(os.release().split('.')[2]) >= 17063) {
attribValue = ACCENT_STATE.ACCENT_ENABLE_ACRYLICBLURBEHIND;
}
break;

case 'blur':
attribValue = ACCENT_STATE.ACCENT_ENABLE_BLURBEHIND;
break;

case 'transparent':
attribValue = ACCENT_STATE.ACCENT_ENABLE_TRANSPARENTGRADIENT;
break;
}

SetWindowCompositionAttribute(this._win.getNativeWindowHandle(), attribValue, 0);
}

private applyTransparency(windowConfig: IWindowSettings): void {
let applied = false;

if (windowConfig) {
if (isWindows && parseFloat(os.release()) >= 10) {
if (windowConfig.compositionAttribute && windowConfig.compositionAttribute !== 'none' && this.hasHiddenTitleBarStyle()) {
this.setCompositionAttribute(windowConfig.compositionAttribute);
applied = true;
} else {
this.setCompositionAttribute('none');
}
} else if (isMacintosh && parseFloat(os.release()) >= 14) {
if (windowConfig.vibrancy && windowConfig.vibrancy !== 'none') {
this._win.setVibrancy(windowConfig.vibrancy);
applied = true;
} else {
// Documentation says to pass null to remove vibrancy but this is not reflected in the typings
this._win.setVibrancy(null as any);
}
} else if (isLinux) {
// TODO
}
}

this._lastFocusTime = Date.now(); // since we show directly, we need to set the last focus time too
// FIXME: on windows, background is pitchblack at startup until the user changes the composition attribute in settings
this._win.setBackgroundColor(applied ? '#00000000' : this.themeMainService.getBackgroundColor());
}

hasHiddenTitleBarStyle(): boolean {
Expand Down Expand Up @@ -471,6 +526,8 @@ export class CodeWindow extends Disposable implements ICodeWindow {
this._win.removeAllListeners('swipe');
}
}

this.applyTransparency(this.configurationService.getValue<IWindowSettings>('window'));
}

private registerNavigationListenerOn(command: 'swipe' | 'app-command', back: 'left' | 'browser-backward', forward: 'right' | 'browser-forward', acrossEditors: boolean) {
Expand Down
3 changes: 2 additions & 1 deletion src/vs/editor/browser/viewParts/minimap/minimap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ class MinimapBuffers {
const backgroundR = background.r;
const backgroundG = background.g;
const backgroundB = background.b;
const backgroundA = background.a;

const result = new Uint8ClampedArray(WIDTH * HEIGHT * 4);
let offset = 0;
Expand All @@ -427,7 +428,7 @@ class MinimapBuffers {
result[offset] = backgroundR;
result[offset + 1] = backgroundG;
result[offset + 2] = backgroundB;
result[offset + 3] = 255;
result[offset + 3] = backgroundA;
offset += 4;
}
}
Expand Down
30 changes: 30 additions & 0 deletions src/vs/editor/common/view/minimapCharRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,12 @@ export class MinimapCharRenderer {
const backgroundR = backgroundColor.r;
const backgroundG = backgroundColor.g;
const backgroundB = backgroundColor.b;
const backgroundA = backgroundColor.a;

const deltaR = color.r - backgroundR;
const deltaG = color.g - backgroundG;
const deltaB = color.b - backgroundB;
const deltaA = color.a - backgroundA;

const dest = target.data;
const sourceOffset = chIndex * Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH;
Expand All @@ -148,12 +150,14 @@ export class MinimapCharRenderer {
dest[destOffset + 0] = backgroundR + deltaR * c;
dest[destOffset + 1] = backgroundG + deltaG * c;
dest[destOffset + 2] = backgroundB + deltaB * c;
dest[destOffset + 3] = backgroundA + deltaA * c;
}
{
const c = x2CharData[sourceOffset + 1] / 255;
dest[destOffset + 4] = backgroundR + deltaR * c;
dest[destOffset + 5] = backgroundG + deltaG * c;
dest[destOffset + 6] = backgroundB + deltaB * c;
dest[destOffset + 7] = backgroundA + deltaA * c;
}

destOffset += outWidth;
Expand All @@ -162,12 +166,14 @@ export class MinimapCharRenderer {
dest[destOffset + 0] = backgroundR + deltaR * c;
dest[destOffset + 1] = backgroundG + deltaG * c;
dest[destOffset + 2] = backgroundB + deltaB * c;
dest[destOffset + 3] = backgroundA + deltaA * c;
}
{
const c = x2CharData[sourceOffset + 3] / 255;
dest[destOffset + 4] = backgroundR + deltaR * c;
dest[destOffset + 5] = backgroundG + deltaG * c;
dest[destOffset + 6] = backgroundB + deltaB * c;
dest[destOffset + 7] = backgroundA + deltaA * c;
}

destOffset += outWidth;
Expand All @@ -176,12 +182,14 @@ export class MinimapCharRenderer {
dest[destOffset + 0] = backgroundR + deltaR * c;
dest[destOffset + 1] = backgroundG + deltaG * c;
dest[destOffset + 2] = backgroundB + deltaB * c;
dest[destOffset + 3] = backgroundA + deltaA * c;
}
{
const c = x2CharData[sourceOffset + 5] / 255;
dest[destOffset + 4] = backgroundR + deltaR * c;
dest[destOffset + 5] = backgroundG + deltaG * c;
dest[destOffset + 6] = backgroundB + deltaB * c;
dest[destOffset + 7] = backgroundA + deltaA * c;
}

destOffset += outWidth;
Expand All @@ -190,12 +198,14 @@ export class MinimapCharRenderer {
dest[destOffset + 0] = backgroundR + deltaR * c;
dest[destOffset + 1] = backgroundG + deltaG * c;
dest[destOffset + 2] = backgroundB + deltaB * c;
dest[destOffset + 3] = backgroundA + deltaA * c;
}
{
const c = x2CharData[sourceOffset + 7] / 255;
dest[destOffset + 4] = backgroundR + deltaR * c;
dest[destOffset + 5] = backgroundG + deltaG * c;
dest[destOffset + 6] = backgroundB + deltaB * c;
dest[destOffset + 7] = backgroundA + deltaA * c;
}
}

Expand All @@ -212,10 +222,12 @@ export class MinimapCharRenderer {
const backgroundR = backgroundColor.r;
const backgroundG = backgroundColor.g;
const backgroundB = backgroundColor.b;
const backgroundA = backgroundColor.a;

const deltaR = color.r - backgroundR;
const deltaG = color.g - backgroundG;
const deltaB = color.b - backgroundB;
const deltaA = color.a - backgroundA;

const dest = target.data;
const sourceOffset = chIndex * Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH;
Expand All @@ -225,6 +237,7 @@ export class MinimapCharRenderer {
dest[destOffset + 0] = backgroundR + deltaR * c;
dest[destOffset + 1] = backgroundG + deltaG * c;
dest[destOffset + 2] = backgroundB + deltaB * c;
dest[destOffset + 3] = backgroundA + deltaA * c;
}

destOffset += outWidth;
Expand All @@ -233,6 +246,7 @@ export class MinimapCharRenderer {
dest[destOffset + 0] = backgroundR + deltaR * c;
dest[destOffset + 1] = backgroundG + deltaG * c;
dest[destOffset + 2] = backgroundB + deltaB * c;
dest[destOffset + 3] = backgroundA + deltaA * c;
}
}

Expand All @@ -249,62 +263,73 @@ export class MinimapCharRenderer {
const backgroundR = backgroundColor.r;
const backgroundG = backgroundColor.g;
const backgroundB = backgroundColor.b;
const backgroundA = backgroundColor.a;

const deltaR = color.r - backgroundR;
const deltaG = color.g - backgroundG;
const deltaB = color.b - backgroundB;
const deltaA = color.a - backgroundA;

const colorR = backgroundR + deltaR * c;
const colorG = backgroundG + deltaG * c;
const colorB = backgroundB + deltaB * c;
const colorA = backgroundA + deltaA * c;

const dest = target.data;
let destOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT;
{
dest[destOffset + 0] = colorR;
dest[destOffset + 1] = colorG;
dest[destOffset + 2] = colorB;
dest[destOffset + 3] = colorA;
}
{
dest[destOffset + 4] = colorR;
dest[destOffset + 5] = colorG;
dest[destOffset + 6] = colorB;
dest[destOffset + 7] = colorA;
}

destOffset += outWidth;
{
dest[destOffset + 0] = colorR;
dest[destOffset + 1] = colorG;
dest[destOffset + 2] = colorB;
dest[destOffset + 3] = colorA;
}
{
dest[destOffset + 4] = colorR;
dest[destOffset + 5] = colorG;
dest[destOffset + 6] = colorB;
dest[destOffset + 7] = colorA;
}

destOffset += outWidth;
{
dest[destOffset + 0] = colorR;
dest[destOffset + 1] = colorG;
dest[destOffset + 2] = colorB;
dest[destOffset + 3] = colorA;
}
{
dest[destOffset + 4] = colorR;
dest[destOffset + 5] = colorG;
dest[destOffset + 6] = colorB;
dest[destOffset + 7] = colorA;
}

destOffset += outWidth;
{
dest[destOffset + 0] = colorR;
dest[destOffset + 1] = colorG;
dest[destOffset + 2] = colorB;
dest[destOffset + 3] = colorA;
}
{
dest[destOffset + 4] = colorR;
dest[destOffset + 5] = colorG;
dest[destOffset + 6] = colorB;
dest[destOffset + 7] = colorA;
}
}

Expand All @@ -321,14 +346,17 @@ export class MinimapCharRenderer {
const backgroundR = backgroundColor.r;
const backgroundG = backgroundColor.g;
const backgroundB = backgroundColor.b;
const backgroundA = backgroundColor.a;

const deltaR = color.r - backgroundR;
const deltaG = color.g - backgroundG;
const deltaB = color.b - backgroundB;
const deltaA = color.a - backgroundA;

const colorR = backgroundR + deltaR * c;
const colorG = backgroundG + deltaG * c;
const colorB = backgroundB + deltaB * c;
const colorA = backgroundA + deltaA * c;

const dest = target.data;

Expand All @@ -337,13 +365,15 @@ export class MinimapCharRenderer {
dest[destOffset + 0] = colorR;
dest[destOffset + 1] = colorG;
dest[destOffset + 2] = colorB;
dest[destOffset + 3] = colorA;
}

destOffset += outWidth;
{
dest[destOffset + 0] = colorR;
dest[destOffset + 1] = colorG;
dest[destOffset + 2] = colorB;
dest[destOffset + 3] = colorA;
}
}
}
Loading