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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import './media/browser.css';
import { localize } from '../../../../nls.js';
import { $, addDisposableListener, disposableWindowInterval, EventType, isHTMLElement, registerExternalFocusChecker, scheduleAtNextAnimationFrame } from '../../../../base/browser/dom.js';
import { $, addDisposableListener, Dimension, disposableWindowInterval, EventType, IDomPosition, isHTMLElement, registerExternalFocusChecker } from '../../../../base/browser/dom.js';
import { renderIcon } from '../../../../base/browser/ui/iconLabel/iconLabels.js';
import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
import { RawContextKey, IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
Expand All @@ -29,7 +29,7 @@ import { StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js
import { BrowserOverlayManager } from './overlayManager.js';
import { getZoomFactor, onDidChangeZoomLevel } from '../../../../base/browser/browser.js';
import { ILogService } from '../../../../platform/log/common/log.js';
import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
import { Disposable, DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js';
import { WorkbenchHoverDelegate } from '../../../../platform/hover/browser/hover.js';
import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js';
import { MenuWorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js';
Expand Down Expand Up @@ -250,6 +250,11 @@ export class BrowserEditor extends EditorPane {
// Register external focus checker so that cross-window focus logic knows when
// this browser view has focus (since it's outside the normal DOM tree).
this._register(registerExternalFocusChecker(() => this._model?.focused ?? false));

// Automatically call layoutBrowserContainer() when the browser container changes size
const resizeObserver = new ResizeObserver(async () => this.layoutBrowserContainer());
resizeObserver.observe(this._browserContainer);
this._register(toDisposable(() => resizeObserver.disconnect()));
}

override async setInput(input: BrowserEditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
Expand Down Expand Up @@ -354,7 +359,7 @@ export class BrowserEditor extends EditorPane {
// Listen for zoom level changes and update browser view zoom factor
this._inputDisposables.add(onDidChangeZoomLevel(targetWindowId => {
if (targetWindowId === this.window.vscodeWindowId) {
this.layout();
this.layoutBrowserContainer();
}
}));
// Capture screenshot periodically (once per second) to keep background updated
Expand All @@ -365,11 +370,8 @@ export class BrowserEditor extends EditorPane {
));

this.updateErrorDisplay();
this.layout();
this.layoutBrowserContainer();
await this._model.setVisible(this.shouldShowView);

// Sometimes the element has not been inserted into the DOM yet. Ensure layout after next animation frame.
scheduleAtNextAnimationFrame(this.window, () => this.layout());
}

protected override setEditorVisible(visible: boolean): void {
Expand Down Expand Up @@ -675,7 +677,20 @@ export class BrowserEditor extends EditorPane {
}
}

override layout(): void {
override layout(_dimension: Dimension, _position?: IDomPosition): void {
// no-op: layout is handled in layoutBrowserContainer()
}

/**
* This should be called whenever .browser-container changes in size, or when
* there could be any elements, such as the command palette, overlapping with it.
*
* Note that we don't call layoutBrowserContainer() from layout() but instead rely on using a ResizeObserver and on
* making direct calls to it. This is because we have seen cases where the getBoundingClientRect() values of
* the .browser-container element are not correct during layout() calls, especially during "Move into New Window"
* and "Copy into New Window" operations into a different monitor.
*/
layoutBrowserContainer(): void {
if (this._model) {
this.checkOverlays();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Codicon } from '../../../../base/common/codicons.js';
import { truncate } from '../../../../base/common/strings.js';
import { ThemeIcon } from '../../../../base/common/themables.js';
import { URI } from '../../../../base/common/uri.js';
import { generateUuid } from '../../../../base/common/uuid.js';
import { BrowserViewUri } from '../../../../platform/browserView/common/browserViewUri.js';
import { EditorInputCapabilities, IEditorSerializer, IUntypedEditorInput } from '../../../common/editor.js';
import { EditorInput } from '../../../common/editor/editorInput.js';
Expand Down Expand Up @@ -56,7 +57,8 @@ export class BrowserEditorInput extends EditorInput {
options: IBrowserEditorInputData,
@IThemeService private readonly themeService: IThemeService,
@IBrowserViewWorkbenchService private readonly browserViewWorkbenchService: IBrowserViewWorkbenchService,
@ILifecycleService private readonly lifecycleService: ILifecycleService
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super();
this._id = options.id;
Expand Down Expand Up @@ -205,6 +207,20 @@ export class BrowserEditorInput extends EditorInput {
return false;
}

/**
* Creates a copy of this browser editor input with a new unique ID, creating an independent browser view with no linked state.
* This is used during Copy into New Window.
*/
override copy(): EditorInput {
const currentUrl = this._model?.url ?? this._initialData.url;
return this.instantiationService.createInstance(BrowserEditorInput, {
id: generateUuid(),
url: currentUrl,
title: this._model?.title ?? this._initialData.title,
favicon: this._model?.favicon ?? this._initialData.favicon
});
}

override toUntyped(): IUntypedEditorInput {
return {
resource: this.resource,
Expand Down
Loading