Skip to content

Commit

Permalink
aux window - require a target window for requestAnimationFrame (#19…
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero authored Nov 1, 2023
1 parent c43d9c4 commit 1a3461f
Show file tree
Hide file tree
Showing 34 changed files with 119 additions and 107 deletions.
43 changes: 21 additions & 22 deletions src/vs/base/browser/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,14 @@ export function addDisposableGenericMouseUpListener(node: EventTarget, handler:
* If currently in an animation frame, `runner` will be executed immediately.
* @return token that can be used to cancel the scheduled runner (only if `runner` was not executed immediately).
*/
export let runAtThisOrScheduleAtNextAnimationFrame: (runner: () => void, priority?: number) => IDisposable;
export let runAtThisOrScheduleAtNextAnimationFrame: (runner: () => void, targetWindow: Window, priority?: number) => IDisposable;
/**
* Schedule a callback to be run at the next animation frame.
* This allows multiple parties to register callbacks that should run at the next animation frame.
* If currently in an animation frame, `runner` will be executed at the next animation frame.
* @return token that can be used to cancel the scheduled runner.
*/
export let scheduleAtNextAnimationFrame: (runner: () => void, priority?: number) => IDisposable;
export let scheduleAtNextAnimationFrame: (runner: () => void, targetWindow: Window, priority?: number) => IDisposable;

class AnimationFrameQueueItem implements IDisposable {

Expand Down Expand Up @@ -252,35 +252,35 @@ class AnimationFrameQueueItem implements IDisposable {
inAnimationFrameRunner = false;
};

scheduleAtNextAnimationFrame = (runner: () => void, priority: number = 0) => {
scheduleAtNextAnimationFrame = (runner: () => void, targetWindow: Window, priority: number = 0) => {
const item = new AnimationFrameQueueItem(runner, priority);
NEXT_QUEUE.push(item);

if (!animFrameRequested) {
animFrameRequested = true;
requestAnimationFrame(animationFrameRunner);
targetWindow.requestAnimationFrame(animationFrameRunner);
}

return item;
};

runAtThisOrScheduleAtNextAnimationFrame = (runner: () => void, priority?: number) => {
runAtThisOrScheduleAtNextAnimationFrame = (runner: () => void, targetWindow: Window, priority?: number) => {
if (inAnimationFrameRunner) {
const item = new AnimationFrameQueueItem(runner, priority);
CURRENT_QUEUE!.push(item);
return item;
} else {
return scheduleAtNextAnimationFrame(runner, priority);
return scheduleAtNextAnimationFrame(runner, targetWindow, priority);
}
};
})();

export function measure(callback: () => void): IDisposable {
return scheduleAtNextAnimationFrame(callback, 10000 /* must be early */);
export function measure(callback: () => void, targetWindow: Window): IDisposable {
return scheduleAtNextAnimationFrame(callback, targetWindow, 10000 /* must be early */);
}

export function modify(callback: () => void): IDisposable {
return scheduleAtNextAnimationFrame(callback, -10000 /* must be late */);
export function modify(callback: () => void, targetWindow: Window): IDisposable {
return scheduleAtNextAnimationFrame(callback, targetWindow, -10000 /* must be late */);
}

/**
Expand Down Expand Up @@ -780,16 +780,15 @@ export function getActiveWindow(): WindowGlobal {
return document.defaultView?.window ?? window;
}

export function getWindow(element: Node): WindowGlobal;
export function getWindow(event: UIEvent): WindowGlobal;
export function getWindow(obj: unknown): WindowGlobal;
export function getWindow(element: Node | undefined | null): WindowGlobal;
export function getWindow(event: UIEvent | undefined | null): WindowGlobal;
export function getWindow(e: unknown): WindowGlobal {
const candidateNode = e as Node | undefined;
const candidateNode = e as Node | undefined | null;
if (candidateNode?.ownerDocument?.defaultView) {
return candidateNode.ownerDocument.defaultView.window;
}

const candidateEvent = e as UIEvent | undefined;
const candidateEvent = e as UIEvent | undefined | null;
if (candidateEvent?.view) {
return candidateEvent.view.window;
}
Expand Down Expand Up @@ -996,22 +995,22 @@ function isCSSStyleRule(rule: CSSRule): rule is CSSStyleRule {

export function isMouseEvent(e: unknown): e is MouseEvent {
// eslint-disable-next-line no-restricted-syntax
return e instanceof MouseEvent || e instanceof getWindow(e).MouseEvent;
return e instanceof MouseEvent || e instanceof getWindow(e as UIEvent).MouseEvent;
}

export function isKeyboardEvent(e: unknown): e is KeyboardEvent {
// eslint-disable-next-line no-restricted-syntax
return e instanceof KeyboardEvent || e instanceof getWindow(e).KeyboardEvent;
return e instanceof KeyboardEvent || e instanceof getWindow(e as UIEvent).KeyboardEvent;
}

export function isPointerEvent(e: unknown): e is PointerEvent {
// eslint-disable-next-line no-restricted-syntax
return e instanceof PointerEvent || e instanceof getWindow(e).PointerEvent;
return e instanceof PointerEvent || e instanceof getWindow(e as UIEvent).PointerEvent;
}

export function isDragEvent(e: unknown): e is DragEvent {
// eslint-disable-next-line no-restricted-syntax
return e instanceof DragEvent || e instanceof getWindow(e).DragEvent;
return e instanceof DragEvent || e instanceof getWindow(e as UIEvent).DragEvent;
}

export const EventType = {
Expand Down Expand Up @@ -1463,13 +1462,13 @@ export function windowOpenWithSuccess(url: string, noOpener = true): boolean {
return false;
}

export function animate(fn: () => void): IDisposable {
export function animate(fn: () => void, targetWindow: Window): IDisposable {
const step = () => {
fn();
stepDisposable = scheduleAtNextAnimationFrame(step);
stepDisposable = scheduleAtNextAnimationFrame(step, targetWindow);
};

let stepDisposable = scheduleAtNextAnimationFrame(step);
let stepDisposable = scheduleAtNextAnimationFrame(step, targetWindow);
return toDisposable(() => stepDisposable.dispose());
}

Expand Down
24 changes: 12 additions & 12 deletions src/vs/base/browser/touch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class Gesture extends Disposable {

this._register(EventUtils.runAndSubscribe(DomUtils.onDidRegisterWindow, ({ window, disposables }) => {
disposables.add(DomUtils.addDisposableListener(window.document, 'touchstart', (e: TouchEvent) => this.onTouchStart(e), { passive: false }));
disposables.add(DomUtils.addDisposableListener(window.document, 'touchend', (e: TouchEvent) => this.onTouchEnd(e)));
disposables.add(DomUtils.addDisposableListener(window.document, 'touchend', (e: TouchEvent) => this.onTouchEnd(window, e)));
disposables.add(DomUtils.addDisposableListener(window.document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e), { passive: false }));
}, { window, disposables: this._store }));
}
Expand Down Expand Up @@ -173,7 +173,7 @@ export class Gesture extends Disposable {
}
}

private onTouchEnd(e: TouchEvent): void {
private onTouchEnd(targetWindow: Window, e: TouchEvent): void {
const timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.

const activeTouchCount = Object.keys(this.activeTouches).length;
Expand Down Expand Up @@ -218,13 +218,13 @@ export class Gesture extends Disposable {

// We need to get all the dispatch targets on the start of the inertia event
const dispatchTo = [...this.targets].filter(t => data.initialTarget instanceof Node && t.contains(data.initialTarget));
this.inertia(dispatchTo, timestamp, // time now
Math.abs(deltaX) / deltaT, // speed
deltaX > 0 ? 1 : -1, // x direction
finalX, // x now
Math.abs(deltaY) / deltaT, // y speed
deltaY > 0 ? 1 : -1, // y direction
finalY // y now
this.inertia(targetWindow, dispatchTo, timestamp, // time now
Math.abs(deltaX) / deltaT, // speed
deltaX > 0 ? 1 : -1, // x direction
finalX, // x now
Math.abs(deltaY) / deltaT, // y speed
deltaY > 0 ? 1 : -1, // y direction
finalY // y now
);
}

Expand Down Expand Up @@ -282,7 +282,7 @@ export class Gesture extends Disposable {
}
}

private inertia(dispatchTo: readonly EventTarget[], t1: number, vX: number, dirX: number, x: number, vY: number, dirY: number, y: number): void {
private inertia(targetWindow: Window, dispatchTo: readonly EventTarget[], t1: number, vX: number, dirX: number, x: number, vY: number, dirY: number, y: number): void {
this.handle = DomUtils.scheduleAtNextAnimationFrame(() => {
const now = Date.now();

Expand Down Expand Up @@ -311,9 +311,9 @@ export class Gesture extends Disposable {
dispatchTo.forEach(d => d.dispatchEvent(evt));

if (!stopped) {
this.inertia(dispatchTo, now, vX, dirX, x + delta_pos_x, vY, dirY, y + delta_pos_y);
this.inertia(targetWindow, dispatchTo, now, vX, dirX, x + delta_pos_x, vY, dirY, y + delta_pos_y);
}
});
}, targetWindow);
}

private onTouchMove(e: TouchEvent): void {
Expand Down
6 changes: 3 additions & 3 deletions src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class BreadcrumbsWidget {
this._domNode.style.width = `${dim.width}px`;
this._domNode.style.height = `${dim.height}px`;
disposables.add(this._updateScrollbar());
}));
}, dom.getWindow(this._domNode)));
return disposables;
}

Expand All @@ -138,8 +138,8 @@ export class BreadcrumbsWidget {
this._scrollable.setRevealOnScroll(false);
this._scrollable.scanDomNode();
this._scrollable.setRevealOnScroll(true);
});
});
}, dom.getWindow(this._domNode));
}, dom.getWindow(this._domNode));
}

private _style(styleElement: HTMLStyleElement, style: IBreadcrumbsWidgetStyles): void {
Expand Down
8 changes: 4 additions & 4 deletions src/vs/base/browser/ui/list/listView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd';
import { $, addDisposableListener, animate, Dimension, getContentHeight, getContentWidth, getTopLeftOffset, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { $, addDisposableListener, animate, Dimension, getContentHeight, getContentWidth, getTopLeftOffset, getWindow, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { DomEmitter } from 'vs/base/browser/event';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { EventType as TouchEventType, Gesture, GestureEvent } from 'vs/base/browser/touch';
Expand Down Expand Up @@ -407,7 +407,7 @@ export class ListView<T> implements IListView<T> {
this.scrollable = this.disposables.add(new Scrollable({
forceIntegerValues: true,
smoothScrollDuration: (options.smoothScrolling ?? false) ? 125 : 0,
scheduleAtNextAnimationFrame: cb => scheduleAtNextAnimationFrame(cb)
scheduleAtNextAnimationFrame: cb => scheduleAtNextAnimationFrame(cb, getWindow(this.domNode))
}));
this.scrollableElement = this.disposables.add(new SmoothScrollableElement(this.rowsContainer, {
alwaysConsumeMouseWheel: options.alwaysConsumeMouseWheel ?? DefaultOptions.alwaysConsumeMouseWheel,
Expand Down Expand Up @@ -684,7 +684,7 @@ export class ListView<T> implements IListView<T> {
this.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });
this.updateScrollWidth();
this.scrollableElementUpdateDisposable = null;
});
}, getWindow(this.domNode));
}
}

Expand Down Expand Up @@ -1291,7 +1291,7 @@ export class ListView<T> implements IListView<T> {
private setupDragAndDropScrollTopAnimation(event: DragEvent): void {
if (!this.dragOverAnimationDisposable) {
const viewTop = getTopLeftOffset(this.domNode).top;
this.dragOverAnimationDisposable = animate(this.animateDragAndDropScrollTop.bind(this, viewTop));
this.dragOverAnimationDisposable = animate(this.animateDragAndDropScrollTop.bind(this, viewTop), getWindow(this.domNode));
}

this.dragOverAnimationStopDisposable.dispose();
Expand Down
2 changes: 1 addition & 1 deletion src/vs/base/browser/ui/menu/menubar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ export class MenuBar extends Disposable {
this.overflowLayoutScheduled = DOM.scheduleAtNextAnimationFrame(() => {
this.updateOverflowAction();
this.overflowLayoutScheduled = undefined;
});
}, DOM.getWindow(this.container));
}

this.setUnfocusedState();
Expand Down
4 changes: 2 additions & 2 deletions src/vs/base/browser/ui/scrollbar/scrollableElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ export class ScrollableElement extends AbstractScrollableElement {
const scrollable = new Scrollable({
forceIntegerValues: true,
smoothScrollDuration: 0,
scheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(callback)
scheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(callback, dom.getWindow(element))
});
super(element, options, scrollable);
this._register(scrollable);
Expand Down Expand Up @@ -621,7 +621,7 @@ export class DomScrollableElement extends AbstractScrollableElement {
const scrollable = new Scrollable({
forceIntegerValues: false, // See https://github.com/microsoft/vscode/issues/139877
smoothScrollDuration: 0,
scheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(callback)
scheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(callback, dom.getWindow(element))
});
super(element, options, scrollable);
this._register(scrollable);
Expand Down
4 changes: 2 additions & 2 deletions src/vs/base/browser/ui/splitview/splitview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { $, addDisposableListener, append, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { $, addDisposableListener, append, getWindow, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { DomEmitter } from 'vs/base/browser/event';
import { ISashEvent as IBaseSashEvent, Orientation, Sash, SashState } from 'vs/base/browser/ui/sash/sash';
import { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
Expand Down Expand Up @@ -584,7 +584,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
this.scrollable = this._register(new Scrollable({
forceIntegerValues: true,
smoothScrollDuration: 125,
scheduleAtNextAnimationFrame
scheduleAtNextAnimationFrame: callback => scheduleAtNextAnimationFrame(callback, getWindow(this.el)),
}));
this.scrollableElement = this._register(new SmoothScrollableElement(this.viewContainer, {
vertical: this.orientation === Orientation.VERTICAL ? (options.scrollbarVisibility ?? ScrollbarVisibility.Auto) : ScrollbarVisibility.Hidden,
Expand Down
5 changes: 3 additions & 2 deletions src/vs/editor/browser/config/elementSizeObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { IDimension } from 'vs/editor/common/core/dimension';
import { Emitter, Event } from 'vs/base/common/event';
import { getWindow, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';

export class ElementSizeObserver extends Disposable {

Expand Down Expand Up @@ -65,10 +66,10 @@ export class ElementSizeObserver extends Disposable {
alreadyObservedThisAnimationFrame = true;
observeNow();
} finally {
requestAnimationFrame(() => {
scheduleAtNextAnimationFrame(() => {
alreadyObservedThisAnimationFrame = false;
update();
});
}, getWindow(this._referenceDomElement));
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions src/vs/editor/browser/controller/mouseHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ class TopBottomDragScrollingOperation extends Disposable {
this._position = position;
this._mouseEvent = mouseEvent;
this._lastTime = Date.now();
this._animationFrameDisposable = dom.scheduleAtNextAnimationFrame(() => this._execute());
this._animationFrameDisposable = dom.scheduleAtNextAnimationFrame(() => this._execute(), dom.getWindow(mouseEvent.browserEvent));
}

public override dispose(): void {
Expand Down Expand Up @@ -752,7 +752,7 @@ class TopBottomDragScrollingOperation extends Disposable {
}

this._dispatchMouse(mouseTarget, true, NavigationCommandRevealType.None);
this._animationFrameDisposable = dom.scheduleAtNextAnimationFrame(() => this._execute());
this._animationFrameDisposable = dom.scheduleAtNextAnimationFrame(() => this._execute(), dom.getWindow(mouseTarget.element));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/vs/editor/browser/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ export class View extends ViewEventHandler {

private _scheduleRender(): void {
if (this._renderAnimationFrame === null) {
this._renderAnimationFrame = dom.runAtThisOrScheduleAtNextAnimationFrame(this._onRenderScheduled.bind(this), 100);
this._renderAnimationFrame = dom.runAtThisOrScheduleAtNextAnimationFrame(this._onRenderScheduled.bind(this), dom.getWindow(this.domNode.domNode), 100);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export class ViewCursor {
return null;
}

const window = dom.getWindow(this._domNode);
const window = dom.getWindow(this._domNode.domNode);
let width: number;
if (this._cursorStyle === TextEditorCursorStyle.Line) {
width = dom.computeScreenAwareSize(window, this._lineCursorWidth > 0 ? this._lineCursorWidth : 2);
Expand Down
2 changes: 1 addition & 1 deletion src/vs/editor/browser/widget/codeEditorWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1648,7 +1648,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
model,
DOMLineBreaksComputerFactory.create(),
MonospaceLineBreaksComputerFactory.create(this._configuration.options),
(callback) => dom.scheduleAtNextAnimationFrame(callback),
(callback) => dom.scheduleAtNextAnimationFrame(callback, dom.getWindow(this._domElement)),
this.languageConfigurationService,
this._themeService,
attachedView,
Expand Down
3 changes: 2 additions & 1 deletion src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { $, h } from 'vs/base/browser/dom';
import { $, getWindow, h } from 'vs/base/browser/dom';
import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash';
import { findLast } from 'vs/base/common/arraysFind';
import { onUnexpectedError } from 'vs/base/common/errors';
Expand Down Expand Up @@ -178,6 +178,7 @@ export class DiffEditorWidget extends DelegatingEditor implements IDiffEditor {
/** @description ViewZoneManager */
store.add(this._instantiationService.createInstance(
readHotReloadableExport(ViewZoneManager, reader),
getWindow(this._domElement),
this._editors,
this._diffModel,
this._options,
Expand Down
5 changes: 3 additions & 2 deletions src/vs/editor/browser/widget/diffEditor/lineAlignment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ export class ViewZoneManager extends Disposable {
private readonly _originalTopPadding = observableValue(this, 0);
private readonly _originalScrollTop: IObservable<number>;
private readonly _originalScrollOffset = observableValue<number, boolean>(this, 0);
private readonly _originalScrollOffsetAnimated = animatedObservable(this._originalScrollOffset, this._store);
private readonly _originalScrollOffsetAnimated = animatedObservable(this._targetWindow, this._originalScrollOffset, this._store);

private readonly _modifiedTopPadding = observableValue(this, 0);
private readonly _modifiedScrollTop: IObservable<number>;
private readonly _modifiedScrollOffset = observableValue<number, boolean>(this, 0);
private readonly _modifiedScrollOffsetAnimated = animatedObservable(this._modifiedScrollOffset, this._store);
private readonly _modifiedScrollOffsetAnimated = animatedObservable(this._targetWindow, this._modifiedScrollOffset, this._store);

constructor(
private readonly _targetWindow: Window,
private readonly _editors: DiffEditorEditors,
private readonly _diffModel: IObservable<DiffEditorViewModel | undefined>,
private readonly _options: DiffEditorOptions,
Expand Down
Loading

0 comments on commit 1a3461f

Please sign in to comment.