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

Some auxiliary windows fixes #195645

Merged
merged 5 commits into from
Oct 16, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export interface IAuxiliaryWindow {
readonly id: number;
readonly win: BrowserWindow | null;

readonly lastFocusTime: number;

focus(options?: { force: boolean }): void;
}

Expand Down Expand Up @@ -42,6 +44,9 @@ export class AuxiliaryWindow extends BaseWindow implements IAuxiliaryWindow {
return this.win;
}

private _lastFocusTime = Date.now(); // window is shown on creation so take current time
get lastFocusTime(): number { return this._lastFocusTime; }

constructor(
private readonly contents: WebContents,
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService
Expand All @@ -61,11 +66,16 @@ export class AuxiliaryWindow extends BaseWindow implements IAuxiliaryWindow {

private registerWindowListeners(window: BrowserWindow): void {

// Window close
// Window Close
window.on('closed', () => {
this._onDidClose.fire();

this.dispose();
});

// Window Focus
window.on('focus', () => {
this._lastFocusTime = Date.now();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ export interface IAuxiliaryWindowsMainService {
registerWindow(webContents: WebContents): void;

getWindowById(windowId: number): IAuxiliaryWindow | undefined;

getFocusedWindow(): IAuxiliaryWindow | undefined;
getLastActiveWindow(): IAuxiliaryWindow | undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { FileAccess } from 'vs/base/common/network';
import { AuxiliaryWindow, IAuxiliaryWindow } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow';
import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { defaultBrowserWindowOptions } from 'vs/platform/windows/electron-main/windows';
import { defaultBrowserWindowOptions, getLastFocused } from 'vs/platform/windows/electron-main/windows';

export class AuxiliaryWindowsMainService implements IAuxiliaryWindowsMainService {

Expand Down Expand Up @@ -48,4 +48,8 @@ export class AuxiliaryWindowsMainService implements IAuxiliaryWindowsMainService

return undefined;
}

getLastActiveWindow(): IAuxiliaryWindow | undefined {
return getLastFocused(Array.from(this.windows.values()));
}
}
26 changes: 16 additions & 10 deletions src/vs/platform/native/electron-main/nativeHostMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { ISerializableCommandAction } from 'vs/platform/action/common/action';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs';
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILifecycleMainService, IRelaunchOptions } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { ILogService } from 'vs/platform/log/common/log';
import { ICommonNativeHostService, IOSProperties, IOSStatistics } from 'vs/platform/native/common/native';
Expand All @@ -34,7 +34,7 @@ import { IPartsSplash } from 'vs/platform/theme/common/themeService';
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
import { ICodeWindow } from 'vs/platform/window/electron-main/window';
import { IColorScheme, IOpenedWindow, IOpenEmptyWindowOptions, IOpenWindowOptions, IWindowOpenable } from 'vs/platform/window/common/window';
import { IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows';
import { getFocusedOrLastActiveWindow, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows';
import { isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService';
import { VSBuffer } from 'vs/base/common/buffer';
Expand All @@ -61,7 +61,8 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
@ILogService private readonly logService: ILogService,
@IProductService private readonly productService: IProductService,
@IThemeMainService private readonly themeMainService: IThemeMainService,
@IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService
@IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super();
}
Expand Down Expand Up @@ -360,19 +361,19 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
//#region Dialog

async showMessageBox(windowId: number | undefined, options: MessageBoxOptions): Promise<MessageBoxReturnValue> {
const window = this.focusedWindow() ?? this.codeWindowById(windowId);
const window = this.getTargetWindow(windowId);

return this.dialogMainService.showMessageBox(options, window?.win ?? undefined);
}

async showSaveDialog(windowId: number | undefined, options: SaveDialogOptions): Promise<SaveDialogReturnValue> {
const window = this.focusedWindow() ?? this.codeWindowById(windowId);
const window = this.getTargetWindow(windowId);

return this.dialogMainService.showSaveDialog(options, window?.win ?? undefined);
}

async showOpenDialog(windowId: number | undefined, options: OpenDialogOptions): Promise<OpenDialogReturnValue> {
const window = this.focusedWindow() ?? this.codeWindowById(windowId);
const window = this.getTargetWindow(windowId);

return this.dialogMainService.showOpenDialog(options, window?.win ?? undefined);
}
Expand Down Expand Up @@ -731,13 +732,13 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
//#region Development

async openDevTools(windowId: number | undefined, options?: OpenDevToolsOptions): Promise<void> {
const window = this.focusedWindow() ?? this.codeWindowById(windowId);
const window = this.getTargetWindow(windowId);

window?.win?.webContents.openDevTools(options);
}

async toggleDevTools(windowId: number | undefined): Promise<void> {
const window = this.focusedWindow() ?? this.codeWindowById(windowId);
const window = this.getTargetWindow(windowId);

window?.win?.webContents.toggleDevTools();
}
Expand Down Expand Up @@ -803,7 +804,12 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
return this.auxiliaryWindowsMainService.getWindowById(windowId);
}

private focusedWindow(): ICodeWindow | IAuxiliaryWindow | undefined {
return this.windowsMainService.getFocusedWindow() ?? this.auxiliaryWindowsMainService.getFocusedWindow();
private getTargetWindow(fallbackWindowId: number | undefined): ICodeWindow | IAuxiliaryWindow | undefined {
let window = this.instantiationService.invokeFunction(getFocusedOrLastActiveWindow);
if (!window) {
window = this.windowById(fallbackWindowId);
}

return window;
}
}
39 changes: 39 additions & 0 deletions src/vs/platform/windows/electron-main/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { join } from 'vs/base/common/path';
import { IAuxiliaryWindow } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow';
import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows';

export const IWindowsMainService = createDecorator<IWindowsMainService>('windowsMainService');

Expand Down Expand Up @@ -157,3 +159,40 @@ export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowSt

return options;
}

export function getFocusedOrLastActiveWindow(accessor: ServicesAccessor): ICodeWindow | IAuxiliaryWindow | undefined {
const windowsMainService = accessor.get(IWindowsMainService);
const auxiliaryWindowsMainService = accessor.get(IAuxiliaryWindowsMainService);

// By: Electron focused window
const focusedWindow = windowsMainService.getFocusedWindow() ?? auxiliaryWindowsMainService.getFocusedWindow();
if (focusedWindow) {
return focusedWindow;
}

// By: Last active window
const mainLastActiveWindow = windowsMainService.getLastActiveWindow();
const auxiliaryLastActiveWindow = auxiliaryWindowsMainService.getLastActiveWindow();

if (mainLastActiveWindow && auxiliaryLastActiveWindow) {
return mainLastActiveWindow.lastFocusTime < auxiliaryLastActiveWindow.lastFocusTime ? auxiliaryLastActiveWindow : mainLastActiveWindow;
}

return mainLastActiveWindow ?? auxiliaryLastActiveWindow;
}

export function getLastFocused(windows: ICodeWindow[]): ICodeWindow | undefined;
export function getLastFocused(windows: IAuxiliaryWindow[]): IAuxiliaryWindow | undefined;
export function getLastFocused(windows: ICodeWindow[] | IAuxiliaryWindow[]): ICodeWindow | IAuxiliaryWindow | undefined {
let lastFocusedWindow: ICodeWindow | IAuxiliaryWindow | undefined = undefined;
let maxLastFocusTime = Number.MIN_VALUE;

for (const window of windows) {
if (window.lastFocusTime > maxLastFocusTime) {
maxLastFocusTime = window.lastFocusTime;
lastFocusedWindow = window;
}
}

return lastFocusedWindow;
}
6 changes: 2 additions & 4 deletions src/vs/platform/windows/electron-main/windowsMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { IStateService } from 'vs/platform/state/node/state';
import { IAddFoldersRequest, INativeOpenFileRequest, INativeWindowConfiguration, IOpenEmptyWindowOptions, IPath, IPathsToWaitFor, isFileToOpen, isFolderToOpen, isWorkspaceToOpen, IWindowOpenable, IWindowSettings } from 'vs/platform/window/common/window';
import { CodeWindow } from 'vs/platform/windows/electron-main/windowImpl';
import { IOpenConfiguration, IOpenEmptyConfiguration, IWindowsCountChangedEvent, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows';
import { IOpenConfiguration, IOpenEmptyConfiguration, IWindowsCountChangedEvent, IWindowsMainService, OpenContext, getLastFocused } from 'vs/platform/windows/electron-main/windows';
import { findWindowOnExtensionDevelopmentPath, findWindowOnFile, findWindowOnWorkspaceOrFolder } from 'vs/platform/windows/electron-main/windowsFinder';
import { IWindowState, WindowsStateHandler } from 'vs/platform/windows/electron-main/windowsStateHandler';
import { IRecent } from 'vs/platform/workspaces/common/workspaces';
Expand Down Expand Up @@ -1620,9 +1620,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
}

private doGetLastActiveWindow(windows: ICodeWindow[]): ICodeWindow | undefined {
const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime));

return windows.find(window => window.lastFocusTime === lastFocusedDate);
return getLastFocused(windows);
}

sendToFocused(channel: string, ...args: any[]): void {
Expand Down
10 changes: 3 additions & 7 deletions src/vs/workbench/browser/parts/editor/editorActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2441,17 +2441,13 @@ export class ExperimentalMoveEditorIntoNewWindowAction extends Action2 {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);

const activeEditor = editorService.activeEditor;
if (!activeEditor) {
const activeEditorPane = editorService.activeEditorPane;
if (!activeEditorPane) {
return;
}

const auxiliaryEditorPart = editorGroupService.createAuxiliaryEditorPart();

await auxiliaryEditorPart.activeGroup.openEditor(activeEditor, {
pinned: true,
viewState: activeEditor.toUntyped({ preserveViewState: editorGroupService.activeGroup.id })?.options?.viewState,
});
await editorGroupService.activeGroup.closeEditor(activeEditor);
activeEditorPane.group.moveEditor(activeEditorPane.input, auxiliaryEditorPart.activeGroup);
}
}
22 changes: 19 additions & 3 deletions src/vs/workbench/browser/parts/editor/editorPanes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/

import { localize } from 'vs/nls';
import { IAction } from 'vs/base/common/actions';
import { IAction, toAction } from 'vs/base/common/actions';
import { Emitter } from 'vs/base/common/event';
import Severity from 'vs/base/common/severity';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { EditorExtensions, EditorInputCapabilities, IEditorOpenContext, IVisibleEditorPane, isEditorOpenError } from 'vs/workbench/common/editor';
import { EditorExtensions, EditorInputCapabilities, IEditorOpenContext, IVisibleEditorPane, createEditorOpenError, isEditorOpenError } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { Dimension, show, hide, IDomNodePagePosition, isAncestor, getWindow, getActiveWindow } from 'vs/base/browser/dom';
import { Registry } from 'vs/platform/registry/common/platform';
Expand Down Expand Up @@ -128,7 +128,23 @@ export class EditorPanes extends Disposable {

async openEditor(editor: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise<IOpenEditorResult> {
try {
return await this.doOpenEditor(this.getEditorPaneDescriptor(editor), editor, options, context);

// Assert the `EditorInputCapabilities.AuxWindowUnsupported` condition
// TODO@bpasero revisit this once all editors can support aux windows
if (getWindow(this.editorPanesParent) !== window && editor.hasCapability(EditorInputCapabilities.AuxWindowUnsupported)) {
return await this.doShowError(createEditorOpenError(localize('editorUnsupportedInAuxWindow', "This type of editor cannot be opened in floating windows yet."), [
toAction({
id: 'workbench.editor.action.closeEditor', label: localize('openFolder', "Close Editor"), run: async () => {
return this.groupView.closeEditor(editor);
}
})
], { forceMessage: true, forceSeverity: Severity.Warning }), editor, options, context);
}

// Open editor normally
else {
return await this.doOpenEditor(this.getEditorPaneDescriptor(editor), editor, options, context);
}
} catch (error) {

// First check if caller instructed us to ignore error handling
Expand Down
8 changes: 7 additions & 1 deletion src/vs/workbench/common/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,13 @@ export const enum EditorInputCapabilities {
* Signals that the editor cannot be in a dirty state
* and may still have unsaved changes
*/
Scratchpad = 1 << 9
Scratchpad = 1 << 9,

/**
* Signals that the editor does not support opening in
* auxiliary windows yet.
*/
AuxWindowUnsupported = 1 << 10
}

export type IUntypedEditorInput = IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput | IResourceDiffEditorInput | IResourceSideBySideEditorInput | IResourceMergeEditorInput;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
let capabilities = EditorInputCapabilities.None;

capabilities |= EditorInputCapabilities.CanDropIntoEditor;
capabilities |= EditorInputCapabilities.AuxWindowUnsupported;

if (!this.customEditorService.getCustomEditorCapabilities(this.viewType)?.supportsMultipleEditorsPerDocument) {
capabilities |= EditorInputCapabilities.Singleton;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class ExtensionsInput extends EditorInput {
}

override get capabilities(): EditorInputCapabilities {
return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton;
return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton | EditorInputCapabilities.AuxWindowUnsupported;
}

override get resource() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export class InteractiveEditorInput extends EditorInput implements ICompositeNot
override get capabilities(): EditorInputCapabilities {
return EditorInputCapabilities.Untitled
| EditorInputCapabilities.Readonly
| EditorInputCapabilities.AuxWindowUnsupported
| EditorInputCapabilities.Scratchpad;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export class NotebookEditorInput extends AbstractResourceEditorInput {
}

override get capabilities(): EditorInputCapabilities {
let capabilities = EditorInputCapabilities.None;
let capabilities = EditorInputCapabilities.AuxWindowUnsupported;

if (this.resource.scheme === Schemas.untitled) {
capabilities |= EditorInputCapabilities.Untitled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Button } from 'vs/base/browser/ui/button/button';
import { ITreeElement } from 'vs/base/browser/ui/tree/tree';
import { Action } from 'vs/base/common/actions';
import { Delayer, IntervalTimer, ThrottledDelayer, timeout } from 'vs/base/common/async';
import { Delayer, IntervalTimer, ThrottledDelayer } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { fromNow } from 'vs/base/common/date';
import { isCancellationError } from 'vs/base/common/errors';
Expand Down Expand Up @@ -360,7 +360,6 @@ export class SettingsEditor2 extends EditorPane {
override async setInput(input: SettingsEditor2Input, options: ISettingsEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
this.inSettingsEditorContextKey.set(true);
await super.setInput(input, options, context, token);
await timeout(0); // Force setInput to be async
if (!this.input) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class WebviewInput extends EditorInput {
}

public override get capabilities(): EditorInputCapabilities {
return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton | EditorInputCapabilities.CanDropIntoEditor;
return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton | EditorInputCapabilities.CanDropIntoEditor | EditorInputCapabilities.AuxWindowUnsupported;
}

private readonly _resourceId = generateUuid();
Expand Down