Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -11,7 +11,7 @@ import { stopProfiling } from 'vs/base/node/profiler';
import nls = require('vs/nls');
import URI from 'vs/base/common/uri';
import { IStorageService } from 'vs/platform/storage/node/storage';
import { shell, screen, BrowserWindow, systemPreferences, app } from 'electron';
import { shell, screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage } from 'electron';
import { TPromise, TValueCallback } from 'vs/base/common/winjs.base';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { ILogService } from 'vs/platform/log/common/log';
@@ -19,13 +19,13 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { parseArgs } from 'vs/platform/environment/node/argv';
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState } from 'vs/platform/windows/common/windows';
import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { KeyboardLayoutMonitor } from 'vs/code/electron-main/keyboard';
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces';
import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { ICommandAction } from 'vs/platform/actions/common/actions';
export interface IWindowState {
width?: number;
@@ -65,11 +65,19 @@ interface IWorkbenchEditorConfiguration {
};
}
interface ITouchBarSegment extends Electron.SegmentedControlSegment {
id: string;
}
export class CodeWindow implements ICodeWindow {
public static themeStorageKey = 'theme';
public static themeBackgroundStorageKey = 'themeBackground';
private static DEFAULT_BG_LIGHT = '#FFFFFF';
private static DEFAULT_BG_DARK = '#1E1E1E';
private static DEFAULT_BG_HC_BLACK = '#000000';
private static MIN_WIDTH = 200;
private static MIN_HEIGHT = 120;
@@ -89,6 +97,8 @@ export class CodeWindow implements ICodeWindow {
private currentConfig: IWindowConfiguration;
private pendingLoadConfig: IWindowConfiguration;
private touchBarGroups: Electron.TouchBarSegmentedControl[];
constructor(
config: IWindowCreationOptions,
@ILogService private logService: ILogService,
@@ -98,6 +108,7 @@ export class CodeWindow implements ICodeWindow {
@IWorkspacesMainService private workspaceService: IWorkspacesMainService,
@IBackupMainService private backupService: IBackupMainService
) {
this.touchBarGroups = [];
this._lastFocusTime = -1;
this._readyState = ReadyState.NONE;
this.whenReadyCallbacks = [];
@@ -109,6 +120,9 @@ export class CodeWindow implements ICodeWindow {
// respect configured menu bar visibility
this.onConfigurationUpdated();
// macOS: touch bar support
this.createTouchBar();
// Eventing
this.registerListeners();
}
@@ -121,12 +135,17 @@ export class CodeWindow implements ICodeWindow {
// 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.BrowserWindowOptions = {
let backgroundColor = this.getBackgroundColor();
if (isMacintosh && backgroundColor.toUpperCase() === CodeWindow.DEFAULT_BG_DARK) {
backgroundColor = '#171717'; // https://github.com/electron/electron/issues/5150
}
const options: Electron.BrowserWindowConstructorOptions = {
width: this.windowState.width,
height: this.windowState.height,
x: this.windowState.x,
y: this.windowState.y,
backgroundColor: this.getBackgroundColor(),
backgroundColor,
minWidth: CodeWindow.MIN_WIDTH,
minHeight: CodeWindow.MIN_HEIGHT,
show: !isFullscreenOrMaximized,
@@ -150,17 +169,12 @@ export class CodeWindow implements ICodeWindow {
}
let useCustomTitleStyle = false;
// {{SQL CARBON EDIT}}
// turn-off custom menus to avoid bug calculating size of SQL editor
/*
if (isMacintosh && (!windowConfig || !windowConfig.titleBarStyle || windowConfig.titleBarStyle === 'custom')) {
const isDev = !this.environmentService.isBuilt || !!config.extensionDevelopmentPath;
if (!isDev) {
useCustomTitleStyle = true; // not enabled when developing due to https://github.com/electron/electron/issues/3647
}
}
*/
if (useNativeTabs) {
useCustomTitleStyle = false; // native tabs on sierra do not work with custom title style
@@ -175,6 +189,23 @@ export class CodeWindow implements ICodeWindow {
this._win = new BrowserWindow(options);
this._id = this._win.id;
// TODO@Ben Bug in Electron (https://github.com/electron/electron/issues/10862). On multi-monitor setups,
// it can happen that the position we set to the window is not the correct one on the display.
// To workaround, we ask the window for its position and set it again if not matching.
// This only applies if the window is not fullscreen or maximized and multiple monitors are used.
if (isWindows && !isFullscreenOrMaximized) {
try {
if (screen.getAllDisplays().length > 1) {
const [x, y] = this._win.getPosition();
if (x !== this.windowState.x || y !== this.windowState.y) {
this._win.setPosition(this.windowState.x, this.windowState.y, false);
}
}
} catch (err) {
this.logService.log(`Unexpected error fixing window position on windows with multiple windows: ${err}\n${err.stack}`);
}
}
if (useCustomTitleStyle) {
this._win.setSheetOffset(22); // offset dialogs by the height of the custom title bar if we have any
}
@@ -275,10 +306,6 @@ export class CodeWindow implements ICodeWindow {
return this.currentConfig ? this.currentConfig.folderPath : void 0;
}
public get openedFilePath(): string {
return this.currentConfig && this.currentConfig.filesToOpen && this.currentConfig.filesToOpen[0] && this.currentConfig.filesToOpen[0].filePath;
}
public setReady(): void {
this._readyState = ReadyState.READY;
@@ -316,7 +343,7 @@ export class CodeWindow implements ICodeWindow {
});
// Prevent loading of svgs
this._win.webContents.session.webRequest.onBeforeRequest((details, callback) => {
this._win.webContents.session.webRequest.onBeforeRequest(null, (details, callback) => {
if (details.url.indexOf('.svg') > 0) {
const uri = URI.parse(details.url);
if (uri && !uri.scheme.match(/file/i) && (uri.path as any).endsWith('.svg')) {
@@ -327,7 +354,7 @@ export class CodeWindow implements ICodeWindow {
return callback({});
});
this._win.webContents.session.webRequest.onHeadersReceived((details, callback) => {
this._win.webContents.session.webRequest.onHeadersReceived(null, (details, callback) => {
const contentType: string[] = (details.responseHeaders['content-type'] || details.responseHeaders['Content-Type']) as any;
if (contentType && Array.isArray(contentType) && contentType.some(x => x.toLowerCase().indexOf('image/svg') >= 0)) {
return callback({ cancel: true });
@@ -384,7 +411,7 @@ export class CodeWindow implements ICodeWindow {
});
// Window Failed to load
this._win.webContents.on('did-fail-load', (event: Event, errorCode: string, errorDescription: string) => {
this._win.webContents.on('did-fail-load', (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
this.logService.warn('[electron event]: fail to load, ', errorDescription);
});
@@ -399,7 +426,7 @@ export class CodeWindow implements ICodeWindow {
}
// Handle configuration changes
this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated()));
this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated()));
// Handle Workspace events
this.toDispose.push(this.workspaceService.onUntitledWorkspaceDeleted(e => this.onUntitledWorkspaceDeleted(e)));
@@ -433,15 +460,15 @@ export class CodeWindow implements ICodeWindow {
};
private registerNavigationListenerOn(command: 'swipe' | 'app-command', back: 'left' | 'browser-backward', forward: 'right' | 'browser-forward', acrossEditors: boolean) {
this._win.on(command, (e, cmd) => {
this._win.on(command as 'swipe' /* | 'app-command' */, (e: Electron.Event, cmd: string) => {
if (this.readyState !== ReadyState.READY) {
return; // window must be ready
}
if (cmd === back) {
this.send('vscode:runAction', acrossEditors ? 'workbench.action.openPreviousRecentlyUsedEditor' : 'workbench.action.navigateBack');
this.send('vscode:runAction', { id: acrossEditors ? 'workbench.action.openPreviousRecentlyUsedEditor' : 'workbench.action.navigateBack', from: 'mouse' } as IRunActionInWindowRequest);
} else if (cmd === forward) {
this.send('vscode:runAction', acrossEditors ? 'workbench.action.openNextRecentlyUsedEditor' : 'workbench.action.navigateForward');
this.send('vscode:runAction', { id: acrossEditors ? 'workbench.action.openNextRecentlyUsedEditor' : 'workbench.action.navigateForward', from: 'mouse' } as IRunActionInWindowRequest);
}
});
}
@@ -512,6 +539,7 @@ export class CodeWindow implements ICodeWindow {
delete configuration.filesToOpen;
delete configuration.filesToCreate;
delete configuration.filesToDiff;
delete configuration.filesToWait;
// Some configuration things get inherited if the window is being reloaded and we are
// in extension development mode. These options are all development related.
@@ -545,9 +573,6 @@ export class CodeWindow implements ICodeWindow {
windowConfiguration.highContrast = isWindows && systemPreferences.isInvertedColorScheme() && (!windowConfig || windowConfig.autoDetectHighContrast);
windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled();
// Set Keyboard Config
windowConfiguration.isISOKeyboard = KeyboardLayoutMonitor.INSTANCE.isISOKeyboard();
// Theme
windowConfiguration.baseTheme = this.getBaseTheme();
windowConfiguration.backgroundColor = this.getBackgroundColor();
@@ -581,14 +606,14 @@ export class CodeWindow implements ICodeWindow {
private getBackgroundColor(): string {
if (isWindows && systemPreferences.isInvertedColorScheme()) {
return '#000000';
return CodeWindow.DEFAULT_BG_HC_BLACK;
}
const background = this.storageService.getItem<string>(CodeWindow.themeBackgroundStorageKey, null);
if (!background) {
const baseTheme = this.getBaseTheme();
return baseTheme === 'hc-black' ? '#000000' : (baseTheme === 'vs' ? '#FFFFFF' : (isMacintosh ? '#171717' : '#1E1E1E')); // https://github.com/electron/electron/issues/5150
return baseTheme === 'hc-black' ? CodeWindow.DEFAULT_BG_HC_BLACK : (baseTheme === 'vs' ? CodeWindow.DEFAULT_BG_LIGHT : CodeWindow.DEFAULT_BG_DARK);
}
return background;
@@ -726,7 +751,13 @@ export class CodeWindow implements ICodeWindow {
// Multi Monitor (non-fullscreen): be less strict because metrics can be crazy
const bounds = { x: state.x, y: state.y, width: state.width, height: state.height };
const display = screen.getDisplayMatching(bounds);
if (display && display.bounds.x + display.bounds.width > bounds.x && display.bounds.y + display.bounds.height > bounds.y) {
if (
display && // we have a display matching the desired bounds
bounds.x < display.bounds.x + display.bounds.width && // prevent window from falling out of the screen to the right
bounds.y < display.bounds.y + display.bounds.height && // prevent window from falling out of the screen to the bottom
bounds.x + bounds.width > display.bounds.x && // prevent window from falling out of the screen to the left
bounds.y + bounds.height > display.bounds.y // prevent window from falling out of the scree nto the top
) {
if (state.mode === WindowMode.Maximized) {
const defaults = defaultWindowState(WindowMode.Maximized); // when maximized, make sure we have good values when the user restores the window
defaults.x = state.x; // carefull to keep x/y position so that the window ends up on the correct monitor
@@ -856,6 +887,78 @@ export class CodeWindow implements ICodeWindow {
this._win.webContents.send(channel, ...args);
}
public updateTouchBar(groups: ICommandAction[][]): void {
if (!isMacintosh) {
return; // only supported on macOS
}
// Update segments for all groups. Setting the segments property
// of the group directly prevents ugly flickering from happening
this.touchBarGroups.forEach((touchBarGroup, index) => {
const commands = groups[index];
touchBarGroup.segments = this.createTouchBarGroupSegments(commands);
});
}
private createTouchBar(): void {
if (!isMacintosh) {
return; // only supported on macOS
}
// To avoid flickering, we try to reuse the touch bar group
// as much as possible by creating a large number of groups
// for reusing later.
for (let i = 0; i < 10; i++) {
const groupTouchBar = this.createTouchBarGroup();
this.touchBarGroups.push(groupTouchBar);
}
// Ugly workaround for native crash on macOS 10.12.1. We are not
// leveraging the API for changing the ESC touch bar item.
// See https://github.com/electron/electron/issues/10442
(<any>this._win)._setEscapeTouchBarItem = () => { };
this._win.setTouchBar(new TouchBar({ items: this.touchBarGroups }));
}
private createTouchBarGroup(items: ICommandAction[] = []): Electron.TouchBarSegmentedControl {
// Group Segments
const segments = this.createTouchBarGroupSegments(items);
// Group Control
const control = new TouchBar.TouchBarSegmentedControl({
segments,
mode: 'buttons',
segmentStyle: 'automatic',
change: (selectedIndex) => {
this.sendWhenReady('vscode:runAction', { id: (control.segments[selectedIndex] as ITouchBarSegment).id, from: 'touchbar' });
}
});
return control;
}
private createTouchBarGroupSegments(items: ICommandAction[] = []): ITouchBarSegment[] {
const segments: ITouchBarSegment[] = items.map(item => {
let icon: Electron.NativeImage;
if (item.iconPath) {
icon = nativeImage.createFromPath(item.iconPath);
if (icon.isEmpty()) {
icon = void 0;
}
}
return {
id: item.id,
label: !icon ? item.title as string : void 0,
icon
};
});
return segments;
}
public dispose(): void {
if (this.showTimeoutHandle) {
clearTimeout(this.showTimeoutHandle);