Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/vs/platform/native/common/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export interface ICommonNativeHostService {

handleTitleDoubleClick(): Promise<void>;

getCursorScreenPoint(): Promise<IPoint>;
getCursorScreenPoint(): Promise<{ readonly point: IPoint; readonly display: IRectangle }>;

isMaximized(): Promise<boolean>;
maximizeWindow(): Promise<void>;
Expand Down
7 changes: 5 additions & 2 deletions src/vs/platform/native/electron-main/nativeHostMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,11 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
window?.handleTitleDoubleClick();
}

async getCursorScreenPoint(windowId: number | undefined): Promise<IPoint> {
return screen.getCursorScreenPoint();
async getCursorScreenPoint(windowId: number | undefined): Promise<{ readonly point: IPoint; readonly display: IRectangle }> {
const point = screen.getCursorScreenPoint();
const display = screen.getDisplayNearestPoint(point);

return { point, display: display.bounds };
}

async isMaximized(windowId: number | undefined): Promise<boolean> {
Expand Down
33 changes: 19 additions & 14 deletions src/vs/workbench/browser/parts/editor/editorTabsControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,27 +331,32 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC
targetGroup.focus();
}

protected async maybeCreateAuxiliaryEditorPartAt(e: DragEvent, offsetElement?: HTMLElement): Promise<IAuxiliaryEditorPart | undefined> {
const cursorLocation = await this.hostService.getCursorScreenPoint() ?? { x: e.screenX, y: e.screenY };
protected async maybeCreateAuxiliaryEditorPartAt(e: DragEvent, offsetElement: HTMLElement): Promise<IAuxiliaryEditorPart | undefined> {
const { point, display } = await this.hostService.getCursorScreenPoint() ?? { point: { x: e.screenX, y: e.screenY } };
const window = getWindow(e);
if (cursorLocation.x >= window.screenX && cursorLocation.x <= window.screenX + window.outerWidth && cursorLocation.y >= window.screenY && cursorLocation.y <= window.screenY + window.outerHeight) {
if (point.x >= window.screenX && point.x <= window.screenX + window.outerWidth && point.y >= window.screenY && point.y <= window.screenY + window.outerHeight) {
return; // refuse to create as long as the mouse was released over main window to reduce chance of opening by accident
}

let offsetX = 0;
let offsetY = 30; // take title bar height into account (approximation)
const offsetX = offsetElement.offsetWidth / 2;
const offsetY = 30/* take title bar height into account (approximation) */ + offsetElement.offsetHeight / 2;

if (offsetElement) {
offsetX += offsetElement.offsetWidth / 2;
offsetY += offsetElement.offsetHeight / 2;
}
const bounds = {
x: point.x - offsetX,
y: point.y - offsetY
};

return this.editorGroupService.createAuxiliaryEditorPart({
bounds: {
x: cursorLocation.x - offsetX,
y: cursorLocation.y - offsetY
if (display) {
if (bounds.x < display.x) {
bounds.x = display.x; // prevent overflow to the left
}
});

if (bounds.y < display.y) {
bounds.y = display.y; // prevent overflow to the top
}
}

return this.editorGroupService.createAuxiliaryEditorPart({ bounds });
}

protected isNewWindowOperation(e: DragEvent): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ export class BrowserAuxiliaryWindowService extends Disposable implements IAuxili
const height = options?.bounds?.height ?? BrowserAuxiliaryWindowService.DEFAULT_SIZE.height;

const bounds: IRectangle = {
x: Math.max(options?.bounds?.x ?? (activeWindow.screen.availWidth / 2 - width / 2), 0),
y: Math.max(options?.bounds?.y ?? (activeWindow.screen.availHeight / 2 - height / 2), 0),
x: options?.bounds?.x ?? (activeWindow.screen.availWidth / 2 - width / 2),
y: options?.bounds?.y ?? (activeWindow.screen.availHeight / 2 - height / 2),
width: Math.max(width, WindowMinimumSize.WIDTH),
height: Math.max(height, WindowMinimumSize.HEIGHT)
};
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/services/host/browser/browserHostService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWindowSettings, IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, isFileToOpen, IOpenEmptyWindowOptions, IPathData, IFileToOpen, IPoint } from 'vs/platform/window/common/window';
import { IWindowSettings, IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, isFileToOpen, IOpenEmptyWindowOptions, IPathData, IFileToOpen } from 'vs/platform/window/common/window';
import { isResourceEditorInput, pathsToEditors } from 'vs/workbench/common/editor';
import { whenEditorClosed } from 'vs/workbench/browser/editor';
import { IWorkspace, IWorkspaceProvider } from 'vs/workbench/browser/web.api';
Expand Down Expand Up @@ -502,7 +502,7 @@ export class BrowserHostService extends Disposable implements IHostService {
// There seems to be no API to bring a window to front in browsers
}

async getCursorScreenPoint(): Promise<IPoint | undefined> {
async getCursorScreenPoint(): Promise<undefined> {
return undefined;
}

Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/services/host/browser/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IWindowOpenable, IOpenWindowOptions, IOpenEmptyWindowOptions, IPoint } from 'vs/platform/window/common/window';
import { IWindowOpenable, IOpenWindowOptions, IOpenEmptyWindowOptions, IPoint, IRectangle } from 'vs/platform/window/common/window';

export const IHostService = createDecorator<IHostService>('hostService');

Expand Down Expand Up @@ -87,9 +87,9 @@ export interface IHostService {
moveTop(targetWindow: Window): Promise<void>;

/**
* Get the location of the mouse cursor or `undefined` if unavailable.
* Get the location of the mouse cursor and its display bounds or `undefined` if unavailable.
*/
getCursorScreenPoint(): Promise<IPoint | undefined>;
getCursorScreenPoint(): Promise<{ readonly point: IPoint; readonly display: IRectangle } | undefined>;

//#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { INativeHostService } from 'vs/platform/native/common/native';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILabelService, Verbosity } from 'vs/platform/label/common/label';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, IOpenEmptyWindowOptions, IPoint } from 'vs/platform/window/common/window';
import { IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, IOpenEmptyWindowOptions, IPoint, IRectangle } from 'vs/platform/window/common/window';
import { Disposable } from 'vs/base/common/lifecycle';
import { NativeHostService } from 'vs/platform/native/common/nativeHostService';
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
Expand Down Expand Up @@ -153,7 +153,7 @@ class WorkbenchHostService extends Disposable implements IHostService {
return this.nativeHostService.moveWindowTop(isAuxiliaryWindow(targetWindow) ? { targetWindowId: targetWindow.vscodeWindowId } : undefined);
}

getCursorScreenPoint(): Promise<IPoint> {
getCursorScreenPoint(): Promise<{ readonly point: IPoint; readonly display: IRectangle }> {
return this.nativeHostService.getCursorScreenPoint();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class TestNativeHostService implements INativeHostService {
async unmaximizeWindow(): Promise<void> { }
async minimizeWindow(): Promise<void> { }
async moveWindowTop(options?: INativeOptions): Promise<void> { }
getCursorScreenPoint(): Promise<IPoint> { throw new Error('Method not implemented.'); }
getCursorScreenPoint(): Promise<{ readonly point: IPoint; readonly display: IRectangle }> { throw new Error('Method not implemented.'); }
async positionWindow(position: IRectangle, options?: INativeOptions): Promise<void> { }
async updateWindowControls(options: { height?: number; backgroundColor?: string; foregroundColor?: string }): Promise<void> { }
async setMinimumSize(width: number | undefined, height: number | undefined): Promise<void> { }
Expand Down