提交 269ae60a 编写于 作者: B Benjamin Pasero 提交者: GitHub

Support actions to show up in the macOS touchbar (#34574)

上级 a39f593a
......@@ -7617,7 +7617,7 @@ declare namespace Electron {
}
interface TouchBarConstructorOptions {
items: TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer;
items: (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer)[];
escapeItem?: TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer;
}
......
......@@ -11,7 +11,7 @@ import { stopProfiling } from 'vs/base/node/profiler';
import nls = require('vs/nls');
import URI from 'vs/base/common/uri';
import { IStorageService } from 'vs/platform/storage/node/storage';
import { shell, screen, BrowserWindow, systemPreferences, app } from 'electron';
import { shell, screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage } from 'electron';
import { TPromise, TValueCallback } from 'vs/base/common/winjs.base';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { ILogService } from 'vs/platform/log/common/log';
......@@ -26,6 +26,7 @@ import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces';
import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { ICommandAction } from 'vs/platform/actions/common/actions';
export interface IWindowState {
width?: number;
......@@ -857,6 +858,51 @@ export class CodeWindow implements ICodeWindow {
this._win.webContents.send(channel, ...args);
}
public updateTouchBar(items: ICommandAction[][]): void {
if (!isMacintosh) {
return; // only supported on macOS
}
const groups: (Electron.TouchBarGroup | Electron.TouchBarSpacer)[] = [];
items.forEach(itemGroup => {
if (itemGroup.length) {
// Group Segments
const groupSegments = itemGroup.map(item => {
let icon: Electron.NativeImage;
if (item.iconPath) {
icon = nativeImage.createFromPath(item.iconPath);
if (icon.isEmpty()) {
icon = void 0;
}
}
return {
label: !icon ? item.title as string : void 0,
icon
};
});
// Group Touch Bar
const groupTouchBar = new TouchBar.TouchBarSegmentedControl({
segments: groupSegments,
mode: 'buttons',
segmentStyle: 'automatic',
change: (selectedIndex) => {
this.sendWhenReady('vscode:runAction', itemGroup[selectedIndex].id);
}
});
// Push and add small space between groups
groups.push(groupTouchBar);
groups.push(new TouchBar.TouchBarSpacer({ size: 'small' }));
}
});
this._win.setTouchBar(new TouchBar({ items: groups }));
}
public dispose(): void {
if (this.showTimeoutHandle) {
clearTimeout(this.showTimeoutHandle);
......
......@@ -1306,8 +1306,6 @@ export class WindowsManager implements IWindowsMainService {
this.workspacesManager.openWorkspace(win);
}
private onBeforeWindowUnload(e: IWindowUnloadEvent): void {
const windowClosing = (e.reason === UnloadReason.CLOSE);
const windowLoading = (e.reason === UnloadReason.LOAD);
......
......@@ -24,6 +24,7 @@ export interface ICommandAction {
title: string | ILocalizedString;
category?: string | ILocalizedString;
iconClass?: string;
iconPath?: string;
}
export interface IMenuItem {
......@@ -52,6 +53,7 @@ export class MenuId {
static readonly CommandPalette = new MenuId('14');
static readonly ViewTitle = new MenuId('15');
static readonly ViewItemContext = new MenuId('16');
static readonly TouchBarContext = new MenuId('17');
constructor(private _id: string) {
......
......@@ -30,6 +30,7 @@ namespace schema {
export function parseMenuId(value: string): MenuId {
switch (value) {
case 'commandPalette': return MenuId.CommandPalette;
case 'touchBar': return MenuId.TouchBarContext;
case 'editor/title': return MenuId.EditorTitle;
case 'editor/context': return MenuId.EditorContext;
case 'explorer/context': return MenuId.ExplorerContext;
......@@ -104,6 +105,11 @@ namespace schema {
type: 'array',
items: menuItem
},
'touchBar': {
description: localize('menus.touchBar', "The touch bar (macOS only)"),
type: 'array',
items: menuItem
},
'editor/title': {
description: localize('menus.editorTitle', "The editor title menu"),
type: 'array',
......@@ -278,20 +284,23 @@ ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.I
let { icon, category, title, command } = userFriendlyCommand;
let iconClass: string;
let iconPath: string;
if (icon) {
iconClass = ids.nextId();
if (typeof icon === 'string') {
const path = join(extension.description.extensionFolderPath, icon);
createCSSRule(`.icon.${iconClass}`, `background-image: url("${URI.file(path).toString()}")`);
iconPath = join(extension.description.extensionFolderPath, icon);
createCSSRule(`.icon.${iconClass}`, `background-image: url("${URI.file(iconPath).toString()}")`);
} else {
const light = join(extension.description.extensionFolderPath, icon.light);
const dark = join(extension.description.extensionFolderPath, icon.dark);
createCSSRule(`.icon.${iconClass}`, `background-image: url("${URI.file(light).toString()}")`);
createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: url("${URI.file(dark).toString()}")`);
iconPath = join(extension.description.extensionFolderPath, icon.dark);
}
}
if (MenuRegistry.addCommand({ id: command, title, category, iconClass })) {
if (MenuRegistry.addCommand({ id: command, title, category, iconClass, iconPath })) {
extension.collector.info(localize('dup', "Command `{0}` appears multiple times in the `commands` section.", userFriendlyCommand.command));
}
}
......
......@@ -13,6 +13,7 @@ import { IProcessEnvironment } from 'vs/base/common/platform';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IRecentlyOpened } from 'vs/platform/history/common/history';
import { ICommandAction } from 'vs/platform/actions/common/actions';
export const IWindowsService = createDecorator<IWindowsService>('windowsService');
......@@ -68,6 +69,9 @@ export interface IWindowsService {
mergeAllWindowTabs(): TPromise<void>;
toggleWindowTabsBar(): TPromise<void>;
// macOS TouchBar
updateTouchBar(windowId: number, items: ICommandAction[][]): TPromise<void>;
// Shared process
whenSharedProcessReady(): TPromise<void>;
toggleSharedProcess(): TPromise<void>;
......@@ -106,6 +110,7 @@ export interface IWindowService {
toggleDevTools(): TPromise<void>;
closeWorkspace(): TPromise<void>;
openWorkspace(): TPromise<void>;
updateTouchBar(items: ICommandAction[][]): TPromise<void>;
createAndOpenWorkspace(folders?: string[], path?: string): TPromise<void>;
saveAndOpenWorkspace(path: string): TPromise<void>;
toggleFullScreen(): TPromise<void>;
......
......@@ -11,6 +11,7 @@ import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/i
import { IWindowsService, INativeOpenDialogOptions } from './windows';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IRecentlyOpened } from 'vs/platform/history/common/history';
import { ICommandAction } from 'vs/platform/actions/common/actions';
export interface IWindowsChannel extends IChannel {
call(command: 'event:onWindowOpen'): TPromise<number>;
......@@ -36,6 +37,7 @@ export interface IWindowsChannel extends IChannel {
call(command: 'moveWindowTabToNewWindow', arg: number): TPromise<void>;
call(command: 'mergeAllWindowTabs', arg: number): TPromise<void>;
call(command: 'toggleWindowTabsBar', arg: number): TPromise<void>;
call(command: 'updateTouchBar', arg: [number, ICommandAction[][]]): TPromise<void>;
call(command: 'focusWindow', arg: number): TPromise<void>;
call(command: 'closeWindow', arg: number): TPromise<void>;
call(command: 'isFocused', arg: number): TPromise<boolean>;
......@@ -97,6 +99,7 @@ export class WindowsChannel implements IWindowsChannel {
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);
......@@ -306,4 +309,8 @@ export class WindowsChannelClient implements IWindowsService {
startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise<void> {
return this.channel.call('startCrashReporter', config);
}
updateTouchBar(windowId: number, items: ICommandAction[][]): TPromise<void> {
return this.channel.call('updateTouchBar', [windowId, items]);
}
}
......@@ -10,6 +10,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { IWindowService, IWindowsService, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows';
import { remote } from 'electron';
import { IRecentlyOpened } from 'vs/platform/history/common/history';
import { ICommandAction } from 'vs/platform/actions/common/actions';
export class WindowService implements IWindowService {
......@@ -143,4 +144,8 @@ export class WindowService implements IWindowService {
return remote.dialog.showOpenDialog(remote.getCurrentWindow(), options); // https://github.com/electron/electron/issues/4936
}
updateTouchBar(items: ICommandAction[][]): TPromise<void> {
return this.windowsService.updateTouchBar(this.windowId, items);
}
}
......@@ -12,6 +12,7 @@ import Event from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { ICommandAction } from 'vs/platform/actions/common/actions';
export interface ICodeWindow {
id: number;
......@@ -35,6 +36,8 @@ export interface ICodeWindow {
setRepresentedFilename(name: string): void;
getRepresentedFilename(): string;
onWindowTitleDoubleClick(): void;
updateTouchBar(items: ICommandAction[][]): void;
}
export const IWindowsMainService = createDecorator<IWindowsMainService>('windowsMainService');
......
......@@ -19,6 +19,7 @@ import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycle
import { IWindowsMainService, ISharedProcess } from 'vs/platform/windows/electron-main/windows';
import { IHistoryMainService, IRecentlyOpened } from 'vs/platform/history/common/history';
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { ICommandAction } from 'vs/platform/actions/common/actions';
export class WindowsService implements IWindowsService, IDisposable {
......@@ -104,6 +105,16 @@ export class WindowsService implements IWindowsService, IDisposable {
return TPromise.as(null);
}
updateTouchBar(windowId: number, items: ICommandAction[][]): TPromise<void> {
const codeWindow = this.windowsMainService.getWindowById(windowId);
if (codeWindow) {
codeWindow.updateTouchBar(items);
}
return TPromise.as(null);
}
closeWorkspace(windowId: number): TPromise<void> {
const codeWindow = this.windowsMainService.getWindowById(windowId);
......
......@@ -24,7 +24,7 @@ import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/bina
import { ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import {
......@@ -39,6 +39,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
import { getQuickNavigateHandler, inQuickOpenContext } from 'vs/workbench/browser/parts/quickopen/quickopen';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { isMacintosh } from 'vs/base/common/platform';
// Register String Editor
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
......@@ -401,4 +402,17 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
// Editor Commands
editorCommands.setup();
\ No newline at end of file
editorCommands.setup();
// Touch Bar
if (isMacintosh) {
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconPath: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/back-tb.png')).fsPath },
group: 'navigation'
});
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconPath: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/forward-tb.png')).fsPath },
group: 'navigation'
});
}
\ No newline at end of file
......@@ -12,6 +12,7 @@ import errors = require('vs/base/common/errors');
import types = require('vs/base/common/types');
import { TPromise } from 'vs/base/common/winjs.base';
import arrays = require('vs/base/common/arrays');
import objects = require('vs/base/common/objects');
import DOM = require('vs/base/browser/dom');
import Severity from 'vs/base/common/severity';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
......@@ -41,6 +42,11 @@ import { Themable } from 'vs/workbench/common/theme';
import { ipcRenderer as ipc, webFrame } from 'electron';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
const TextInputActions: IAction[] = [
new Action('undo', nls.localize('undo', "Undo"), null, true, () => document.execCommand('undo') && TPromise.as(true)),
......@@ -57,6 +63,13 @@ export class ElectronWindow extends Themable {
private static AUTO_SAVE_SETTING = 'files.autoSave';
private touchBarUpdater: RunOnceScheduler;
private touchBarMenu: IMenu;
private touchBarDisposables: IDisposable[];
private lastInstalledTouchedBar: ICommandAction[][];
private previousConfiguredZoomLevel: number;
constructor(
shellContainer: HTMLElement,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
......@@ -78,22 +91,33 @@ export class ElectronWindow extends Themable {
@ITelemetryService private telemetryService: ITelemetryService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
@IFileService private fileService: IFileService
@IFileService private fileService: IFileService,
@IMenuService private menuService: IMenuService,
@IContextKeyService private contextKeyService: IContextKeyService
) {
super(themeService);
this.touchBarDisposables = [];
this.touchBarUpdater = new RunOnceScheduler(() => this.doSetupTouchbar(), 300);
this.toUnbind.push(this.touchBarUpdater);
this.registerListeners();
this.setup();
this.create();
}
private registerListeners(): void {
// React to editor input changes
this.editorGroupService.onEditorsChanged(() => {
const file = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
this.toUnbind.push(this.editorGroupService.onEditorsChanged(() => {
// Represented File Name
const file = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
this.titleService.setRepresentedFilename(file ? file.fsPath : '');
});
// Touch Bar
this.updateTouchbarMenu();
}));
// prevent opening a real URL inside the shell
[DOM.EventType.DRAG_OVER, DOM.EventType.DROP].forEach(event => {
......@@ -102,17 +126,6 @@ export class ElectronWindow extends Themable {
});
});
// Handle window.open() calls
const $this = this;
(<any>window).open = function (url: string, target: string, features: string, replace: boolean): any {
$this.windowsService.openExternal(url);
return null;
};
}
private setup(): void {
// Support runAction event
ipc.on('vscode:runAction', (event, actionId: string) => {
this.commandService.executeCommand(actionId, { from: 'menu' }).done(_ => {
......@@ -139,11 +152,6 @@ export class ElectronWindow extends Themable {
}, () => errors.onUnexpectedError);
});
// Send over all extension viewlets when extensions are ready
this.extensionService.onReady().then(() => {
ipc.send('vscode:extensionViewlets', JSON.stringify(this.viewletService.getViewlets().filter(v => !!v.extensionId).map(v => { return { id: v.id, label: v.name }; })));
});
ipc.on('vscode:reportError', (event, error) => {
if (error) {
const errorParsed = JSON.parse(error);
......@@ -158,11 +166,6 @@ export class ElectronWindow extends Themable {
// Support addFolders event if we have a workspace opened
ipc.on('vscode:addFolders', (event, request: IAddFoldersRequest) => this.onAddFolders(request));
// Emit event when vscode has loaded
this.partService.joinCreation().then(() => {
ipc.send('vscode:workbenchLoaded', this.windowService.getCurrentWindowId());
});
// Message support
ipc.on('vscode:showInfoMessage', (event, message: string) => {
this.messageService.show(Severity.Info, message);
......@@ -216,47 +219,134 @@ export class ElectronWindow extends Themable {
});
// Configuration changes
let previousConfiguredZoomLevel: number;
this.configurationService.onDidUpdateConfiguration(e => {
const windowConfig: IWindowsConfiguration = this.configurationService.getConfiguration<IWindowsConfiguration>();
this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onDidUpdateConfiguration(e)));
let newZoomLevel = 0;
if (windowConfig.window && typeof windowConfig.window.zoomLevel === 'number') {
newZoomLevel = windowConfig.window.zoomLevel;
// Context menu support in input/textarea
window.document.addEventListener('contextmenu', e => this.onContextMenu(e));
}
// Leave early if the configured zoom level did not change (https://github.com/Microsoft/vscode/issues/1536)
if (previousConfiguredZoomLevel === newZoomLevel) {
return;
}
private onContextMenu(e: PointerEvent): void {
if (e.target instanceof HTMLElement) {
const target = <HTMLElement>e.target;
if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) {
e.preventDefault();
e.stopPropagation();
previousConfiguredZoomLevel = newZoomLevel;
this.contextMenuService.showContextMenu({
getAnchor: () => e,
getActions: () => TPromise.as(TextInputActions)
});
}
}
}
private onDidUpdateConfiguration(e): void {
const windowConfig: IWindowsConfiguration = this.configurationService.getConfiguration<IWindowsConfiguration>();
let newZoomLevel = 0;
if (windowConfig.window && typeof windowConfig.window.zoomLevel === 'number') {
newZoomLevel = windowConfig.window.zoomLevel;
if (webFrame.getZoomLevel() !== newZoomLevel) {
webFrame.setZoomLevel(newZoomLevel);
browser.setZoomFactor(webFrame.getZoomFactor());
// See https://github.com/Microsoft/vscode/issues/26151
// Cannot be trusted because the webFrame might take some time
// until it really applies the new zoom level
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
// Leave early if the configured zoom level did not change (https://github.com/Microsoft/vscode/issues/1536)
if (this.previousConfiguredZoomLevel === newZoomLevel) {
return;
}
this.previousConfiguredZoomLevel = newZoomLevel;
}
if (webFrame.getZoomLevel() !== newZoomLevel) {
webFrame.setZoomLevel(newZoomLevel);
browser.setZoomFactor(webFrame.getZoomFactor());
// See https://github.com/Microsoft/vscode/issues/26151
// Cannot be trusted because the webFrame might take some time
// until it really applies the new zoom level
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
}
}
private create(): void {
// Handle window.open() calls
const $this = this;
(<any>window).open = function (url: string, target: string, features: string, replace: boolean): any {
$this.windowsService.openExternal(url);
return null;
};
// Send over all extension viewlets when extensions are ready
this.extensionService.onReady().then(() => {
ipc.send('vscode:extensionViewlets', JSON.stringify(this.viewletService.getViewlets().filter(v => !!v.extensionId).map(v => { return { id: v.id, label: v.name }; })));
});
// Context menu support in input/textarea
window.document.addEventListener('contextmenu', e => {
if (e.target instanceof HTMLElement) {
const target = <HTMLElement>e.target;
if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) {
e.preventDefault();
e.stopPropagation();
this.contextMenuService.showContextMenu({
getAnchor: () => e,
getActions: () => TPromise.as(TextInputActions)
});
// Emit event when vscode has loaded
this.partService.joinCreation().then(() => {
ipc.send('vscode:workbenchLoaded', this.windowService.getCurrentWindowId());
});
// Touchbar Support
this.updateTouchbarMenu();
}
private updateTouchbarMenu(): void {
if (!platform.isMacintosh) {
return; // macOS only
}
// Dispose old
this.touchBarDisposables = dispose(this.touchBarDisposables);
// Create new
this.touchBarMenu = this.editorGroupService.invokeWithinEditorContext(accessor => this.menuService.createMenu(MenuId.TouchBarContext, accessor.get(IContextKeyService)));
this.touchBarDisposables.push(this.touchBarMenu);
this.touchBarDisposables.push(this.touchBarMenu.onDidChange(() => {
this.scheduleSetupTouchbar();
}));
this.scheduleSetupTouchbar();
}
private scheduleSetupTouchbar(): void {
this.touchBarUpdater.schedule();
}
private doSetupTouchbar(): void {
const actions: (MenuItemAction | Separator)[] = [];
// Fill actions into groups respecting order
fillInActions(this.touchBarMenu, void 0, actions);
// Convert into command action multi array
const items: ICommandAction[][] = [];
let group: ICommandAction[] = [];
for (let i = 0; i < actions.length; i++) {
const action = actions[i];
// Command
if (action instanceof MenuItemAction) {
group.push(action.item);
}
// Separator
else if (action instanceof Separator) {
if (group.length) {
items.push(group);
}
group = [];
}
});
}
if (group.length) {
items.push(group);
}
// Only update if the actions have changed
if (!objects.equals(this.lastInstalledTouchedBar, items)) {
this.lastInstalledTouchedBar = items;
this.windowService.updateTouchBar(items);
}
}
private resolveKeybindings(actionIds: string[]): TPromise<{ id: string; label: string, isNative: boolean; }[]> {
......@@ -401,4 +491,10 @@ export class ElectronWindow extends Themable {
this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ElectronWindow.AUTO_SAVE_SETTING, value: newAutoSaveValue });
}
public dispose(): void {
this.touchBarDisposables = dispose(this.touchBarDisposables);
super.dispose();
}
}
......@@ -7,7 +7,7 @@ import 'vs/css!../browser/media/debug.contribution';
import 'vs/css!../browser/media/debugHover';
import * as nls from 'vs/nls';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { Registry } from 'vs/platform/registry/common/platform';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { KeybindingsRegistry, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
......@@ -17,7 +17,7 @@ import { ToggleViewletAction, Extensions as ViewletExtensions, ViewletRegistry,
import { TogglePanelAction, Extensions as PanelExtensions, PanelRegistry, PanelDescriptor } from 'vs/workbench/browser/panel';
import { VariablesView, WatchExpressionsView, CallStackView, BreakpointsView } from 'vs/workbench/parts/debug/electron-browser/debugViews';
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { IDebugService, VIEWLET_ID, REPL_ID, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA } from 'vs/workbench/parts/debug/common/debug';
import { IDebugService, VIEWLET_ID, REPL_ID, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA, CONTEXT_DEBUG_STATE } from 'vs/workbench/parts/debug/common/debug';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { DebugEditorModelManager } from 'vs/workbench/parts/debug/browser/debugEditorModelManager';
......@@ -35,6 +35,9 @@ import * as debugCommands from 'vs/workbench/parts/debug/electron-browser/debugC
import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
import { StatusBarColorProvider } from 'vs/workbench/parts/debug/electron-browser/statusbarColorProvider';
import { ViewLocation, ViewsRegistry } from 'vs/workbench/browser/parts/views/viewsRegistry';
import { isMacintosh } from 'vs/base/common/platform';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import URI from 'vs/base/common/uri';
class OpenDebugViewletAction extends ToggleViewletAction {
public static ID = VIEWLET_ID;
......@@ -183,3 +186,27 @@ configurationRegistry.registerConfiguration({
});
debugCommands.registerCommands();
// Touch Bar
if (isMacintosh) {
const registerTouchBarEntry = (id: string, title: string, order, when: ContextKeyExpr, icon: string) => {
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
command: {
id, title, iconPath: URI.parse(require.toUrl(`vs/workbench/parts/debug/electron-browser/media/${icon}`)).fsPath
},
when,
group: '9_debug',
order
});
};
registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_NOT_IN_DEBUG_MODE, 'continue-tb.png');
registerTouchBarEntry(ContinueAction.ID, ContinueAction.LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png');
registerTouchBarEntry(PauseAction.ID, PauseAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE, 'pause-tb.png');
registerTouchBarEntry(StepOverAction.ID, StepOverAction.LABEL, 2, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepover-tb.png');
registerTouchBarEntry(StepIntoAction.ID, StepIntoAction.LABEL, 3, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepinto-tb.png');
registerTouchBarEntry(StepOutAction.ID, StepOutAction.LABEL, 4, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepout-tb.png');
registerTouchBarEntry(RestartAction.ID, RestartAction.LABEL, 5, CONTEXT_IN_DEBUG_MODE, 'restart-tb.png');
registerTouchBarEntry(StopAction.ID, StopAction.LABEL, 6, CONTEXT_IN_DEBUG_MODE, 'stop-tb.png');
}
\ No newline at end of file
......@@ -26,6 +26,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { explorerItemToFileResource, ExplorerFocusCondition, FilesExplorerFocusCondition } from 'vs/workbench/parts/files/common/files';
import URI from 'vs/base/common/uri';
class FilesViewerActionContributor extends ActionBarContributor {
......@@ -339,4 +340,12 @@ function appendSaveConflictEditorTitleAction(id: string, title: string, iconClas
group: 'navigation',
order
});
}
// Touch Bar
if (isMacintosh) {
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
command: { id: GlobalNewUntitledFileAction.ID, title: GlobalNewUntitledFileAction.LABEL, iconPath: URI.parse(require.toUrl('vs/workbench/parts/files/browser/media/new-file-tb.png')).fsPath },
group: '1_modification'
});
}
\ No newline at end of file
......@@ -58,6 +58,7 @@ import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderW
import { IRecentlyOpened } from 'vs/platform/history/common/history';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { IPosition } from 'vs/editor/common/core/position';
import { ICommandAction } from 'vs/platform/actions/common/actions';
export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput {
return instantiationService.createInstance(FileEditorInput, resource, void 0);
......@@ -965,6 +966,10 @@ export class TestWindowService implements IWindowService {
showOpenDialog(options: Electron.OpenDialogOptions, callback?: (fileNames: string[]) => void): string[] {
return void 0;
}
updateTouchBar(items: ICommandAction[][]): Promise<void> {
return TPromise.as(void 0);
}
}
export class TestLifecycleService implements ILifecycleService {
......@@ -1171,6 +1176,10 @@ export class TestWindowsService implements IWindowsService {
return TPromise.as(void 0);
}
updateTouchBar(windowId: number, items: ICommandAction[][]): Promise<void> {
return TPromise.as(void 0);
}
// This needs to be handled from browser process to prevent
// foreground ordering issues on Windows
openExternal(url: string): TPromise<boolean> {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册