diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 1ece3c7b2926754c3cbd96ab537ef27e9524b9b8..7f4f3612fc64738565ab9aae3adb590738268bda 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -14,6 +14,7 @@ import { Extensions, IColorRegistry, ColorIdentifier } from 'vs/platform/theme/c import { Extensions as ThemingExtensions, IThemingRegistry, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { Registry } from 'vs/platform/registry/common/platform'; import { Event, Emitter } from 'vs/base/common/event'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; const VS_THEME_NAME = 'vs'; const VS_DARK_THEME_NAME = 'vs-dark'; @@ -119,7 +120,7 @@ export class StandaloneThemeServiceImpl implements IStandaloneThemeService { private _styleElement: HTMLStyleElement; private _theme: IStandaloneTheme; private readonly _onThemeChange: Emitter; - + private environment: IEnvironmentService = Object.create(null); constructor() { this._onThemeChange = new Emitter(); @@ -185,7 +186,7 @@ export class StandaloneThemeServiceImpl implements IStandaloneThemeService { } } }; - themingRegistry.getThemingParticipants().forEach(p => p(theme, ruleCollector)); + themingRegistry.getThemingParticipants().forEach(p => p(theme, ruleCollector, this.environment)); let tokenTheme = theme.tokenTheme; let colorMap = tokenTheme.getColorMap(); diff --git a/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts index 6c0181bc7d42cd372cfe2209131967eb11a4bb73..c58b79603bc10abfec67de63fbf273a46d158614 100644 --- a/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -10,6 +10,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/platform/registry/common/platform'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { Event, Emitter } from 'vs/base/common/event'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; export const IThemeService = createDecorator('themeService'); @@ -66,7 +67,7 @@ export interface ICssStyleCollector { } export interface IThemingParticipant { - (theme: ITheme, collector: ICssStyleCollector): void; + (theme: ITheme, collector: ICssStyleCollector, environment: IEnvironmentService): void; } export interface IThemeService { diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 45a3201135d1e4424460faa3a8320455846d9b33..626dbc2eb4854031c97cc7b9434ee3d0bd1b934e 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -78,18 +78,6 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService //#endregion - //#region TODO@grid watermark (do this from the outside? what about background color for empt root view?) - - private initStyles(): void { - - // Letterpress Background when Empty - createCSSRule('.vs .monaco-workbench > .part.editor.empty', `background-image: url('${join(this.environmentService.appRoot, 'resources/letterpress.svg')}')`); - createCSSRule('.vs-dark .monaco-workbench > .part.editor.empty', `background-image: url('${join(this.environmentService.appRoot, 'resources/letterpress-dark.svg')}')`); - createCSSRule('.hc-black .monaco-workbench > .part.editor.empty', `background-image: url('${join(this.environmentService.appRoot, 'resources/letterpress-hc.svg')}')`); - } - - //#endregion - //#region TODO@grid closeEditors() public closeEditors(positions?: Position[]): TPromise; @@ -750,6 +738,14 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.registerListeners(); } + private initStyles(): void { + + // Letterpress Background when Empty + createCSSRule('.vs .monaco-workbench > .part.editor.empty', `background-image: url('${join(this.environmentService.appRoot, 'resources/letterpress.svg')}')`); + createCSSRule('.vs-dark .monaco-workbench > .part.editor.empty', `background-image: url('${join(this.environmentService.appRoot, 'resources/letterpress-dark.svg')}')`); + createCSSRule('.hc-black .monaco-workbench > .part.editor.empty', `background-image: url('${join(this.environmentService.appRoot, 'resources/letterpress-hc.svg')}')`); + } + public hideTabs(forceHide: boolean): void { this.forceHideTabs = forceHide; const config = this.configurationService.getValue(); diff --git a/src/vs/workbench/browser/parts/editor2/media/nextEditorGroupView.css b/src/vs/workbench/browser/parts/editor2/media/nextEditorGroupView.css index 882bba763562faa28de41852782e0679296563e1..eab4dbed83b31ee5fa9bbbbec23d69a057eedd03 100644 --- a/src/vs/workbench/browser/parts/editor2/media/nextEditorGroupView.css +++ b/src/vs/workbench/browser/parts/editor2/media/nextEditorGroupView.css @@ -7,6 +7,16 @@ height: 100%; } +.monaco-workbench > .part.editor > .content .editor-group-container.empty { + background-repeat: no-repeat; + background-position: 50% 50%; + background-size: 15%; +} + +.monaco-workbench > .part.editor > .content.empty .editor-group-container.empty { + background-size: 260px 260px; /* larger for empty editor part */ +} + .monaco-workbench > .part.editor > .content .editor-group-container.empty.active { outline-width: 1px; outline-style: solid; diff --git a/src/vs/workbench/browser/parts/editor2/media/nextEditorpart.css b/src/vs/workbench/browser/parts/editor2/media/nextEditorpart.css deleted file mode 100644 index 1dc4c7da0b71949e1de803a9d12285bdbfdff564..0000000000000000000000000000000000000000 --- a/src/vs/workbench/browser/parts/editor2/media/nextEditorpart.css +++ /dev/null @@ -1,11 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* Letter press styling for empty editor */ -.monaco-workbench > .part.editor.empty { - background-repeat: no-repeat; - background-position: 50% 50%; - background-size: 260px 260px; -} diff --git a/src/vs/workbench/browser/parts/editor2/nextEditorActions.ts b/src/vs/workbench/browser/parts/editor2/nextEditorActions.ts index 28d02609fd553fb5c083440957226e6411363c56..0c7975beada134aa74141f1746bc0888aa5fcc01 100644 --- a/src/vs/workbench/browser/parts/editor2/nextEditorActions.ts +++ b/src/vs/workbench/browser/parts/editor2/nextEditorActions.ts @@ -88,7 +88,7 @@ export class GridOpenOneEditorAction extends Action { } run(): TPromise { - const path = join(process.cwd(), 'src/vs/workbench/browser/parts/editor2/editor2.contribution.ts'); + const path = join(process.cwd(), 'src/vs/workbench/browser/parts/editor/editor.contribution.ts'); this.nextEditorGroupsService.activeGroup.openEditor(this.legacyEditorService.createInput({ resource: URI.file(path) }) as EditorInput); return TPromise.as(void 0); diff --git a/src/vs/workbench/browser/parts/editor2/nextEditorGroupView.ts b/src/vs/workbench/browser/parts/editor2/nextEditorGroupView.ts index 38827fd4985ea82e4a5775707385bba43ea50dab..fba92e04cf90f5224eacb07ff5db8451dcfd1edf 100644 --- a/src/vs/workbench/browser/parts/editor2/nextEditorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor2/nextEditorGroupView.ts @@ -16,9 +16,9 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { attachProgressBarStyler } from 'vs/platform/theme/common/styler'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorBackground, contrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; -import { Themable, EDITOR_GROUP_HEADER_TABS_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND } from 'vs/workbench/common/theme'; +import { Themable, EDITOR_GROUP_HEADER_TABS_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND } from 'vs/workbench/common/theme'; import { IMoveEditorOptions } from 'vs/workbench/services/editor/common/nextEditorGroupsService'; import { NextTabsTitleControl } from 'vs/workbench/browser/parts/editor2/nextTabsTitleControl'; import { NextEditorControl } from 'vs/workbench/browser/parts/editor2/nextEditorControl'; @@ -38,6 +38,8 @@ import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch import { NextTitleControl } from 'vs/workbench/browser/parts/editor2/nextTitleControl'; import { INextEditorGroupsAccessor, INextEditorGroupView, INextEditorPartOptionsChangeEvent } from 'vs/workbench/browser/parts/editor2/editor2'; import { NextNoTabsTitleControl } from './nextNoTabsTitleControl'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { join } from 'vs/base/common/paths'; export class NextEditorGroupView extends Themable implements INextEditorGroupView { @@ -106,7 +108,8 @@ export class NextEditorGroupView extends Themable implements INextEditorGroupVie @IThemeService themeService: IThemeService, @IPartService private partService: IPartService, @INotificationService private notificationService: INotificationService, - @ITelemetryService private telemetryService: ITelemetryService + @ITelemetryService private telemetryService: ITelemetryService, + @IUntitledEditorService private untitledEditorService: IUntitledEditorService ) { super(themeService); @@ -284,6 +287,15 @@ export class NextEditorGroupView extends Themable implements INextEditorGroupVie // Container addClasses(this.element, 'editor-group-container'); + // Open new file via doubleclick on container + this._register(addDisposableListener(this.element, EventType.DBLCLICK, e => { + if (e.target === this.element) { + EventHelper.stop(e); + + this.openEditor(this.untitledEditorService.createOrGet(), EditorOptions.create({ pinned: true })); + } + })); + // Title container this.titleContainer = document.createElement('div'); addClass(this.titleContainer, 'title'); @@ -803,7 +815,6 @@ export class NextEditorGroupView extends Themable implements INextEditorGroupVie protected updateStyles(): void { // Container - this.element.style.backgroundColor = this.getColor(EDITOR_GROUP_BACKGROUND); this.element.style.outlineColor = this.getColor(focusBorder); // Title control @@ -868,4 +879,15 @@ export class NextEditorGroupView extends Themable implements INextEditorGroupVie super.dispose(); } -} \ No newline at end of file +} + +registerThemingParticipant((theme, collector, environment) => { + + // Letterpress + const letterpress = `resources/letterpress${theme.type === 'dark' ? '-dark' : theme.type === 'hc' ? '-hc' : ''}.svg`; + collector.addRule(` + .monaco-workbench > .part.editor > .content .editor-group-container.empty { + background-image: url('${join(environment.appRoot, letterpress)}') + } + `); +}); \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor2/nextEditorPart.ts b/src/vs/workbench/browser/parts/editor2/nextEditorPart.ts index ae6541114b8e9060827c9026c6e89aa714846fc0..61c4123c2a1009a4e96241d319532904f3b57409 100644 --- a/src/vs/workbench/browser/parts/editor2/nextEditorPart.ts +++ b/src/vs/workbench/browser/parts/editor2/nextEditorPart.ts @@ -5,25 +5,24 @@ 'use strict'; -import 'vs/css!./media/nextEditorpart'; import 'vs/workbench/browser/parts/editor/editor.contribution'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { Part } from 'vs/workbench/browser/part'; -import { Dimension, addClass, isAncestor } from 'vs/base/browser/dom'; +import { Dimension, isAncestor, toggleClass, addClass } from 'vs/base/browser/dom'; import { Event, Emitter, once } from 'vs/base/common/event'; -import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { INextEditorGroupsService, Direction, CopyKind } from 'vs/workbench/services/editor/common/nextEditorGroupsService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Grid, Direction as GridViewDirection } from 'vs/base/browser/ui/grid/grid'; import { GroupIdentifier, EditorOptions, TextEditorOptions, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; import { values } from 'vs/base/common/map'; -import { EDITOR_GROUP_BORDER, EDITOR_GROUP_BACKGROUND } from 'vs/workbench/common/theme'; +import { EDITOR_GROUP_BORDER } from 'vs/workbench/common/theme'; import { distinct } from 'vs/base/common/arrays'; import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService'; import { INextEditorGroupsAccessor, INextEditorGroupView, INextEditorPartOptions, getEditorPartOptions, impactsEditorPartOptions, INextEditorPartOptionsChangeEvent } from 'vs/workbench/browser/parts/editor2/editor2'; import { NextEditorGroupView } from 'vs/workbench/browser/parts/editor2/nextEditorGroupView'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; // TODO@grid provide DND support of groups/editors: @@ -192,6 +191,9 @@ export class NextEditorPart extends Part implements INextEditorGroupsService, IN newGroupView.openEditor(activeEditor, options); } + // Update container + this.updateContainer(); + return newGroupView; } @@ -222,6 +224,9 @@ export class NextEditorPart extends Part implements INextEditorGroupsService, IN // Remove from grid widget & dispose this.gridWidget.removeView(groupView); groupView.dispose(); + + // Update container + this.updateContainer(); } private toGridViewDirection(direction: Direction): GridViewDirection { @@ -253,6 +258,13 @@ export class NextEditorPart extends Part implements INextEditorGroupsService, IN // Set group active this.doSetGroupActive(initialGroup); + + // Update container + this.updateContainer(); + } + + private updateContainer(): void { + toggleClass(this.gridContainer, 'empty', this.groupViews.size === 1 && this.activeGroup.isEmpty()); } private doSetGroupActive(group: INextEditorGroupView): void { @@ -308,13 +320,19 @@ export class NextEditorPart extends Part implements INextEditorGroupsService, IN this.groupViews.set(groupView.id, groupView); // Track focus - const focusListener = groupView.onDidFocus(() => { + let groupDisposables: IDisposable[] = []; + groupDisposables.push(groupView.onDidFocus(() => { this.doSetGroupActive(groupView); - }); + })); + + // Track editor change + groupDisposables.push(groupView.onDidActiveEditorChange(() => { + this.updateContainer(); + })); // Track dispose once(groupView.onWillDispose)(() => { - focusListener.dispose(); + groupDisposables = dispose(groupDisposables); this.groupViews.delete(groupView.id); this.doUpdateMostRecentActive(groupView); }); @@ -335,7 +353,7 @@ export class NextEditorPart extends Part implements INextEditorGroupsService, IN // Part container const container = this.getContainer(); - container.style.backgroundColor = this.getColor(EDITOR_GROUP_BACKGROUND); + container.style.backgroundColor = this.getColor(editorBackground); } createContentArea(parent: HTMLElement): HTMLElement { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index f8f07debb37ceaea4e233701e96191265e95012e..fadaaa3d1249e50e0baa3ed9513b85c2439e4d8f 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -9,11 +9,11 @@ import 'vs/css!./media/workbench'; import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as DOM from 'vs/base/browser/dom'; import { Builder, $ } from 'vs/base/browser/builder'; -import { Delayer, RunOnceScheduler } from 'vs/base/common/async'; +import { RunOnceScheduler } from 'vs/base/common/async'; import * as browser from 'vs/base/browser/browser'; import * as perf from 'vs/base/common/performance'; import * as errors from 'vs/base/common/errors'; @@ -94,7 +94,6 @@ import { IDecorationsService } from 'vs/workbench/services/decorations/browser/d import { ActivityService } from 'vs/workbench/services/activity/browser/activityService'; import URI from 'vs/base/common/uri'; import { IListService, ListService } from 'vs/platform/list/browser/listService'; -import { domEvent } from 'vs/base/browser/event'; import { InputFocusedContext } from 'vs/platform/workbench/common/contextkeys'; import { IViewsService } from 'vs/workbench/common/views'; import { CustomViewsService } from 'vs/workbench/browser/parts/views/customView'; @@ -163,10 +162,16 @@ function getWorkbenchStateString(state: WorkbenchState): string { } } -/** - * The workbench creates and lays out all parts that make up the workbench. - */ -export class Workbench implements IPartService { +interface IZenMode { + active: boolean; + transitionedToFullScreen: boolean; + transitionedToCenteredEditorLayout: boolean; + transitionDisposeables: IDisposable[]; + wasSideBarVisible: boolean; + wasPanelVisible: boolean; +} + +export class Workbench extends Disposable implements IPartService { private static readonly sidebarHiddenStorageKey = 'workbench.sidebar.hidden'; private static readonly sidebarRestoreStorageKey = 'workbench.sidebar.restore'; @@ -181,24 +186,27 @@ export class Workbench implements IPartService { private static readonly closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty'; private static readonly fontAliasingConfigurationKey = 'workbench.fontAliasing'; - public _serviceBrand: any; + _serviceBrand: any; - private parent: HTMLElement; - private container: HTMLElement; private workbenchParams: WorkbenchParams; private workbenchContainer: Builder; private workbench: Builder; private workbenchStarted: boolean; private workbenchCreated: boolean; + private workbenchShutdown: boolean; + private legacyEditorService: IWorkbenchEditorService; private legacyEditorGroupService: IEditorGroupService; private nextEditorService: INextEditorService; - private workbenchShutdown: boolean; private viewletService: IViewletService; private contextKeyService: IContextKeyService; private keybindingService: IKeybindingService; private backupFileService: IBackupFileService; private fileService: IFileService; + private quickInput: QuickInputService; + + private workbenchLayout: WorkbenchLayout; + private titlebarPart: TitlebarPart; private activitybarPart: ActivitybarPart; private sidebarPart: SidebarPart; @@ -207,39 +215,35 @@ export class Workbench implements IPartService { private editorPart: NextEditorPart; private statusbarPart: StatusbarPart; private quickOpen: QuickOpenController; - private quickInput: QuickInputService; private notificationsCenter: NotificationsCenter; private notificationsToasts: NotificationsToasts; - private workbenchLayout: WorkbenchLayout; - private toUnbind: IDisposable[]; + private sideBarHidden: boolean; private statusBarHidden: boolean; private activityBarHidden: boolean; private sideBarPosition: Position; private panelPosition: Position; private panelHidden: boolean; - private editorBackgroundDelayer: Delayer; - private closeEmptyWindowScheduler: RunOnceScheduler; + private zenMode: IZenMode; + private centeredEditorLayoutActive: boolean; + private fontAliasing: FontAliasingOption; + private hasFilesToCreateOpenOrDiff: boolean; + + private inZenMode: IContextKey; private editorsVisibleContext: IContextKey; - private _onTitleBarVisibilityChange: Emitter; private textCompareEditorVisible: IContextKey; - private inZenMode: IContextKey; private sideBarVisibleContext: IContextKey; - private hasFilesToCreateOpenOrDiff: boolean; - private fontAliasing: FontAliasingOption; - private centeredEditorLayoutActive: boolean; - private zenMode: { - active: boolean; - transitionedToFullScreen: boolean; - transitionedToCenteredEditorLayout: boolean; - transitionDisposeables: IDisposable[]; - wasSideBarVisible: boolean; - wasPanelVisible: boolean; - }; + + private closeEmptyWindowScheduler: RunOnceScheduler = new RunOnceScheduler(() => this.onAllEditorsClosed(), 50); + + private _onTitleBarVisibilityChange: Emitter = new Emitter(); + get onTitleBarVisibilityChange(): Event { return this._onTitleBarVisibilityChange.event; } + + get onEditorLayout(): Event { return this.editorPart.onDidLayout; } constructor( - parent: HTMLElement, - container: HTMLElement, + private parent: HTMLElement, + private container: HTMLElement, private configuration: IWindowConfiguration, serviceCollection: ServiceCollection, private lifecycleService: LifecycleService, @@ -252,8 +256,7 @@ export class Workbench implements IPartService { @IWindowService private windowService: IWindowService, @INotificationService private notificationService: NotificationService ) { - this.parent = parent; - this.container = container; + super(); this.workbenchParams = { configuration, @@ -264,28 +267,9 @@ export class Workbench implements IPartService { (configuration.filesToCreate && configuration.filesToCreate.length > 0) || (configuration.filesToOpen && configuration.filesToOpen.length > 0) || (configuration.filesToDiff && configuration.filesToDiff.length > 0); - - this.toUnbind = []; - - this.editorBackgroundDelayer = new Delayer(50); - this.closeEmptyWindowScheduler = new RunOnceScheduler(() => this.onAllEditorsClosed(), 50); - - this._onTitleBarVisibilityChange = new Emitter(); - } - - public get onTitleBarVisibilityChange(): Event { - return this._onTitleBarVisibilityChange.event; } - public get onEditorLayout(): Event { - return this.editorPart.onDidLayout; - } - - /** - * Starts the workbench and creates the HTML elements on the container. A workbench can only be started - * once. Use the shutdown function to free up resources created by the workbench on startup. - */ - public startup(): TPromise { + startup(): TPromise { this.workbenchStarted = true; // Create Workbench Container @@ -297,25 +281,8 @@ export class Workbench implements IPartService { // Services this.initServices(); - // Contexts - this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService); - this.textCompareEditorVisible = TextCompareEditorVisible.bindTo(this.contextKeyService); - this.inZenMode = InZenModeContext.bindTo(this.contextKeyService); - this.sideBarVisibleContext = SidebarVisibleContext.bindTo(this.contextKeyService); - - const inputFocused = InputFocusedContext.bindTo(this.contextKeyService); - const onWindowsFocusIn = domEvent(window, 'focusin', true); - onWindowsFocusIn(() => inputFocused.set(document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA')), null, this.toUnbind); - - // Set workbench state context - const WorkbenchStateContext = new RawContextKey('workbenchState', getWorkbenchStateString(this.configurationService.getWorkbenchState())); - const workbenchStateContext = WorkbenchStateContext.bindTo(this.contextKeyService); - - const WorkspaceFolderCountContext = new RawContextKey('workspaceFolderCount', this.configurationService.getWorkspace().folders.length); - const workspaceFolderCountContext = WorkspaceFolderCountContext.bindTo(this.contextKeyService); - - this.toUnbind.push(this.configurationService.onDidChangeWorkbenchState(() => workbenchStateContext.set(getWorkbenchStateString(this.configurationService.getWorkbenchState())))); - this.toUnbind.push(this.configurationService.onDidChangeWorkspaceFolders(() => workspaceFolderCountContext.set(this.configurationService.getWorkspace().folders.length))); + // Context Keys + this.handleContextKeys(); // Register Listeners this.registerListeners(); @@ -331,18 +298,52 @@ export class Workbench implements IPartService { // Driver if (this.environmentService.driverHandle) { - registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService) - .then(disposable => this.toUnbind.push(disposable)); + registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService).then(disposable => this._register(disposable)); } // Restore Parts return this.restoreParts(); } + private handleContextKeys(): void { + this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService); + this.textCompareEditorVisible = TextCompareEditorVisible.bindTo(this.contextKeyService); + this.inZenMode = InZenModeContext.bindTo(this.contextKeyService); + this.sideBarVisibleContext = SidebarVisibleContext.bindTo(this.contextKeyService); + + this._register(this.nextEditorService.onDidVisibleEditorsChange(() => { + const visibleEditors = this.nextEditorService.visibleControls; + this.textCompareEditorVisible.set(visibleEditors.some(e => e && e.isVisible() && e.getId() === TEXT_DIFF_EDITOR_ID)); + + if (visibleEditors.length === 0) { + this.editorsVisibleContext.reset(); + } else { + this.editorsVisibleContext.set(true); + } + })); + + const inputFocused = InputFocusedContext.bindTo(this.contextKeyService); + this._register(DOM.addDisposableListener(window, 'focusin', () => { + inputFocused.set(document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA')); + }, true)); + + const workbenchStateRawContext = new RawContextKey('workbenchState', getWorkbenchStateString(this.configurationService.getWorkbenchState())); + const workbenchStateContext = workbenchStateRawContext.bindTo(this.contextKeyService); + this._register(this.configurationService.onDidChangeWorkbenchState(() => { + workbenchStateContext.set(getWorkbenchStateString(this.configurationService.getWorkbenchState())); + })); + + const workspaceFolderCountRawContext = new RawContextKey('workspaceFolderCount', this.configurationService.getWorkspace().folders.length); + const workspaceFolderCountContext = workspaceFolderCountRawContext.bindTo(this.contextKeyService); + this._register(this.configurationService.onDidChangeWorkspaceFolders(() => { + workspaceFolderCountContext.set(this.configurationService.getWorkspace().folders.length); + })); + } + private registerListeners(): void { // Listen to visible editor changes - this.toUnbind.push(this.nextEditorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange())); + this._register(this.nextEditorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange())); // Listen to editor closing (if we run with --wait) const filesToWait = this.workbenchParams.configuration.filesToWait; @@ -351,14 +352,14 @@ export class Workbench implements IPartService { const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath); const listenerDispose = this.legacyEditorGroupService.getStacksModel().onEditorClosed(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile)); - this.toUnbind.push(listenerDispose); + this._register(listenerDispose); } // Configuration changes - this.toUnbind.push(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration())); + this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration())); // Fullscreen changes - this.toUnbind.push(browser.onDidChangeFullscreen(() => this.onFullscreenChanged())); + this._register(browser.onDidChangeFullscreen(() => this.onFullscreenChanged())); } private onFullscreenChanged(): void { @@ -409,24 +410,6 @@ export class Workbench implements IPartService { this.closeEmptyWindowScheduler.schedule(); } } - - // Update text compare editor context key - this.textCompareEditorVisible.set(visibleEditors.some(e => e && e.isVisible() && e.getId() === TEXT_DIFF_EDITOR_ID)); - - // We update the editorpart class to indicate if an editor is opened or not - // through a delay to accomodate for fast editor switching - this.handleEditorBackground(); - } - - private handleEditorBackground(): void { - const editorContainer = this.editorPart.getContainer(); - if (this.nextEditorService.visibleControls.length === 0) { - this.editorsVisibleContext.reset(); - this.editorBackgroundDelayer.trigger(() => DOM.addClass(editorContainer, 'empty')); // TODO@grid reenable - } else { - this.editorsVisibleContext.set(true); - this.editorBackgroundDelayer.trigger(() => DOM.removeClass(editorContainer, 'empty')); - } } private onAllEditorsClosed(): void { @@ -486,8 +469,6 @@ export class Workbench implements IPartService { } return editorOpenPromise.then(editors => { - this.handleEditorBackground(); // make sure we show the proper background in the editor area - perf.mark('didRestoreEditors'); for (const editor of editors) { @@ -681,7 +662,7 @@ export class Workbench implements IPartService { // Status bar this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART); - this.toUnbind.push(toDisposable(() => this.statusbarPart.shutdown())); + this._register(toDisposable(() => this.statusbarPart.shutdown())); serviceCollection.set(IStatusbarService, this.statusbarPart); // Progress 2 @@ -705,7 +686,7 @@ export class Workbench implements IPartService { // Sidebar part this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART); - this.toUnbind.push(toDisposable(() => this.sidebarPart.shutdown())); + this._register(toDisposable(() => this.sidebarPart.shutdown())); // Viewlet service this.viewletService = this.instantiationService.createInstance(ViewletService, this.sidebarPart); @@ -713,7 +694,7 @@ export class Workbench implements IPartService { // Panel service (panel part) this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART); - this.toUnbind.push(toDisposable(() => this.panelPart.shutdown())); + this._register(toDisposable(() => this.panelPart.shutdown())); serviceCollection.set(IPanelService, this.panelPart); // Custom views service @@ -722,7 +703,7 @@ export class Workbench implements IPartService { // Activity service (activitybar part) this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART); - this.toUnbind.push(toDisposable(() => this.activitybarPart.shutdown())); + this._register(toDisposable(() => this.activitybarPart.shutdown())); const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart); serviceCollection.set(IActivityService, activityService); @@ -733,7 +714,7 @@ export class Workbench implements IPartService { // Editor service (next editor part) this.editorPart = this.instantiationService.createInstance(NextEditorPart, Identifiers.EDITOR_PART /*, !this.hasFilesToCreateOpenOrDiff*/); - this.toUnbind.push(toDisposable(() => this.editorPart.shutdown())); + this._register(toDisposable(() => this.editorPart.shutdown())); serviceCollection.set(INextEditorGroupsService, this.editorPart); this.nextEditorService = this.instantiationService.createInstance(NextEditorService); serviceCollection.set(INextEditorService, this.nextEditorService); @@ -747,7 +728,7 @@ export class Workbench implements IPartService { // Title bar this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART); - this.toUnbind.push(toDisposable(() => this.titlebarPart.shutdown())); + this._register(toDisposable(() => this.titlebarPart.shutdown())); serviceCollection.set(ITitleService, this.titlebarPart); // History @@ -787,12 +768,12 @@ export class Workbench implements IPartService { // Quick open service (quick open controller) this.quickOpen = this.instantiationService.createInstance(QuickOpenController); - this.toUnbind.push(toDisposable(() => this.quickOpen.shutdown())); + this._register(toDisposable(() => this.quickOpen.shutdown())); serviceCollection.set(IQuickOpenService, this.quickOpen); // Quick input service this.quickInput = this.instantiationService.createInstance(QuickInputService); - this.toUnbind.push(toDisposable(() => this.quickInput.shutdown())); + this._register(toDisposable(() => this.quickInput.shutdown())); serviceCollection.set(IQuickInputService, this.quickInput); // PreferencesService @@ -867,18 +848,18 @@ export class Workbench implements IPartService { /** * Returns whether the workbench has been started. */ - public isStarted(): boolean { + isStarted(): boolean { return this.workbenchStarted && !this.workbenchShutdown; } /** * Returns whether the workbench has been fully created. */ - public isCreated(): boolean { + isCreated(): boolean { return this.workbenchCreated && this.workbenchStarted; } - public hasFocus(part: Parts): boolean { + hasFocus(part: Parts): boolean { const activeElement = document.activeElement; if (!activeElement) { return false; @@ -888,7 +869,7 @@ export class Workbench implements IPartService { return DOM.isAncestor(activeElement, container); } - public getContainer(part: Parts): HTMLElement { + getContainer(part: Parts): HTMLElement { let container: HTMLElement = null; switch (part) { case Parts.TITLEBAR_PART: @@ -914,7 +895,7 @@ export class Workbench implements IPartService { return container; } - public isVisible(part: Parts): boolean { + isVisible(part: Parts): boolean { switch (part) { case Parts.TITLEBAR_PART: return this.getCustomTitleBarStyle() && !browser.isFullscreen(); @@ -931,7 +912,7 @@ export class Workbench implements IPartService { return true; // any other part cannot be hidden } - public getTitleBarOffset(): number { + getTitleBarOffset(): number { let offset = 0; if (this.isVisible(Parts.TITLEBAR_PART)) { offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor @@ -982,7 +963,7 @@ export class Workbench implements IPartService { } } - public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void { + setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void { this.activityBarHidden = hidden; // Layout @@ -991,7 +972,7 @@ export class Workbench implements IPartService { } } - public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise { + setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise { this.sideBarHidden = hidden; this.sideBarVisibleContext.set(!hidden); @@ -1043,7 +1024,7 @@ export class Workbench implements IPartService { }); } - public setPanelHidden(hidden: boolean, skipLayout?: boolean): TPromise { + setPanelHidden(hidden: boolean, skipLayout?: boolean): TPromise { this.panelHidden = hidden; // Adjust CSS @@ -1090,19 +1071,19 @@ export class Workbench implements IPartService { }); } - public toggleMaximizedPanel(): void { + toggleMaximizedPanel(): void { this.workbenchLayout.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART }); } - public isPanelMaximized(): boolean { + isPanelMaximized(): boolean { return this.workbenchLayout.isPanelMaximized(); } - public getSideBarPosition(): Position { + getSideBarPosition(): Position { return this.sideBarPosition; } - public setSideBarPosition(position: Position): void { + setSideBarPosition(position: Position): void { if (this.sideBarHidden) { this.setSideBarHidden(false, true /* Skip Layout */).done(void 0, errors.onUnexpectedError); } @@ -1125,11 +1106,11 @@ export class Workbench implements IPartService { this.workbenchLayout.layout(); } - public getPanelPosition(): Position { + getPanelPosition(): Position { return this.panelPosition; } - public setPanelPosition(position: Position): TPromise { + setPanelPosition(position: Position): TPromise { return (this.panelHidden ? this.setPanelHidden(false, true /* Skip Layout */) : TPromise.as(undefined)).then(() => { const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right'; const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right'; @@ -1160,7 +1141,7 @@ export class Workbench implements IPartService { } } - public layout(options?: ILayoutOptions): void { + layout(options?: ILayoutOptions): void { if (this.isStarted()) { this.workbenchLayout.layout(options); } @@ -1274,7 +1255,7 @@ export class Workbench implements IPartService { private createEditorPart(): void { const editorContainer = $(this.workbench) .div({ - 'class': ['part', 'editor', 'empty2'], + 'class': ['part', 'editor'], id: Identifiers.EDITOR_PART, role: 'main' }); @@ -1295,22 +1276,19 @@ export class Workbench implements IPartService { private createNotificationsHandlers(): void { // Notifications Center - this.notificationsCenter = this.instantiationService.createInstance(NotificationsCenter, this.workbench.getHTMLElement(), this.notificationService.model); - this.toUnbind.push(this.notificationsCenter); + this.notificationsCenter = this._register(this.instantiationService.createInstance(NotificationsCenter, this.workbench.getHTMLElement(), this.notificationService.model)); // Notifications Toasts - this.notificationsToasts = this.instantiationService.createInstance(NotificationsToasts, this.workbench.getHTMLElement(), this.notificationService.model); - this.toUnbind.push(this.notificationsToasts); + this.notificationsToasts = this._register(this.instantiationService.createInstance(NotificationsToasts, this.workbench.getHTMLElement(), this.notificationService.model)); // Notifications Alerts - const notificationsAlerts = this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model); - this.toUnbind.push(notificationsAlerts); + this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model)); // Notifications Status const notificationsStatus = this.instantiationService.createInstance(NotificationsStatus, this.notificationService.model); // Eventing - this.toUnbind.push(this.notificationsCenter.onDidChangeVisibility(() => { + this._register(this.notificationsCenter.onDidChangeVisibility(() => { // Update status notificationsStatus.update(this.notificationsCenter.isVisible); @@ -1323,15 +1301,15 @@ export class Workbench implements IPartService { registerNotificationCommands(this.notificationsCenter, this.notificationsToasts); } - public getInstantiationService(): IInstantiationService { + getInstantiationService(): IInstantiationService { return this.instantiationService; } - public getWorkbenchElementId(): string { + getWorkbenchElementId(): string { return Identifiers.WORKBENCH_CONTAINER; } - public toggleZenMode(skipLayout?: boolean): void { + toggleZenMode(skipLayout?: boolean): void { this.zenMode.active = !this.zenMode.active; this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables); @@ -1405,11 +1383,11 @@ export class Workbench implements IPartService { } } - public isEditorLayoutCentered(): boolean { + isEditorLayoutCentered(): boolean { return this.centeredEditorLayoutActive; } - public centerEditorLayout(active: boolean, skipLayout?: boolean): void { + centerEditorLayout(active: boolean, skipLayout?: boolean): void { this.centeredEditorLayoutActive = active; this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, this.centeredEditorLayoutActive, StorageScope.GLOBAL); @@ -1418,7 +1396,7 @@ export class Workbench implements IPartService { } } - public resizePart(part: Parts, sizeChange: number): void { + resizePart(part: Parts, sizeChange: number): void { switch (part) { case Parts.SIDEBAR_PART: case Parts.PANEL_PART: @@ -1430,7 +1408,8 @@ export class Workbench implements IPartService { } } - public dispose(reason = ShutdownReason.QUIT): void { + dispose(reason = ShutdownReason.QUIT): void { + super.dispose(); // Restore sidebar if we are being shutdown as a matter of a reload if (reason === ShutdownReason.RELOAD) { @@ -1449,9 +1428,6 @@ export class Workbench implements IPartService { this.storageService.remove(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE); } - // Dispose bindings - this.toUnbind = dispose(this.toUnbind); - // Pass shutdown on to each participant this.workbenchShutdown = true; } diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.css b/src/vs/workbench/parts/watermark/electron-browser/watermark.css index d87bfe217ed90097bc7e12f49f325b952af7b81a..c9ad611ed2399259496d97124360fa9a5a727adf 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.css +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.css @@ -3,15 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .part.editor.empty.has-watermark { +.monaco-workbench .part.editor.has-watermark > .content.empty .editor-group-container { background-position-y: calc(50% - 100px); } +.monaco-workbench .part.editor.max-height-478px > .content.empty .editor-group-container { + background-position-y: 50%; +} + .monaco-workbench > .part.editor > .content > .watermark { display: none; /* only visible when no editors are opened */ } -.monaco-workbench > .part.editor.empty.has-watermark > .content > .watermark { +.monaco-workbench > .part.editor.has-watermark > .content.empty > .watermark { display: block; position: absolute; width: 100%; @@ -21,72 +25,69 @@ overflow: hidden; } -.monaco-workbench > .part.editor.empty > .content > .watermark > .watermark-box { +.monaco-workbench > .part.editor > .content.empty > .watermark > .watermark-box { display: inline-table; border-collapse: separate; border-spacing: 13px 17px; } -.monaco-workbench > .part.editor.empty.max-height-478px > .content > .watermark { +.monaco-workbench > .part.editor.max-height-478px > .content.empty > .watermark { display: none; } -.monaco-workbench .part.editor.empty.max-height-478px { - background-position-y: 50%; -} -.monaco-workbench > .part.editor.empty > .content > .watermark dl { +.monaco-workbench > .part.editor > .content.empty > .watermark dl { display: table-row; opacity: .8; cursor: default; } -.monaco-workbench > .part.editor.empty > .content > .watermark dt { +.monaco-workbench > .part.editor > .content.empty > .watermark dt { text-align: right; letter-spacing: 0.04em } -.monaco-workbench > .part.editor.empty > .content > .watermark dd { +.monaco-workbench > .part.editor > .content.empty > .watermark dd { text-align: left; } -.monaco-workbench > .part.editor.empty > .content > .watermark dd > .shortcuts { +.monaco-workbench > .part.editor > .content.empty > .watermark dd > .shortcuts { padding-left: 0.5em; padding-right: 0.5em; } -.monaco-workbench.mac > .part.editor.empty > .content > .watermark dd > .shortcuts { +.monaco-workbench.mac > .part.editor > .content.empty > .watermark dd > .shortcuts { letter-spacing: 0.15em; font-family: "Lucida Grande", sans-serif; } -.monaco-workbench > .part.editor.empty > .content > .watermark dd > .unbound { +.monaco-workbench > .part.editor > .content.empty > .watermark dd > .unbound { padding-left: 0.5em; padding-right: 0.5em; } -.monaco-workbench.mac > .part.editor.empty > .content > .watermark dd > .unbound { +.monaco-workbench.mac > .part.editor > .content.empty > .watermark dd > .unbound { font-family: "Lucida Grande", sans-serif; } -.monaco-workbench > .part.editor.empty > .content > .watermark dt, -.monaco-workbench > .part.editor.empty > .content > .watermark dd { +.monaco-workbench > .part.editor > .content.empty > .watermark dt, +.monaco-workbench > .part.editor > .content.empty > .watermark dd { display: table-cell; } -.monaco-workbench > .part.editor.empty > .content > .watermark dt, -.monaco-workbench > .part.editor.empty > .content > .watermark dl { +.monaco-workbench > .part.editor > .content.empty > .watermark dt, +.monaco-workbench > .part.editor > .content.empty > .watermark dl { color: rgba(0,0,0,.68); } -.vs-dark .monaco-workbench > .part.editor.empty > .content > .watermark dt, -.vs-dark .monaco-workbench > .part.editor.empty > .content > .watermark dl { +.vs-dark .monaco-workbench > .part.editor > .content.empty > .watermark dt, +.vs-dark .monaco-workbench > .part.editor > .content.empty > .watermark dl { color: rgba(255,255,255,.6); } -.hc-black .monaco-workbench > .part.editor.empty > .content > .watermark dt { +.hc-black .monaco-workbench > .part.editor > .content.empty > .watermark dt { color: #FFF; } -.hc-black .monaco-workbench > .part.editor.empty > .content > .watermark dl { +.hc-black .monaco-workbench > .part.editor > .content.empty > .watermark dl { color: #FFF; opacity: 1; } diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index abe12f5b9e72f8fabec1db29e713e01653d02c00..dc07f87f19521ee0bdfefc162fa9013e4ca1f3cd 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -30,6 +30,7 @@ import { FileIconThemeStore } from 'vs/workbench/services/themes/electron-browse import { FileIconThemeData } from 'vs/workbench/services/themes/electron-browser/fileIconThemeData'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { removeClasses, addClasses } from 'vs/base/browser/dom'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; // implementation @@ -97,7 +98,9 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { @IConfigurationService private configurationService: IConfigurationService, @ITelemetryService private telemetryService: ITelemetryService, @IWindowService private windowService: IWindowService, - @IInstantiationService private instantiationService: IInstantiationService) { + @IInstantiationService private instantiationService: IInstantiationService, + @IEnvironmentService private environmentService: IEnvironmentService + ) { this.container = container; this.colorThemeStore = new ColorThemeStore(extensionService, ColorThemeData.createLoadedEmptyTheme(DEFAULT_THEME_ID, DEFAULT_THEME_SETTING_VALUE)); @@ -306,7 +309,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } } }; - themingRegistry.getThemingParticipants().forEach(p => p(themeData, ruleCollector)); + themingRegistry.getThemingParticipants().forEach(p => p(themeData, ruleCollector, this.environmentService)); _applyRules(cssRules.join('\n'), colorThemeRulesClassName); }