Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

joh/cruel hoverfly #155276

Merged
merged 5 commits into from
Jul 15, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export class MenuId {
static readonly TestPeekTitle = new MenuId('TestPeekTitle');
static readonly TouchBarContext = new MenuId('TouchBarContext');
static readonly TitleBarContext = new MenuId('TitleBarContext');
static readonly TitleBarTitleContext = new MenuId('TitleBarTitleContext');
static readonly TunnelContext = new MenuId('TunnelContext');
static readonly TunnelPrivacy = new MenuId('TunnelPrivacy');
static readonly TunnelProtocol = new MenuId('TunnelProtocol');
Expand Down
2 changes: 2 additions & 0 deletions src/vs/platform/native/common/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export interface ICommonNativeHostService {

readonly onDidChangePassword: Event<{ service: string; account: string }>;

readonly onDidTriggerSystemContextMenu: Event<{ windowId: number; x: number; y: number }>;

// Window
getWindows(): Promise<IOpenedWindow[]>;
getWindowCount(): Promise<number>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
//#region Events

readonly onDidOpenWindow = Event.map(this.windowsMainService.onDidOpenWindow, window => window.id);
readonly onDidTriggerSystemContextMenu = Event.filter(Event.map(this.windowsMainService.onDidTriggerSystemContextMenu, ({ window, x, y }) => { return { windowId: window.id, x, y }; }), ({ windowId }) => !!this.windowsMainService.getWindowById(windowId));

readonly onDidMaximizeWindow = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-maximize', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId));
readonly onDidUnmaximizeWindow = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-unmaximize', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId));
Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/window/electron-main/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface ICodeWindow extends IDisposable {

readonly onWillLoad: Event<ILoadEvent>;
readonly onDidSignalReady: Event<void>;
readonly onDidTriggerSystemContextMenu: Event<{ x: number; y: number }>;
readonly onDidClose: Event<void>;
readonly onDidDestroy: Event<void>;

Expand Down
19 changes: 19 additions & 0 deletions src/vs/platform/windows/electron-main/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ export class CodeWindow extends Disposable implements ICodeWindow {
private readonly _onDidSignalReady = this._register(new Emitter<void>());
readonly onDidSignalReady = this._onDidSignalReady.event;

private readonly _onDidTriggerSystemContextMenu = this._register(new Emitter<{ x: number; y: number }>());
readonly onDidTriggerSystemContextMenu = this._onDidTriggerSystemContextMenu.event;

private readonly _onDidClose = this._register(new Emitter<void>());
readonly onDidClose = this._onDidClose.event;

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

// Windows Custom System Context Menu
// See https://github.com/electron/electron/issues/24893
if (isWindows && useCustomTitleStyle) {
const WM_INITMENU = 0x0116;
this._win.hookWindowMessage(WM_INITMENU, () => {
const [x, y] = this._win.getPosition();
const cursorPos = screen.getCursorScreenPoint();

this._win.setEnabled(false);
this._win.setEnabled(true);
Comment on lines +300 to +301
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These end up calling EnableWindow on windows with the toggled state https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow. What is the reasoning to disable the window ?


this._onDidTriggerSystemContextMenu.fire({ x: cursorPos.x - x, y: cursorPos.y - y });
return 0; // skip native menu
});
}

// TODO@electron (Electron 4 regression): when running on multiple displays where the target display
// to open the window has a larger resolution than the primary display, the window will not size
// correctly unless we set the bounds again (https://github.com/microsoft/vscode/issues/74872)
Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/windows/electron-main/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface IWindowsMainService {

readonly onDidOpenWindow: Event<ICodeWindow>;
readonly onDidSignalReadyWindow: Event<ICodeWindow>;
readonly onDidTriggerSystemContextMenu: Event<{ window: ICodeWindow; x: number; y: number }>;
readonly onDidDestroyWindow: Event<ICodeWindow>;

open(openConfig: IOpenConfiguration): ICodeWindow[];
Expand Down
4 changes: 4 additions & 0 deletions src/vs/platform/windows/electron-main/windowsMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
private readonly _onDidChangeWindowsCount = this._register(new Emitter<IWindowsCountChangedEvent>());
readonly onDidChangeWindowsCount = this._onDidChangeWindowsCount.event;

private readonly _onDidTriggerSystemContextMenu = this._register(new Emitter<{ window: ICodeWindow; x: number; y: number }>());
readonly onDidTriggerSystemContextMenu = this._onDidTriggerSystemContextMenu.event;

private readonly windowsStateHandler = this._register(new WindowsStateHandler(this, this.stateMainService, this.lifecycleMainService, this.logService, this.configurationService));

constructor(
Expand Down Expand Up @@ -1379,6 +1382,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
once(createdWindow.onDidSignalReady)(() => this._onDidSignalReadyWindow.fire(createdWindow));
once(createdWindow.onDidClose)(() => this.onWindowClosed(createdWindow));
once(createdWindow.onDidDestroy)(() => this._onDidDestroyWindow.fire(createdWindow));
createdWindow.onDidTriggerSystemContextMenu(({ x, y }) => this._onDidTriggerSystemContextMenu.fire({ window: createdWindow, x, y }));

const webContents = assertIsDefined(createdWindow.win?.webContents);
webContents.removeAllListeners('devtools-reload-page'); // remove built in listener so we can handle this on our own
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ suite('WindowsFinder', () => {
function createTestCodeWindow(options: { lastFocusTime: number; openedFolderUri?: URI; openedWorkspace?: IWorkspaceIdentifier }): ICodeWindow {
return new class implements ICodeWindow {
onWillLoad: Event<ILoadEvent> = Event.None;
onDidTriggerSystemContextMenu: Event<{ x: number; y: number }> = Event.None;
onDidSignalReady: Event<void> = Event.None;
onDidClose: Event<void> = Event.None;
onDidDestroy: Event<void> = Event.None;
Expand Down
3 changes: 3 additions & 0 deletions src/vs/workbench/browser/actions/layoutActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,9 @@ if (isWindows || isLinux || isWeb) {
id: MenuId.MenubarAppearanceMenu,
group: '2_workbench_layout',
order: 0
}, {
id: MenuId.TitleBarContext,
order: 0
}]
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@
width: 35px;
height: 100%;
position: relative;
z-index: 3000;
z-index: 2500;
flex-shrink: 0;
}

Expand Down
87 changes: 44 additions & 43 deletions src/vs/workbench/browser/parts/titlebar/titlebarPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ import { getZoomFactor } from 'vs/base/browser/browser';
import { MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/window/common/window';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IAction, toAction } from 'vs/base/common/actions';
import { IAction } from 'vs/base/common/actions';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
import { IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER, WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme';
import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform';
import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform';
import { Color } from 'vs/base/common/color';
import { EventType, EventHelper, Dimension, isAncestor, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame, prepend, reset } from 'vs/base/browser/dom';
import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { Emitter, Event } from 'vs/base/common/event';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { createActionViewItem, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenuService, IMenu, MenuId } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Action2, IMenuService, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { Codicon } from 'vs/base/common/codicons';
import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry';
Expand Down Expand Up @@ -82,8 +82,6 @@ export class TitlebarPart extends Part implements ITitleService {

private readonly windowTitle: WindowTitle;

private readonly contextMenu: IMenu;

constructor(
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IConfigurationService protected readonly configurationService: IConfigurationService,
Expand All @@ -99,7 +97,6 @@ export class TitlebarPart extends Part implements ITitleService {
) {
super(Parts.TITLEBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
this.windowTitle = this._register(instantiationService.createInstance(WindowTitle));
this.contextMenu = this._register(menuService.createMenu(MenuId.TitleBarContext, contextKeyService));

this.titleBarStyle = getTitleBarStyle(this.configurationService);

Expand Down Expand Up @@ -276,13 +273,6 @@ export class TitlebarPart extends Part implements ITitleService {
allowContextMenu: true
});

this._register(addDisposableListener(this.layoutControls, EventType.CONTEXT_MENU, e => {
EventHelper.stop(e);

this.onLayoutControlContextMenu(e, this.layoutControls!);
}));


const menu = this._register(this.menuService.createMenu(MenuId.LayoutControlMenu, this.contextKeyService));
const updateLayoutMenu = () => {
if (!this.layoutToolbar) {
Expand All @@ -305,11 +295,10 @@ export class TitlebarPart extends Part implements ITitleService {

// Context menu on title
[EventType.CONTEXT_MENU, EventType.MOUSE_DOWN].forEach(event => {
this._register(addDisposableListener(this.title, event, e => {
this._register(addDisposableListener(this.rootContainer, event, e => {
if (e.type === EventType.CONTEXT_MENU || e.metaKey) {
EventHelper.stop(e);

this.onContextMenu(e);
this.onContextMenu(e, e.target === this.title ? MenuId.TitleBarTitleContext : MenuId.TitleBarContext);
}
}));
});
Expand Down Expand Up @@ -380,42 +369,23 @@ export class TitlebarPart extends Part implements ITitleService {
}
}

private onContextMenu(e: MouseEvent): void {
protected onContextMenu(e: MouseEvent, menuId: MenuId): void {
// Find target anchor
const event = new StandardMouseEvent(e);
const anchor = { x: event.posx, y: event.posy };

// Fill in contributed actions
const menu = this.menuService.createMenu(menuId, this.contextKeyService);
const actions: IAction[] = [];
const actionsDisposable = createAndFillInContextMenuActions(this.contextMenu, undefined, actions);

// Show it
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => actions,
onHide: () => dispose(actionsDisposable)
});
}

private onLayoutControlContextMenu(e: MouseEvent, el: HTMLElement): void {
// Find target anchor
const event = new StandardMouseEvent(e);
const anchor = { x: event.posx, y: event.posy };

const actions: IAction[] = [];
actions.push(toAction({
id: 'layoutControl.hide',
label: localize('layoutControl.hide', "Hide Layout Control"),
run: () => {
this.configurationService.updateValue('workbench.layoutControl.enabled', false);
}
}));
const actionsDisposable = createAndFillInContextMenuActions(menu, undefined, actions);
menu.dispose();

// Show it
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => actions,
domForShadowRoot: el
onHide: () => dispose(actionsDisposable),
domForShadowRoot: isMacintosh && isNative ? event.target : undefined
});
}

Expand Down Expand Up @@ -499,3 +469,34 @@ registerThemingParticipant((theme, collector) => {
`);
}
});


class ToogleConfigAction extends Action2 {

constructor(private readonly section: string, title: string, order: number) {
super({
id: `toggle.${section}`,
title,
toggled: ContextKeyExpr.equals(`config.${section}`, true),
menu: { id: MenuId.TitleBarContext, order }
});
}

run(accessor: ServicesAccessor, ...args: any[]): void {
const configService = accessor.get(IConfigurationService);
const value = configService.getValue(this.section);
configService.updateValue(this.section, !value);
}
}

registerAction2(class ToogleCommandCenter extends ToogleConfigAction {
constructor() {
super('window.commandCenter', localize('toggle.commandCenter', 'Show Command Center'), 1);
}
});

registerAction2(class ToogleLayoutControl extends ToogleConfigAction {
constructor() {
super('workbench.layoutControl.enabled', localize('toggle.layout', 'Show Layout Controls'), 2);
}
});
15 changes: 14 additions & 1 deletion src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { isMacintosh, isWindows, isLinux } from 'vs/base/common/platform';
import { IMenuService } from 'vs/platform/actions/common/actions';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { TitlebarPart as BrowserTitleBarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IThemeService } from 'vs/platform/theme/common/themeService';
Expand Down Expand Up @@ -195,6 +195,19 @@ export class TitlebarPart extends BrowserTitleBarPart {

this._register(this.layoutService.onDidChangeWindowMaximized(maximized => this.onDidChangeWindowMaximized(maximized)));
this.onDidChangeWindowMaximized(this.layoutService.isWindowMaximized());

// Window System Context Menu
// See https://github.com/electron/electron/issues/24893
if (isWindows) {
this._register(this.nativeHostService.onDidTriggerSystemContextMenu(({ windowId, x, y }) => {
if (this.nativeHostService.windowId !== windowId) {
return;
}

const zoomFactor = getZoomFactor();
this.onContextMenu(new MouseEvent('mouseup', { clientX: x / zoomFactor, clientY: y / zoomFactor }), MenuId.TitleBarContext);
}));
}
}

return ret;
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/electron-sandbox/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ export class NativeWindow extends Disposable {

const commandId = `workbench.action.revealPathInFinder${i}`;
this.customTitleContextMenuDisposable.add(CommandsRegistry.registerCommand(commandId, () => this.nativeHostService.showItemInFolder(path.fsPath)));
this.customTitleContextMenuDisposable.add(MenuRegistry.appendMenuItem(MenuId.TitleBarContext, { command: { id: commandId, title: label || posix.sep }, order: -i }));
this.customTitleContextMenuDisposable.add(MenuRegistry.appendMenuItem(MenuId.TitleBarTitleContext, { command: { id: commandId, title: label || posix.sep }, order: -i }));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ export class TestNativeHostService implements INativeHostService {
onDidResumeOS: Event<unknown> = Event.None;
onDidChangeColorScheme = Event.None;
onDidChangePassword = Event.None;
onDidTriggerSystemContextMenu: Event<{ windowId: number; x: number; y: number }> = Event.None;
onDidChangeDisplay = Event.None;

windowCount = Promise.resolve(1);
Expand Down