import { getWindowId, onDidUnregisterWindow } from './dom.js';
import { Emitter, Event } from '../common/event.js';
import { Disposable, markAsSingleton } from '../common/lifecycle.js';
class DevicePixelRatioMonitor extends Disposable {
private readonly _onDidChange = this._register(new Emitter<void>());
readonly onDidChange = this._onDidChange.event;
private readonly _listener: () => void;
private _mediaQueryList: MediaQueryList | null;
constructor(targetWindow: Window) {
super();
this._listener = () => this._handleChange(targetWindow, true);
this._mediaQueryList = null;
this._handleChange(targetWindow, false);
}
private _handleChange(targetWindow: Window, fireEvent: boolean): void {
this._mediaQueryList?.removeEventListener('change', this._listener);
this._mediaQueryList = targetWindow.matchMedia(`(resolution: ${targetWindow.devicePixelRatio}dppx)`);
this._mediaQueryList.addEventListener('change', this._listener);
if (fireEvent) {
this._onDidChange.fire();
}
}
}
export interface IPixelRatioMonitor {
readonly value: number;
readonly onDidChange: Event<number>;
}
class PixelRatioMonitorImpl extends Disposable implements IPixelRatioMonitor {
private readonly _onDidChange = this._register(new Emitter<number>());
readonly onDidChange = this._onDidChange.event;
private _value: number;
get value(): number {
return this._value;
}
constructor(targetWindow: Window) {
super();
this._value = this._getPixelRatio(targetWindow);
const dprMonitor = this._register(new DevicePixelRatioMonitor(targetWindow));
this._register(dprMonitor.onDidChange(() => {
this._value = this._getPixelRatio(targetWindow);
this._onDidChange.fire(this._value);
}));
}
private _getPixelRatio(targetWindow: Window): number {
const ctx: any = document.createElement('canvas').getContext('2d');
const dpr = targetWindow.devicePixelRatio || 1;
const bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
return dpr / bsr;
}
}
class PixelRatioMonitorFacade {
private readonly mapWindowIdToPixelRatioMonitor = new Map<number, PixelRatioMonitorImpl>();
private _getOrCreatePixelRatioMonitor(targetWindow: Window): PixelRatioMonitorImpl {
const targetWindowId = getWindowId(targetWindow);
let pixelRatioMonitor = this.mapWindowIdToPixelRatioMonitor.get(targetWindowId);
if (!pixelRatioMonitor) {
pixelRatioMonitor = markAsSingleton(new PixelRatioMonitorImpl(targetWindow));
this.mapWindowIdToPixelRatioMonitor.set(targetWindowId, pixelRatioMonitor);
markAsSingleton(Event.once(onDidUnregisterWindow)(({ vscodeWindowId }) => {
if (vscodeWindowId === targetWindowId) {
pixelRatioMonitor?.dispose();
this.mapWindowIdToPixelRatioMonitor.delete(targetWindowId);
}
}));
}
return pixelRatioMonitor;
}
getInstance(targetWindow: Window): IPixelRatioMonitor {
return this._getOrCreatePixelRatioMonitor(targetWindow);
}
}
export const PixelRatio = new PixelRatioMonitorFacade();