未验证 提交 699c708e 编写于 作者: M Miguel Solorio 提交者: GitHub

Merge branch 'master' into misolori/icon-font-explorer

......@@ -303,7 +303,7 @@ export class IssueReporter extends Disposable {
const loggerClient = new LoggerChannelClient(mainProcessService.getChannel('logger'));
this.logService = new FollowerLogService(loggerClient, logService);
const sharedProcess = (<IWindowsService>serviceCollection.get(IWindowsService)).whenSharedProcessReady()
const sharedProcess = mainProcessService.getChannel('sharedProcess').call('whenSharedProcessReady')
.then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${configuration.windowId}`));
const instantiationService = new InstantiationService(serviceCollection, true);
......
......@@ -77,6 +77,7 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro
import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
export class CodeApplication extends Disposable {
......@@ -448,7 +449,8 @@ export class CodeApplication extends Disposable {
}
services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv]));
services.set(IWindowsService, new SyncDescriptor(LegacyWindowsMainService, [sharedProcess]));
services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess]));
services.set(IWindowsService, new SyncDescriptor(LegacyWindowsMainService));
services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService));
const diagnosticsChannel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('diagnostics')));
......@@ -545,6 +547,10 @@ export class CodeApplication extends Disposable {
const electronChannel = new SimpleServiceProxyChannel(electronService);
electronIpcServer.registerChannel('electron', electronChannel);
const sharedProcessMainService = accessor.get(ISharedProcessMainService);
const sharedProcessChannel = new SimpleServiceProxyChannel(sharedProcessMainService);
electronIpcServer.registerChannel('sharedProcess', sharedProcessChannel);
const workspacesMainService = accessor.get(IWorkspacesMainService);
const workspacesChannel = new WorkspacesChannel(workspacesMainService);
electronIpcServer.registerChannel('workspaces', workspacesChannel);
......
......@@ -908,7 +908,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
}
}
onWindowTitleDoubleClick(): void {
handleTitleDoubleClick(): void {
// Respect system settings on mac with regards to title click on windows title
if (isMacintosh) {
......
......@@ -1763,7 +1763,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this._onWindowClose.fire(win.id);
}
async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('open', "Open");
const paths = await this.dialogs.pick({ ...options, pickFolders: true, pickFiles: true, title });
if (paths) {
......@@ -1775,7 +1775,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}));
this.open({
context: OpenContext.DIALOG,
contextWindowId: options.windowId,
contextWindowId: win ? win.id : undefined,
cli: this.environmentService.args,
urisToOpen,
forceNewWindow: options.forceNewWindow
......@@ -1783,14 +1783,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openFolder', "Open Folder");
const paths = await this.dialogs.pick({ ...options, pickFolders: true, title });
if (paths) {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFolder', options.telemetryExtraData);
this.open({
context: OpenContext.DIALOG,
contextWindowId: options.windowId,
contextWindowId: win ? win.id : undefined,
cli: this.environmentService.args,
urisToOpen: paths.map(path => ({ folderUri: URI.file(path) })),
forceNewWindow: options.forceNewWindow
......@@ -1798,14 +1798,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openFile', "Open File");
const paths = await this.dialogs.pick({ ...options, pickFiles: true, title });
if (paths) {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFile', options.telemetryExtraData);
this.open({
context: OpenContext.DIALOG,
contextWindowId: options.windowId,
contextWindowId: win ? win.id : undefined,
cli: this.environmentService.args,
urisToOpen: paths.map(path => ({ fileUri: URI.file(path) })),
forceNewWindow: options.forceNewWindow
......@@ -1813,7 +1813,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openWorkspaceTitle', "Open Workspace");
const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open"));
const filters = WORKSPACE_FILTER;
......@@ -1822,7 +1822,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openWorkspace', options.telemetryExtraData);
this.open({
context: OpenContext.DIALOG,
contextWindowId: options.windowId,
contextWindowId: win ? win.id : undefined,
cli: this.environmentService.args,
urisToOpen: paths.map(path => ({ workspaceUri: URI.file(path) })),
forceNewWindow: options.forceNewWindow
......@@ -1899,7 +1899,7 @@ class Dialogs {
this.noWindowDialogQueue = new Queue<void>();
}
async pick(options: IInternalNativeOpenDialogOptions): Promise<string[] | undefined> {
async pick(options: IInternalNativeOpenDialogOptions, win?: ICodeWindow): Promise<string[] | undefined> {
// Ensure dialog options
const dialogOptions: OpenDialogOptions = {
......@@ -1930,9 +1930,9 @@ class Dialogs {
}
// Show Dialog
const focusedWindow = (typeof options.windowId === 'number' ? this.windowsMainService.getWindowById(options.windowId) : undefined) || this.windowsMainService.getFocusedWindow();
const windowToUse = win || this.windowsMainService.getFocusedWindow();
const result = await this.showOpenDialog(dialogOptions, focusedWindow);
const result = await this.showOpenDialog(dialogOptions, windowToUse);
if (result && result.filePaths && result.filePaths.length > 0) {
// Remember path in storage for next time
......
......@@ -4,12 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue } from 'electron';
import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, CrashReporterStartOptions, crashReporter, Menu } from 'electron';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { OpenContext, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows';
import { isMacintosh } from 'vs/base/common/platform';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { AddContextToFunctions } from 'vs/platform/ipc/node/simpleIpcProxy';
export class ElectronMainService {
export class ElectronMainService implements AddContextToFunctions<IElectronService, number> {
_serviceBrand: undefined;
......@@ -36,6 +39,13 @@ export class ElectronMainService {
}
}
async handleTitleDoubleClick(windowId: number): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
window.handleTitleDoubleClick();
}
}
//#endregion
//#region Dialog
......@@ -53,27 +63,19 @@ export class ElectronMainService {
}
async pickFileFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
options.windowId = windowId;
return this.windowsMainService.pickFileFolderAndOpen(options);
return this.windowsMainService.pickFileFolderAndOpen(options, this.windowsMainService.getWindowById(windowId));
}
async pickFileAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
options.windowId = windowId;
return this.windowsMainService.pickFileAndOpen(options);
return this.windowsMainService.pickFileAndOpen(options, this.windowsMainService.getWindowById(windowId));
}
async pickFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
options.windowId = windowId;
return this.windowsMainService.pickFolderAndOpen(options);
return this.windowsMainService.pickFolderAndOpen(options, this.windowsMainService.getWindowById(windowId));
}
async pickWorkspaceAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
options.windowId = windowId;
return this.windowsMainService.pickWorkspaceAndOpen(options);
return this.windowsMainService.pickWorkspaceAndOpen(options, this.windowsMainService.getWindowById(windowId));
}
//#endregion
......@@ -98,6 +100,45 @@ export class ElectronMainService {
}
}
async openExternal(windowId: number, url: string): Promise<boolean> {
return this.windowsMainService.openExternal(url);
}
async updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
window.updateTouchBar(items);
}
}
//#endregion
//#region macOS Touchbar
async newWindowTab(): Promise<void> {
this.windowsMainService.openNewTabbedWindow(OpenContext.API);
}
async showPreviousWindowTab(): Promise<void> {
Menu.sendActionToFirstResponder('selectPreviousTab:');
}
async showNextWindowTab(): Promise<void> {
Menu.sendActionToFirstResponder('selectNextTab:');
}
async moveWindowTabToNewWindow(): Promise<void> {
Menu.sendActionToFirstResponder('moveTabToNewWindow:');
}
async mergeAllWindowTabs(): Promise<void> {
Menu.sendActionToFirstResponder('mergeAllWindows:');
}
async toggleWindowTabsBar(): Promise<void> {
Menu.sendActionToFirstResponder('toggleTabBar:');
}
//#endregion
//#region Lifecycle
......@@ -113,6 +154,32 @@ export class ElectronMainService {
}
}
async closeWorkpsace(windowId: number): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
return this.windowsMainService.closeWorkspace(window);
}
}
async quit(windowId: number): Promise<void> {
return this.windowsMainService.quit();
}
//#endregion
//#region Connectivity
async resolveProxy(windowId: number, url: string): Promise<string | undefined> {
return new Promise(resolve => {
const window = this.windowsMainService.getWindowById(windowId);
if (window && window.win && window.win.webContents && window.win.webContents.session) {
window.win.webContents.session.resolveProxy(url, proxy => resolve(proxy));
} else {
resolve();
}
});
}
//#endregion
//#region Development
......@@ -136,19 +203,8 @@ export class ElectronMainService {
}
}
//#endregion
//#region Connectivity
async resolveProxy(windowId: number, url: string): Promise<string | undefined> {
return new Promise(resolve => {
const window = this.windowsMainService.getWindowById(windowId);
if (window && window.win && window.win.webContents && window.win.webContents.session) {
window.win.webContents.session.resolveProxy(url, proxy => resolve(proxy));
} else {
resolve();
}
});
async startCrashReporter(windowId: number, options: CrashReporterStartOptions): Promise<void> {
crashReporter.start(options);
}
//#endregion
......
......@@ -3,9 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { MessageBoxOptions, MessageBoxReturnValue, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, OpenDialogReturnValue, SaveDialogReturnValue } from 'electron';
import { MessageBoxOptions, MessageBoxReturnValue, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, OpenDialogReturnValue, SaveDialogReturnValue, CrashReporterStartOptions } from 'electron';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { INativeOpenDialogOptions } from 'vs/platform/windows/common/windows';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
export const IElectronService = createDecorator<IElectronService>('electronService');
......@@ -17,6 +18,7 @@ export interface IElectronService {
windowCount(): Promise<number>;
openEmptyWindow(options?: { reuse?: boolean, remoteAuthority?: string }): Promise<void>;
toggleFullScreen(): Promise<void>;
handleTitleDoubleClick(): Promise<void>;
// Dialogs
showMessageBox(options: MessageBoxOptions): Promise<MessageBoxReturnValue>;
......@@ -32,14 +34,27 @@ export interface IElectronService {
showItemInFolder(path: string): Promise<void>;
setRepresentedFilename(path: string): Promise<void>;
setDocumentEdited(edited: boolean): Promise<void>;
openExternal(url: string): Promise<boolean>;
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void>;
// macOS Touchbar
newWindowTab(): Promise<void>;
showPreviousWindowTab(): Promise<void>;
showNextWindowTab(): Promise<void>;
moveWindowTabToNewWindow(): Promise<void>;
mergeAllWindowTabs(): Promise<void>;
toggleWindowTabsBar(): Promise<void>;
// Lifecycle
relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise<void>;
reload(): Promise<void>;
closeWorkpsace(): Promise<void>;
quit(): Promise<void>;
// Development
openDevTools(options?: OpenDevToolsOptions): Promise<void>;
toggleDevTools(): Promise<void>;
startCrashReporter(options: CrashReporterStartOptions): Promise<void>;
// Connectivity
resolveProxy(url: string): Promise<string | undefined>;
......
......@@ -6,9 +6,10 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
import { connect } from 'vs/base/parts/ipc/node/ipc.net';
import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
export const ISharedProcessService = createDecorator<ISharedProcessService>('sharedProcessService');
......@@ -17,8 +18,10 @@ export interface ISharedProcessService {
_serviceBrand: undefined;
getChannel(channelName: string): IChannel;
registerChannel(channelName: string, channel: IServerChannel<string>): void;
whenSharedProcessReady(): Promise<void>;
toggleSharedProcessWindow(): Promise<void>;
}
export class SharedProcessService implements ISharedProcessService {
......@@ -26,16 +29,23 @@ export class SharedProcessService implements ISharedProcessService {
_serviceBrand: undefined;
private withSharedProcessConnection: Promise<Client<string>>;
private sharedProcessMainChannel: IChannel;
constructor(
@IWindowsService windowsService: IWindowsService,
@IMainProcessService mainProcessService: IMainProcessService,
@IWindowService windowService: IWindowService,
@IEnvironmentService environmentService: IEnvironmentService
) {
this.withSharedProcessConnection = windowsService.whenSharedProcessReady()
this.sharedProcessMainChannel = mainProcessService.getChannel('sharedProcess');
this.withSharedProcessConnection = this.whenSharedProcessReady()
.then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.windowId}`));
}
whenSharedProcessReady(): Promise<void> {
return this.sharedProcessMainChannel.call('whenSharedProcessReady');
}
getChannel(channelName: string): IChannel {
return getDelayedChannel(this.withSharedProcessConnection.then(connection => connection.getChannel(channelName)));
}
......@@ -43,4 +53,8 @@ export class SharedProcessService implements ISharedProcessService {
registerChannel(channelName: string, channel: IServerChannel<string>): void {
this.withSharedProcessConnection.then(connection => connection.registerChannel(channelName, channel));
}
toggleSharedProcessWindow(): Promise<void> {
return this.sharedProcessMainChannel.call('toggleSharedProcessWindow');
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ISharedProcess } from 'vs/platform/windows/electron-main/windows';
export const ISharedProcessMainService = createDecorator<ISharedProcessMainService>('sharedProcessMainService');
export interface ISharedProcessMainService {
_serviceBrand: undefined;
whenSharedProcessReady(): Promise<void>;
toggleSharedProcessWindow(): Promise<void>;
}
export class SharedProcessMainService implements ISharedProcessMainService {
_serviceBrand: undefined;
constructor(private sharedProcess: ISharedProcess) { }
whenSharedProcessReady(): Promise<void> {
return this.sharedProcess.whenReady();
}
async toggleSharedProcessWindow(): Promise<void> {
return this.sharedProcess.toggle();
}
}
......@@ -11,6 +11,11 @@ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
// for a very basic process <=> process communication over methods.
//
export type AddContextToFunctions<Target, Context> = {
// For every property: IF property is a FUNCTION ADD context as first parameter and original parameters afterwards with same return type, otherwise preserve as is
[K in keyof Target]: Target[K] extends (...args: any) => any ? (context: Context, ...args: Parameters<Target[K]>) => ReturnType<Target[K]> : Target[K]
};
interface ISimpleChannelProxyContext {
__$simpleIPCContextMarker: boolean;
proxyContext: unknown;
......@@ -44,13 +49,15 @@ export class SimpleServiceProxyChannel implements IServerChannel {
throw new Error(`Events are currently unsupported by SimpleServiceProxyChannel: ${event}`);
}
call(_: unknown, command: string, args: any[]): Promise<any> {
call(_: unknown, command: string, args?: any[]): Promise<any> {
const target = this.service[command];
if (typeof target === 'function') {
if (Array.isArray(args)) {
const context = deserializeContext(args[0]);
if (context) {
args[0] = context;
}
}
return target.apply(this.service, args);
}
......
......@@ -10,7 +10,6 @@ import { IProcessEnvironment, isMacintosh, isLinux, isWeb } from 'vs/base/common
import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { ExportData } from 'vs/base/common/performance';
import { LogLevel } from 'vs/platform/log/common/log';
import { DisposableStore, Disposable } from 'vs/base/common/lifecycle';
......@@ -21,7 +20,6 @@ import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async
export const IWindowsService = createDecorator<IWindowsService>('windowsService');
export interface INativeOpenDialogOptions {
windowId?: number;
forceNewWindow?: boolean;
defaultPath?: string;
......@@ -35,16 +33,6 @@ export interface IEnterWorkspaceResult {
backupPath?: string;
}
export interface CrashReporterStartOptions {
companyName?: string;
submitURL: string;
productName?: string;
uploadToServer?: boolean;
ignoreSystemCrashHandler?: boolean;
extra?: any;
crashesDirectory?: string;
}
export interface OpenDialogOptions {
title?: string;
defaultPath?: string;
......@@ -94,7 +82,6 @@ export interface IWindowsService {
readonly onWindowUnmaximize: Event<number>;
readonly onRecentlyOpenedChange: Event<void>;
closeWorkspace(windowId: number): Promise<void>;
enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | undefined>;
addRecentlyOpened(recents: IRecent[]): Promise<void>;
removeFromRecentlyOpened(paths: URI[]): Promise<void>;
......@@ -107,36 +94,11 @@ export interface IWindowsService {
maximizeWindow(windowId: number): Promise<void>;
unmaximizeWindow(windowId: number): Promise<void>;
minimizeWindow(windowId: number): Promise<void>;
onWindowTitleDoubleClick(windowId: number): Promise<void>;
quit(): Promise<void>;
// macOS Native Tabs
newWindowTab(): Promise<void>;
showPreviousWindowTab(): Promise<void>;
showNextWindowTab(): Promise<void>;
moveWindowTabToNewWindow(): Promise<void>;
mergeAllWindowTabs(): Promise<void>;
toggleWindowTabsBar(): Promise<void>;
// macOS TouchBar
updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise<void>;
// Shared process
whenSharedProcessReady(): Promise<void>;
toggleSharedProcess(): Promise<void>;
// Global methods
openWindow(windowId: number, uris: IURIToOpen[], options: IOpenSettings): Promise<void>;
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void>;
getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>;
getActiveWindowId(): Promise<number | undefined>;
// This needs to be handled from browser process to prevent
// foreground ordering issues on Windows
openExternal(url: string): Promise<boolean>;
// TODO: this is a bit backwards
startCrashReporter(config: CrashReporterStartOptions): Promise<void>;
}
export const IWindowService = createDecorator<IWindowService>('windowService');
......@@ -193,8 +155,6 @@ export interface IWindowService {
readonly windowId: number;
closeWorkspace(): Promise<void>;
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void>;
enterWorkspace(path: URI): Promise<IEnterWorkspaceResult | undefined>;
getRecentlyOpened(): Promise<IRecentlyOpened>;
addRecentlyOpened(recents: IRecent[]): Promise<void>;
......@@ -207,7 +167,6 @@ export interface IWindowService {
maximizeWindow(): Promise<void>;
unmaximizeWindow(): Promise<void>;
minimizeWindow(): Promise<void>;
onWindowTitleDoubleClick(): Promise<void>;
}
export type MenuBarVisibility = 'default' | 'visible' | 'toggle' | 'hidden';
......
......@@ -43,7 +43,6 @@ export class WindowsChannel implements IServerChannel {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'closeWorkspace': return this.service.closeWorkspace(arg);
case 'enterWorkspace': return this.service.enterWorkspace(arg[0], URI.revive(arg[1]));
case 'addRecentlyOpened': return this.service.addRecentlyOpened(arg.map((recent: IRecent) => {
if (isRecentFile(recent)) {
......@@ -57,13 +56,6 @@ export class WindowsChannel implements IServerChannel {
}));
case 'removeFromRecentlyOpened': return this.service.removeFromRecentlyOpened(arg.map(URI.revive));
case 'clearRecentlyOpened': return this.service.clearRecentlyOpened();
case 'newWindowTab': return this.service.newWindowTab();
case 'showPreviousWindowTab': return this.service.showPreviousWindowTab();
case 'showNextWindowTab': return this.service.showNextWindowTab();
case 'moveWindowTabToNewWindow': return this.service.moveWindowTabToNewWindow();
case 'mergeAllWindowTabs': return this.service.mergeAllWindowTabs();
case 'toggleWindowTabsBar': return this.service.toggleWindowTabsBar();
case 'updateTouchBar': return this.service.updateTouchBar(arg[0], arg[1]);
case 'getRecentlyOpened': return this.service.getRecentlyOpened(arg);
case 'focusWindow': return this.service.focusWindow(arg);
case 'closeWindow': return this.service.closeWindow(arg);
......@@ -72,7 +64,6 @@ export class WindowsChannel implements IServerChannel {
case 'maximizeWindow': return this.service.maximizeWindow(arg);
case 'unmaximizeWindow': return this.service.unmaximizeWindow(arg);
case 'minimizeWindow': return this.service.minimizeWindow(arg);
case 'onWindowTitleDoubleClick': return this.service.onWindowTitleDoubleClick(arg);
case 'openWindow': {
const urisToOpen: IURIToOpen[] = arg[1];
const options: IOpenSettings = arg[2];
......@@ -88,14 +79,9 @@ export class WindowsChannel implements IServerChannel {
options.waitMarkerFileURI = options.waitMarkerFileURI && URI.revive(options.waitMarkerFileURI);
return this.service.openWindow(arg[0], urisToOpen, options);
}
case 'openExtensionDevelopmentHostWindow': return this.service.openExtensionDevelopmentHostWindow(arg[0], arg[1]);
case 'openExtensionDevelopmentHostWindow': return (this.service as any).openExtensionDevelopmentHostWindow(arg[0], arg[1]); // TODO@Isidor move
case 'getWindows': return this.service.getWindows();
case 'whenSharedProcessReady': return this.service.whenSharedProcessReady();
case 'toggleSharedProcess': return this.service.toggleSharedProcess();
case 'quit': return this.service.quit();
case 'getActiveWindowId': return this.service.getActiveWindowId();
case 'openExternal': return this.service.openExternal(arg);
case 'startCrashReporter': return this.service.startCrashReporter(arg);
}
throw new Error(`Call not found: ${command}`);
......
......@@ -5,10 +5,9 @@
import { Event } from 'vs/base/common/event';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IWindowsService, IEnterWorkspaceResult, CrashReporterStartOptions, IURIToOpen, IOpenSettings } from 'vs/platform/windows/common/windows';
import { IWindowsService, IEnterWorkspaceResult, IURIToOpen, IOpenSettings } from 'vs/platform/windows/common/windows';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IRecentlyOpened, IRecent, isRecentWorkspace } from 'vs/platform/history/common/history';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { URI } from 'vs/base/common/uri';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
......@@ -31,10 +30,6 @@ export class WindowsService implements IWindowsService {
this.channel = mainProcessService.getChannel('windows');
}
closeWorkspace(windowId: number): Promise<void> {
return this.channel.call('closeWorkspace', windowId);
}
async enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | undefined> {
const result: IEnterWorkspaceResult = await this.channel.call('enterWorkspace', [windowId, path]);
if (result) {
......@@ -64,30 +59,6 @@ export class WindowsService implements IWindowsService {
return recentlyOpened;
}
newWindowTab(): Promise<void> {
return this.channel.call('newWindowTab');
}
showPreviousWindowTab(): Promise<void> {
return this.channel.call('showPreviousWindowTab');
}
showNextWindowTab(): Promise<void> {
return this.channel.call('showNextWindowTab');
}
moveWindowTabToNewWindow(): Promise<void> {
return this.channel.call('moveWindowTabToNewWindow');
}
mergeAllWindowTabs(): Promise<void> {
return this.channel.call('mergeAllWindowTabs');
}
toggleWindowTabsBar(): Promise<void> {
return this.channel.call('toggleWindowTabsBar');
}
focusWindow(windowId: number): Promise<void> {
return this.channel.call('focusWindow', windowId);
}
......@@ -116,22 +87,6 @@ export class WindowsService implements IWindowsService {
return this.channel.call('minimizeWindow', windowId);
}
onWindowTitleDoubleClick(windowId: number): Promise<void> {
return this.channel.call('onWindowTitleDoubleClick', windowId);
}
quit(): Promise<void> {
return this.channel.call('quit');
}
whenSharedProcessReady(): Promise<void> {
return this.channel.call('whenSharedProcessReady');
}
toggleSharedProcess(): Promise<void> {
return this.channel.call('toggleSharedProcess');
}
openWindow(windowId: number, uris: IURIToOpen[], options: IOpenSettings): Promise<void> {
return this.channel.call('openWindow', [windowId, uris, options]);
}
......@@ -165,16 +120,4 @@ export class WindowsService implements IWindowsService {
getActiveWindowId(): Promise<number | undefined> {
return this.channel.call('getActiveWindowId');
}
openExternal(url: string): Promise<boolean> {
return this.channel.call('openExternal', url);
}
startCrashReporter(config: CrashReporterStartOptions): Promise<void> {
return this.channel.call('startCrashReporter', config);
}
updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise<void> {
return this.channel.call('updateTouchBar', [windowId, items]);
}
}
......@@ -8,14 +8,13 @@ import { assign } from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri';
import { IWindowsService, OpenContext, IEnterWorkspaceResult, IOpenSettings, IURIToOpen } from 'vs/platform/windows/common/windows';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { crashReporter, app, Menu, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue, CrashReporterStartOptions, BrowserWindow, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions } from 'electron';
import { app, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue, BrowserWindow, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions } from 'electron';
import { Event } from 'vs/base/common/event';
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
import { IWindowsMainService, ISharedProcess, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { Schemas } from 'vs/base/common/network';
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
import { ILogService } from 'vs/platform/log/common/log';
......@@ -41,7 +40,6 @@ export class LegacyWindowsMainService extends Disposable implements IWindowsServ
readonly onRecentlyOpenedChange: Event<void> = this.historyMainService.onRecentlyOpenedChange;
constructor(
private sharedProcess: ISharedProcess,
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IURLService urlService: IURLService,
......@@ -75,18 +73,6 @@ export class LegacyWindowsMainService extends Disposable implements IWindowsServ
return this.withWindow(windowId, codeWindow => this.windowsMainService.showOpenDialog(options, codeWindow), () => this.windowsMainService.showOpenDialog(options))!;
}
async updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise<void> {
this.logService.trace('windowsService#updateTouchBar', windowId);
return this.withWindow(windowId, codeWindow => codeWindow.updateTouchBar(items));
}
async closeWorkspace(windowId: number): Promise<void> {
this.logService.trace('windowsService#closeWorkspace', windowId);
return this.withWindow(windowId, codeWindow => this.windowsMainService.closeWorkspace(codeWindow));
}
async enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | undefined> {
this.logService.trace('windowsService#enterWorkspace', windowId);
......@@ -116,42 +102,6 @@ export class LegacyWindowsMainService extends Disposable implements IWindowsServ
return this.withWindow(windowId, codeWindow => this.historyMainService.getRecentlyOpened(codeWindow.config.workspace, codeWindow.config.folderUri, codeWindow.config.filesToOpenOrCreate), () => this.historyMainService.getRecentlyOpened())!;
}
async newWindowTab(): Promise<void> {
this.logService.trace('windowsService#newWindowTab');
this.windowsMainService.openNewTabbedWindow(OpenContext.API);
}
async showPreviousWindowTab(): Promise<void> {
this.logService.trace('windowsService#showPreviousWindowTab');
Menu.sendActionToFirstResponder('selectPreviousTab:');
}
async showNextWindowTab(): Promise<void> {
this.logService.trace('windowsService#showNextWindowTab');
Menu.sendActionToFirstResponder('selectNextTab:');
}
async moveWindowTabToNewWindow(): Promise<void> {
this.logService.trace('windowsService#moveWindowTabToNewWindow');
Menu.sendActionToFirstResponder('moveTabToNewWindow:');
}
async mergeAllWindowTabs(): Promise<void> {
this.logService.trace('windowsService#mergeAllWindowTabs');
Menu.sendActionToFirstResponder('mergeAllWindows:');
}
async toggleWindowTabsBar(): Promise<void> {
this.logService.trace('windowsService#toggleWindowTabsBar');
Menu.sendActionToFirstResponder('toggleTabBar:');
}
async focusWindow(windowId: number): Promise<void> {
this.logService.trace('windowsService#focusWindow', windowId);
......@@ -198,12 +148,6 @@ export class LegacyWindowsMainService extends Disposable implements IWindowsServ
return this.withWindow(windowId, codeWindow => codeWindow.win.minimize());
}
async onWindowTitleDoubleClick(windowId: number): Promise<void> {
this.logService.trace('windowsService#onWindowTitleDoubleClick', windowId);
return this.withWindow(windowId, codeWindow => codeWindow.onWindowTitleDoubleClick());
}
async openWindow(windowId: number, urisToOpen: IURIToOpen[], options: IOpenSettings): Promise<void> {
this.logService.trace('windowsService#openWindow');
if (!urisToOpen || !urisToOpen.length) {
......@@ -262,35 +206,6 @@ export class LegacyWindowsMainService extends Disposable implements IWindowsServ
return this._activeWindowId;
}
async openExternal(url: string): Promise<boolean> {
return this.windowsMainService.openExternal(url);
}
async startCrashReporter(config: CrashReporterStartOptions): Promise<void> {
this.logService.trace('windowsService#startCrashReporter');
crashReporter.start(config);
}
async quit(): Promise<void> {
this.logService.trace('windowsService#quit');
this.windowsMainService.quit();
}
async whenSharedProcessReady(): Promise<void> {
this.logService.trace('windowsService#whenSharedProcessReady');
return this.sharedProcess.whenReady();
}
async toggleSharedProcess(): Promise<void> {
this.logService.trace('windowsService#toggleSharedProcess');
this.sharedProcess.toggle();
}
async handleURL(uri: URI): Promise<boolean> {
// Catch file URLs
......
......@@ -67,7 +67,7 @@ export interface ICodeWindow {
hasHiddenTitleBarStyle(): boolean;
setRepresentedFilename(name: string): void;
getRepresentedFilename(): string;
onWindowTitleDoubleClick(): void;
handleTitleDoubleClick(): void;
updateTouchBar(items: ISerializableCommandAction[][]): void;
......@@ -98,10 +98,10 @@ export interface IWindowsMainService {
closeWorkspace(win: ICodeWindow): void;
open(openConfig: IOpenConfiguration): ICodeWindow[];
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void;
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void>;
pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void>;
pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void>;
pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void>;
showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise<MessageBoxReturnValue>;
showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise<SaveDialogReturnValue>;
showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise<OpenDialogReturnValue>;
......
......@@ -13,10 +13,14 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c
import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { MenuRegistry, MenuId, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { WorkbenchStateContext, SupportsWorkspacesContext } from 'vs/workbench/browser/contextkeys';
import { WorkbenchStateContext, SupportsWorkspacesContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
export class OpenFileAction extends Action {
......@@ -90,6 +94,32 @@ export class OpenWorkspaceAction extends Action {
}
}
export class CloseWorkspaceAction extends Action {
static readonly ID = 'workbench.action.closeFolder';
static LABEL = nls.localize('closeWorkspace', "Close Workspace");
constructor(
id: string,
label: string,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@INotificationService private readonly notificationService: INotificationService,
@IHostService private readonly hostService: IHostService
) {
super(id, label);
}
run(): Promise<void> {
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
this.notificationService.info(nls.localize('noWorkspaceOpened', "There is currently no workspace opened in this instance to close."));
return Promise.resolve(undefined);
}
return this.hostService.closeWorkspace();
}
}
export class OpenWorkspaceConfigFileAction extends Action {
static readonly ID = 'workbench.action.openWorkspaceConfigFile';
......@@ -170,6 +200,7 @@ const workspacesCategory = nls.localize('workspaces', "Workspaces");
registry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory, SupportsWorkspacesContext);
registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory, SupportsWorkspacesContext);
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', workspacesCategory, SupportsWorkspacesContext);
// --- Menu Registration
......@@ -194,3 +225,24 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
},
when: WorkbenchStateContext.isEqualTo('workspace')
});
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '6_close',
command: {
id: CloseWorkspaceAction.ID,
title: nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"),
precondition: WorkspaceFolderCountContext.notEqualsTo('0')
},
order: 3,
when: WorkbenchStateContext.notEqualsTo('workspace')
});
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '6_close',
command: {
id: CloseWorkspaceAction.ID,
title: nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace")
},
order: 3,
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), SupportsWorkspacesContext)
});
......@@ -346,15 +346,6 @@ export class TitlebarPart extends Part implements ITitleService {
this.titleUpdater.schedule();
}
// Maximize/Restore on doubleclick
if (isMacintosh && !isWeb) {
this._register(addDisposableListener(this.element, EventType.DBLCLICK, e => {
EventHelper.stop(e);
this.onTitleDoubleclick();
}));
}
// Context menu on title
[EventType.CONTEXT_MENU, EventType.MOUSE_DOWN].forEach(event => {
this._register(addDisposableListener(this.title, event, e => {
......@@ -405,7 +396,7 @@ export class TitlebarPart extends Part implements ITitleService {
const isMaximized = this.environmentService.configuration.maximized ? true : false;
this.onDidChangeMaximized(isMaximized);
this.windowService.onDidChangeMaximize(this.onDidChangeMaximized, this);
this._register(this.windowService.onDidChangeMaximize(this.onDidChangeMaximized, this));
}
// Since the title area is used to drag the window, we do not want to steal focus from the
......@@ -477,10 +468,6 @@ export class TitlebarPart extends Part implements ITitleService {
}
}
private onTitleDoubleclick(): void {
this.windowService.onWindowTitleDoubleClick();
}
private onUpdateAppIconDragBehavior() {
const setting = this.configurationService.getValue('window.doubleClickIconToClose');
if (setting) {
......
......@@ -10,18 +10,15 @@ import { Event } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { Disposable } from 'vs/base/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IWindowService, IEnterWorkspaceResult, IURIToOpen, IWindowsService, IOpenSettings, IWindowSettings, CrashReporterStartOptions } from 'vs/platform/windows/common/windows';
import { IWindowService, IEnterWorkspaceResult, IURIToOpen, IWindowsService, IOpenSettings, IWindowSettings } from 'vs/platform/windows/common/windows';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IRecentlyOpened, IRecent, isRecentFile, isRecentFolder } from 'vs/platform/history/common/history';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { addDisposableListener, EventType, windowOpenNoOpener } from 'vs/base/browser/dom';
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
import { pathsToEditors } from 'vs/workbench/common/editor';
import { IFileService } from 'vs/platform/files/common/files';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage';
//#region Window
......@@ -91,10 +88,6 @@ export class SimpleWindowService extends Disposable implements IWindowService {
return Promise.resolve(false);
}
closeWorkspace(): Promise<void> {
return Promise.resolve();
}
enterWorkspace(_path: URI): Promise<IEnterWorkspaceResult | undefined> {
return Promise.resolve(undefined);
}
......@@ -208,14 +201,6 @@ export class SimpleWindowService extends Disposable implements IWindowService {
return Promise.resolve();
}
onWindowTitleDoubleClick(): Promise<void> {
return Promise.resolve();
}
updateTouchBar(_items: ISerializableCommandAction[][]): Promise<void> {
return Promise.resolve();
}
}
registerSingleton(IWindowService, SimpleWindowService);
......@@ -238,10 +223,6 @@ export class SimpleWindowsService implements IWindowsService {
return Promise.resolve(true);
}
closeWorkspace(_windowId: number): Promise<void> {
return Promise.resolve();
}
enterWorkspace(_windowId: number, _path: URI): Promise<IEnterWorkspaceResult | undefined> {
return Promise.resolve(undefined);
}
......@@ -289,79 +270,18 @@ export class SimpleWindowsService implements IWindowsService {
return Promise.resolve();
}
onWindowTitleDoubleClick(_windowId: number): Promise<void> {
return Promise.resolve();
}
quit(): Promise<void> {
return Promise.resolve();
}
whenSharedProcessReady(): Promise<void> {
return Promise.resolve();
}
toggleSharedProcess(): Promise<void> {
return Promise.resolve();
}
// Global methods
openWindow(_windowId: number, _uris: IURIToOpen[], _options: IOpenSettings): Promise<void> {
return Promise.resolve();
}
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
return Promise.resolve();
}
getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {
return Promise.resolve([]);
}
newWindowTab(): Promise<void> {
return Promise.resolve();
}
showPreviousWindowTab(): Promise<void> {
return Promise.resolve();
}
showNextWindowTab(): Promise<void> {
return Promise.resolve();
}
moveWindowTabToNewWindow(): Promise<void> {
return Promise.resolve();
}
mergeAllWindowTabs(): Promise<void> {
return Promise.resolve();
}
toggleWindowTabsBar(): Promise<void> {
return Promise.resolve();
}
updateTouchBar(_windowId: number, _items: ISerializableCommandAction[][]): Promise<void> {
return Promise.resolve();
}
getActiveWindowId(): Promise<number | undefined> {
return Promise.resolve(0);
}
// This needs to be handled from browser process to prevent
// foreground ordering issues on Windows
openExternal(_url: string): Promise<boolean> {
windowOpenNoOpener(_url);
return Promise.resolve(true);
}
// TODO: this is a bit backwards
startCrashReporter(_config: CrashReporterStartOptions): Promise<void> {
return Promise.resolve();
}
}
registerSingleton(IWindowsService, SimpleWindowsService);
......
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4L12 8L8 12L4 8L8 4Z" fill="#848484"/>
<path d="M8 3L13 8L8 13L3 8L8 3Z" fill="#848484"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4.84323L11.1365 7.97969L8 11.1161L4.86355 7.97969L8 4.84323Z" stroke="#848484" stroke-width="1.25"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.02039 7.97961L8 3L12.9796 7.97961L8 12.9592L3.02039 7.97961ZM8 10.7696L10.79 7.97961L8 5.18956L5.20996 7.97961L8 10.7696Z" fill="#848484"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4L12 8L8 12L4 8L8 4Z" fill="#E51400"/>
<path d="M8 3L13 8L8 13L3 8L8 3Z" fill="#E51400"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3259 10.2223C11.7654 9.56448 12 8.79112 12 8C12.0001 7.47467 11.8968 6.95447 11.6958 6.4691C11.4948 5.98374 11.2002 5.54273 10.8287 5.17126C10.4573 4.7998 10.0163 4.50517 9.5309 4.3042C9.04553 4.10323 8.52533 3.99986 8 4C7.20888 4 6.43552 4.2346 5.77772 4.67412C5.11992 5.11365 4.60723 5.73836 4.30448 6.46927C4.00173 7.20017 3.92252 8.00444 4.07686 8.78036C4.2312 9.55628 4.61216 10.269 5.17157 10.8284C5.73098 11.3878 6.44372 11.7688 7.21964 11.9231C7.99556 12.0775 8.79983 11.9983 9.53073 11.6955C10.2616 11.3928 10.8864 10.8801 11.3259 10.2223ZM8.4 9.6H7.6V10.4H8.4V9.6ZM7.6 8.8V5.6H8.4V8.8H7.6Z" fill="#E51400"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3259 10.2223C11.7654 9.56448 12 8.79112 12 8C12.0001 7.47467 11.8968 6.95447 11.6958 6.4691C11.4948 5.98374 11.2002 5.54273 10.8287 5.17126C10.4573 4.7998 10.0163 4.50517 9.5309 4.3042C9.04553 4.10323 8.52533 3.99986 8 4C7.20888 4 6.43552 4.2346 5.77772 4.67412C5.11992 5.11365 4.60723 5.73836 4.30448 6.46927C4.00173 7.20017 3.92252 8.00444 4.07686 8.78036C4.2312 9.55628 4.61216 10.269 5.17157 10.8284C5.73098 11.3878 6.44372 11.7688 7.21964 11.9231C7.99556 12.0775 8.79983 11.9983 9.53073 11.6955C10.2616 11.3928 10.8864 10.8801 11.3259 10.2223ZM8.65 10H7.4V11H8.65V10ZM7.4 9V5H8.65V9H7.4Z" fill="#E51400"/>
</svg>
......@@ -10,6 +10,7 @@ import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } f
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService';
export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {
......@@ -22,7 +23,7 @@ export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
// TODO@Isidor use debug IPC channel
return this.windowsService.openExtensionDevelopmentHostWindow(args, env);
return (this.windowsService as WindowsService).openExtensionDevelopmentHostWindow(args, env);
}
}
......
......@@ -23,12 +23,14 @@ const enum ForceOpenAs {
Text,
Binary
}
const memoizer = createMemoizer();
/**
* A file editor input is the input type for the file editor of file system resources.
*/
export class FileEditorInput extends EditorInput implements IFileEditorInput {
private static readonly MEMOIZER = createMemoizer();
private preferredEncoding: string;
private preferredMode: string;
......@@ -69,7 +71,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
this._register(this.textFileService.models.onModelSaved(e => this.onDirtyStateChange(e)));
this._register(this.textFileService.models.onModelReverted(e => this.onDirtyStateChange(e)));
this._register(this.textFileService.models.onModelOrphanedChanged(e => this.onModelOrphanedChanged(e)));
this._register(this.labelService.onDidChangeFormatters(() => memoizer.clear()));
this._register(this.labelService.onDidChangeFormatters(() => FileEditorInput.MEMOIZER.clear()));
}
private onDirtyStateChange(e: TextFileModelChangeEvent): void {
......@@ -145,22 +147,22 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
return FILE_EDITOR_INPUT_ID;
}
@memoizer
@FileEditorInput.MEMOIZER
getName(): string {
return this.decorateLabel(this.labelService.getUriBasenameLabel(this.resource));
}
@memoizer
@FileEditorInput.MEMOIZER
private get shortDescription(): string {
return this.labelService.getUriBasenameLabel(dirname(this.resource));
}
@memoizer
@FileEditorInput.MEMOIZER
private get mediumDescription(): string {
return this.labelService.getUriLabel(dirname(this.resource), { relative: true });
}
@memoizer
@FileEditorInput.MEMOIZER
private get longDescription(): string {
return this.labelService.getUriLabel(dirname(this.resource));
}
......@@ -177,17 +179,17 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
}
}
@memoizer
@FileEditorInput.MEMOIZER
private get shortTitle(): string {
return this.getName();
}
@memoizer
@FileEditorInput.MEMOIZER
private get mediumTitle(): string {
return this.labelService.getUriLabel(this.resource, { relative: true });
}
@memoizer
@FileEditorInput.MEMOIZER
private get longTitle(): string {
return this.labelService.getUriLabel(this.resource);
}
......
......@@ -13,7 +13,7 @@ import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lif
import product from 'vs/platform/product/common/product';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IUpdateService } from 'vs/platform/update/common/update';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import * as files from 'vs/workbench/contrib/files/common/files';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
......@@ -27,7 +27,7 @@ export class StartupTimings implements IWorkbenchContribution {
constructor(
@ITimerService private readonly _timerService: ITimerService,
@IWindowsService private readonly _windowsService: IWindowsService,
@IElectronService private readonly _electronService: IElectronService,
@IEditorService private readonly _editorService: IEditorService,
@IViewletService private readonly _viewletService: IViewletService,
@IPanelService private readonly _panelService: IPanelService,
......@@ -76,10 +76,10 @@ export class StartupTimings implements IWorkbenchContribution {
]).then(([startupMetrics]) => {
return promisify(appendFile)(appendTo, `${startupMetrics.ellapsed}\t${product.nameShort}\t${(product.commit || '').slice(0, 10) || '0000000000'}\t${sessionId}\t${isStandardStartup ? 'standard_start' : 'NO_standard_start'}\n`);
}).then(() => {
this._windowsService.quit();
this._electronService.quit();
}).catch(err => {
console.error(err);
this._windowsService.quit();
this._electronService.quit();
});
}
......
......@@ -3,6 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.preferences-editor {
display: flex;
flex-direction: column;
}
.preferences-editor > .preferences-header {
padding-left: 27px;
padding-right: 32px;
......@@ -11,7 +16,7 @@
}
.preferences-editor > .preferences-editors-container.side-by-side-preferences-editor {
position: relative;
flex: 1;
}
.preferences-editor > .preferences-editors-container.side-by-side-preferences-editor .preferences-header-container {
......
......@@ -12,13 +12,13 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { isMacintosh } from 'vs/base/common/platform';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { MenuId, IMenuService, MenuItemAction, IMenu, MenuRegistry } from 'vs/platform/actions/common/actions';
import { MenuId, IMenuService, MenuItemAction, IMenu, MenuRegistry, registerAction } from 'vs/platform/actions/common/actions';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchContributionsExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
import { ILabelService } from 'vs/platform/label/common/label';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
......@@ -39,8 +39,8 @@ import { RemoteConnectionState, Deprecated_RemoteAuthorityContext, RemoteFileDia
import { IDownloadService } from 'vs/platform/download/common/download';
import { OpenLocalFileFolderCommand, OpenLocalFileCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/services/dialogs/browser/simpleFileDialog';
const WINDOW_ACTIONS_COMMAND_ID = 'remote.showActions';
const CLOSE_REMOTE_COMMAND_ID = 'remote.closeRemote';
const WINDOW_ACTIONS_COMMAND_ID = 'workbench.action.remote.showMenu';
const CLOSE_REMOTE_COMMAND_ID = 'workbench.action.remote.close';
export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenchContribution {
......@@ -68,13 +68,32 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc
this.windowCommandMenu = this.menuService.createMenu(MenuId.StatusBarWindowIndicatorMenu, this.contextKeyService);
this._register(this.windowCommandMenu);
this._register(CommandsRegistry.registerCommand(WINDOW_ACTIONS_COMMAND_ID, _ => this.showIndicatorActions(this.windowCommandMenu)));
this._register(CommandsRegistry.registerCommand(CLOSE_REMOTE_COMMAND_ID, _ => this.remoteAuthority && hostService.openEmptyWindow({ reuse: true })));
const category = nls.localize('remote.category', "Remote");
registerAction({
id: WINDOW_ACTIONS_COMMAND_ID,
category,
title: { value: nls.localize('remote.showMenu', "Show Remote Menu"), original: 'Show Remote Menu' },
menu: {
menuId: MenuId.CommandPalette
},
handler: (_accessor) => this.showIndicatorActions(this.windowCommandMenu)
});
this.remoteAuthority = environmentService.configuration.remoteAuthority;
Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(this.remoteAuthority || '');
if (this.remoteAuthority) {
registerAction({
id: CLOSE_REMOTE_COMMAND_ID,
category,
title: { value: nls.localize('remote.close', "Close Remote Connection"), original: 'Close Remote Connection' },
menu: {
menuId: MenuId.CommandPalette
},
handler: (_accessor) => this.remoteAuthority && hostService.openEmptyWindow({ reuse: true })
});
// Pending entry until extensions are ready
this.renderWindowIndicator(nls.localize('host.open', "$(sync~spin) Opening Remote..."), undefined, WINDOW_ACTIONS_COMMAND_ID);
this.connectionState = 'initializing';
......@@ -305,6 +324,7 @@ class RemoteTelemetryEnablementUpdater extends Disposable implements IWorkbenchC
}
}
class RemoteEmptyWorkbenchPresentation extends Disposable implements IWorkbenchContribution {
constructor(
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
......
......@@ -493,7 +493,7 @@ class ViewModel {
export class ToggleViewModeAction extends Action {
static readonly ID = 'workbench.scm.action.toggleViewMode';
static readonly LABEL = localize('toggleViewMode', "ToggleViewMode");
static readonly LABEL = localize('toggleViewMode', "Toggle View Mode");
constructor(private viewModel: ViewModel) {
super(ToggleViewModeAction.ID, ToggleViewModeAction.LABEL);
......
......@@ -1239,7 +1239,8 @@ namespace ConfigurationProperties {
{ property: 'name' }, { property: 'identifier' }, { property: 'group' }, { property: 'isBackground' },
{ property: 'promptOnClose' }, { property: 'dependsOn' },
{ property: 'presentation', type: CommandConfiguration.PresentationOptions }, { property: 'problemMatchers' }
{ property: 'presentation', type: CommandConfiguration.PresentationOptions }, { property: 'problemMatchers' },
{ property: 'options' }
];
export function from(this: void, external: ConfigurationProperties & { [key: string]: any; }, context: ParseContext, includeCommandOptions: boolean, properties?: IJSONSchemaMap): Tasks.ConfigurationProperties | undefined {
......
......@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import { Action } from 'vs/base/common/actions';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import * as nls from 'vs/nls';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
export class ToggleDevToolsAction extends Action {
......@@ -27,11 +27,11 @@ export class ToggleSharedProcessAction extends Action {
static readonly ID = 'workbench.action.toggleSharedProcess';
static LABEL = nls.localize('toggleSharedProcess', "Toggle Shared Process");
constructor(id: string, label: string, @IWindowsService private readonly windowsService: IWindowsService) {
constructor(id: string, label: string, @ISharedProcessService private readonly sharedProcessService: ISharedProcessService) {
super(id, label);
}
run(): Promise<void> {
return this.windowsService.toggleSharedProcess();
return this.sharedProcessService.toggleSharedProcessWindow();
}
}
......@@ -258,25 +258,25 @@ export class QuickSwitchWindow extends BaseSwitchWindow {
}
export const NewWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) {
return accessor.get(IWindowsService).newWindowTab();
return accessor.get(IElectronService).newWindowTab();
};
export const ShowPreviousWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) {
return accessor.get(IWindowsService).showPreviousWindowTab();
return accessor.get(IElectronService).showPreviousWindowTab();
};
export const ShowNextWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) {
return accessor.get(IWindowsService).showNextWindowTab();
return accessor.get(IElectronService).showNextWindowTab();
};
export const MoveWindowTabToNewWindowHandler: ICommandHandler = function (accessor: ServicesAccessor) {
return accessor.get(IWindowsService).moveWindowTabToNewWindow();
return accessor.get(IElectronService).moveWindowTabToNewWindow();
};
export const MergeWindowTabsHandlerHandler: ICommandHandler = function (accessor: ServicesAccessor) {
return accessor.get(IWindowsService).mergeAllWindowTabs();
return accessor.get(IElectronService).mergeAllWindowTabs();
};
export const ToggleWindowTabsBarHandler: ICommandHandler = function (accessor: ServicesAccessor) {
return accessor.get(IWindowsService).toggleWindowTabsBar();
return accessor.get(IElectronService).toggleWindowTabsBar();
};
......@@ -10,7 +10,6 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { INotificationService } from 'vs/platform/notification/common/notification';
export class SaveWorkspaceAsAction extends Action {
......@@ -69,29 +68,3 @@ export class DuplicateWorkspaceInNewWindowAction extends Action {
return this.windowService.openWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true });
}
}
export class CloseWorkspaceAction extends Action {
static readonly ID = 'workbench.action.closeFolder';
static LABEL = nls.localize('closeWorkspace', "Close Workspace");
constructor(
id: string,
label: string,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@INotificationService private readonly notificationService: INotificationService,
@IWindowService private readonly windowService: IWindowService
) {
super(id, label);
}
run(): Promise<void> {
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
this.notificationService.info(nls.localize('noWorkspaceOpened', "There is currently no workspace opened in this instance to close."));
return Promise.resolve(undefined);
}
return this.windowService.closeWorkspace();
}
}
......@@ -9,30 +9,24 @@ import * as os from 'os';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
import { ToggleSharedProcessAction, ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions';
import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseCurrentWindowAction, SwitchWindow, QuickSwitchWindow, RestartWithExtensionsDisabledAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-browser/actions/windowActions';
import { SaveWorkspaceAsAction, DuplicateWorkspaceInNewWindowAction, CloseWorkspaceAction } from 'vs/workbench/electron-browser/actions/workspaceActions';
import { SaveWorkspaceAsAction, DuplicateWorkspaceInNewWindowAction } from 'vs/workbench/electron-browser/actions/workspaceActions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext, WorkbenchStateContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys';
import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext } from 'vs/workbench/browser/contextkeys';
import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor';
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IElectronService } from 'vs/platform/electron/node/electron';
// Actions
(function registerActions(): void {
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
// Actions: File
(function registerFileActions(): void {
const fileCategory = nls.localize('file', "File");
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory, SupportsWorkspacesContext);
})();
// Actions: View
(function registerViewActions(): void {
const viewCategory = nls.localize('view', "View");
......@@ -63,8 +57,8 @@ import { IWindowService, IWindowsService } from 'vs/platform/windows/common/wind
id: 'workbench.action.quit',
weight: KeybindingWeight.WorkbenchContrib,
handler(accessor: ServicesAccessor) {
const windowsService = accessor.get(IWindowsService);
windowsService.quit();
const electronService = accessor.get(IElectronService);
electronService.quit();
},
when: undefined,
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_Q },
......@@ -130,27 +124,6 @@ import { IWindowService, IWindowsService } from 'vs/platform/windows/common/wind
when: SupportsWorkspacesContext
});
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '6_close',
command: {
id: CloseWorkspaceAction.ID,
title: nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"),
precondition: WorkspaceFolderCountContext.notEqualsTo('0')
},
order: 3,
when: WorkbenchStateContext.notEqualsTo('workspace')
});
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '6_close',
command: {
id: CloseWorkspaceAction.ID,
title: nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace")
},
order: 3,
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), SupportsWorkspacesContext)
});
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '6_close',
command: {
......
......@@ -59,6 +59,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron';
import { posix, dirname } from 'vs/base/common/path';
import { getBaseLabel } from 'vs/base/common/labels';
import { ITunnelService, extractLocalHostUriMetaDataForPortMapping } from 'vs/platform/remote/common/tunnel';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
const TextInputActions: IAction[] = [
new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))),
......@@ -88,7 +89,6 @@ export class ElectronWindow extends Disposable {
constructor(
@IEditorService private readonly editorService: EditorServiceImpl,
@IWindowsService private readonly windowsService: IWindowsService,
@IWindowService private readonly windowService: IWindowService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ITitleService private readonly titleService: ITitleService,
......@@ -111,6 +111,7 @@ export class ElectronWindow extends Disposable {
@IOpenerService private readonly openerService: IOpenerService,
@IElectronService private readonly electronService: IElectronService,
@ITunnelService private readonly tunnelService: ITunnelService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
) {
super();
......@@ -264,6 +265,17 @@ export class ElectronWindow extends Disposable {
this.provideCustomTitleContextMenu(file ? file.fsPath : undefined);
}));
}
// Maximize/Restore on doubleclick (for macOS custom title)
if (isMacintosh && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
const titlePart = this.layoutService.getContainer(Parts.TITLEBAR_PART);
this._register(DOM.addDisposableListener(titlePart, DOM.EventType.DBLCLICK, e => {
DOM.EventHelper.stop(e);
this.electronService.handleTitleDoubleClick();
}));
}
}
private onDidVisibleEditorsChange(): void {
......@@ -426,7 +438,7 @@ export class ElectronWindow extends Disposable {
// the main process to prevent window focus issues.
if (this.shouldOpenExternal(resource, options)) {
const { resolved } = await this.openerService.resolveExternalUri(resource);
const success = await this.windowsService.openExternal(encodeURI(resolved.toString(true)));
const success = await this.electronService.openExternal(encodeURI(resolved.toString(true)));
if (!success && resolved.scheme === Schemas.file) {
// if opening failed, and this is a file, we can still try to reveal it
await this.electronService.showItemInFolder(resolved.fsPath);
......@@ -526,7 +538,7 @@ export class ElectronWindow extends Disposable {
// Only update if the actions have changed
if (!equals(this.lastInstalledTouchedBar, items)) {
this.lastInstalledTouchedBar = items;
this.windowService.updateTouchBar(items);
this.electronService.updateTouchBar(items);
}
}
......@@ -554,7 +566,7 @@ export class ElectronWindow extends Disposable {
crashReporter.start(deepClone(options));
// start crash reporter in the main process
return this.windowsService.startCrashReporter(options);
return this.electronService.startCrashReporter(options);
}
private onAddFoldersRequest(request: IAddFoldersRequest): void {
......
......@@ -70,6 +70,10 @@ export class BrowserHostService implements IHostService {
async reload(): Promise<void> {
window.location.reload();
}
async closeWorkspace(): Promise<void> {
return this.openEmptyWindow({ reuse: true });
}
}
registerSingleton(IHostService, BrowserHostService, true);
......@@ -24,14 +24,30 @@ export interface IHostService {
*/
openEmptyWindow(options?: { reuse?: boolean, remoteAuthority?: string }): Promise<void>;
/**
* Switch between fullscreen and normal window.
*/
toggleFullScreen(): Promise<void>;
//#endregion
//#region Lifecycle
/**
* Restart the entire application.
*/
restart(): Promise<void>;
/**
* Reload the currently active window.
*/
reload(): Promise<void>;
/**
* Closes the currently opened folder/workspace and returns to an empty
* window.
*/
closeWorkspace(): Promise<void>;
//#endregion
}
......@@ -34,6 +34,10 @@ export class DesktopHostService implements IHostService {
reload(): Promise<void> {
return this.electronService.reload();
}
closeWorkspace(): Promise<void> {
return this.electronService.closeWorkpsace();
}
}
registerSingleton(IHostService, DesktopHostService, true);
......@@ -6,7 +6,6 @@
import { Event } from 'vs/base/common/event';
import { IWindowService, IWindowsService, IEnterWorkspaceResult, IOpenSettings, IURIToOpen, isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows';
import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { URI } from 'vs/base/common/uri';
import { Disposable } from 'vs/base/common/lifecycle';
import { ILabelService } from 'vs/platform/label/common/label';
......@@ -52,10 +51,6 @@ export class WindowService extends Disposable implements IWindowService {
return this._windowId;
}
closeWorkspace(): Promise<void> {
return this.windowsService.closeWorkspace(this.windowId);
}
enterWorkspace(path: URI): Promise<IEnterWorkspaceResult | undefined> {
return this.windowsService.enterWorkspace(this.windowId, path);
}
......@@ -108,14 +103,6 @@ export class WindowService extends Disposable implements IWindowService {
return this.windowsService.minimizeWindow(this.windowId);
}
onWindowTitleDoubleClick(): Promise<void> {
return this.windowsService.onWindowTitleDoubleClick(this.windowId);
}
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void> {
return this.windowsService.updateTouchBar(this.windowId, items);
}
private getRecentLabel(u: IURIToOpen): string {
if (isFolderToOpen(u)) {
return this.labelService.getWorkspaceLabel(u.folderUri, { verbose: true });
......
......@@ -35,17 +35,17 @@ import { IModeService } from 'vs/editor/common/services/modeService';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IWindowsService, IWindowService, IEnterWorkspaceResult, MenuBarVisibility, IURIToOpen, IOpenSettings, IWindowConfiguration, CrashReporterStartOptions } from 'vs/platform/windows/common/windows';
import { IWindowsService, IWindowService, IEnterWorkspaceResult, MenuBarVisibility, IURIToOpen, IOpenSettings, IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
import { IPosition, Position as EditorPosition } from 'vs/editor/common/core/position';
import { IMenuService, MenuId, IMenu, ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MockContextKeyService, MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { ITextBufferFactory, DefaultEndOfLine, EndOfLinePreference, IModelDecorationOptions, ITextModel, ITextSnapshot } from 'vs/editor/common/model';
......@@ -71,7 +71,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { ViewletDescriptor, Viewlet } from 'vs/workbench/browser/viewlet';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage';
import { isLinux, isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
import { LabelService } from 'vs/workbench/services/label/common/labelService';
import { IDimension } from 'vs/platform/layout/browser/layoutService';
import { Part } from 'vs/workbench/browser/part';
......@@ -1196,10 +1196,6 @@ export class TestWindowService implements IWindowService {
return Promise.resolve(false);
}
closeWorkspace(): Promise<void> {
return Promise.resolve();
}
enterWorkspace(_path: URI): Promise<IEnterWorkspaceResult | undefined> {
return Promise.resolve(undefined);
}
......@@ -1242,14 +1238,6 @@ export class TestWindowService implements IWindowService {
closeWindow(): Promise<void> {
return Promise.resolve();
}
onWindowTitleDoubleClick(): Promise<void> {
return Promise.resolve();
}
updateTouchBar(_items: ISerializableCommandAction[][]): Promise<void> {
return Promise.resolve();
}
}
export class TestLifecycleService implements ILifecycleService {
......@@ -1306,10 +1294,6 @@ export class TestWindowsService implements IWindowsService {
return Promise.resolve(false);
}
closeWorkspace(_windowId: number): Promise<void> {
return Promise.resolve();
}
enterWorkspace(_windowId: number, _path: URI): Promise<IEnterWorkspaceResult | undefined> {
return Promise.resolve(undefined);
}
......@@ -1357,77 +1341,18 @@ export class TestWindowsService implements IWindowsService {
return Promise.resolve();
}
onWindowTitleDoubleClick(_windowId: number): Promise<void> {
return Promise.resolve();
}
quit(): Promise<void> {
return Promise.resolve();
}
whenSharedProcessReady(): Promise<void> {
return Promise.resolve();
}
toggleSharedProcess(): Promise<void> {
return Promise.resolve();
}
// Global methods
openWindow(_windowId: number, _uris: IURIToOpen[], _options: IOpenSettings): Promise<void> {
return Promise.resolve();
}
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
return Promise.resolve();
}
getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {
throw new Error('not implemented');
}
newWindowTab(): Promise<void> {
return Promise.resolve();
}
showPreviousWindowTab(): Promise<void> {
return Promise.resolve();
}
showNextWindowTab(): Promise<void> {
return Promise.resolve();
}
moveWindowTabToNewWindow(): Promise<void> {
return Promise.resolve();
}
mergeAllWindowTabs(): Promise<void> {
return Promise.resolve();
}
toggleWindowTabsBar(): Promise<void> {
return Promise.resolve();
}
updateTouchBar(_windowId: number, _items: ISerializableCommandAction[][]): Promise<void> {
return Promise.resolve();
}
getActiveWindowId(): Promise<number | undefined> {
return Promise.resolve(undefined);
}
// This needs to be handled from browser process to prevent
// foreground ordering issues on Windows
openExternal(_url: string): Promise<boolean> {
return Promise.resolve(true);
}
// TODO: this is a bit backwards
startCrashReporter(_config: CrashReporterStartOptions): Promise<void> {
return Promise.resolve();
}
}
export class TestTextResourceConfigurationService implements ITextResourceConfigurationService {
......@@ -1478,6 +1403,9 @@ export class TestSharedProcessService implements ISharedProcessService {
}
registerChannel(channelName: string, channel: any): void { }
async toggleSharedProcessWindow(): Promise<void> { }
async whenSharedProcessReady(): Promise<void> { }
}
export class RemoteFileSystemProvider implements IFileSystemProvider {
......@@ -1517,10 +1445,11 @@ export class TestHostService implements IHostService {
windowCount = Promise.resolve(1);
restart(): Promise<void> { return Promise.resolve(); }
reload(): Promise<void> { return Promise.resolve(); }
async restart(): Promise<void> { }
async reload(): Promise<void> { }
async closeWorkspace(): Promise<void> { }
openEmptyWindow(options?: { reuse?: boolean, remoteAuthority?: string }): Promise<void> { return Promise.resolve(); }
async openEmptyWindow(options?: { reuse?: boolean, remoteAuthority?: string }): Promise<void> { }
toggleFullScreen(): Promise<void> { return Promise.resolve(); }
async toggleFullScreen(): Promise<void> { }
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册