1 Commits

Author SHA1 Message Date
d91e275993 Fix Windows overlay scaling bounds 2026-03-25 09:01:20 -07:00
4 changed files with 68 additions and 7 deletions

View File

@@ -0,0 +1,4 @@
type: fixed
area: overlay
- Fixed Windows overlay window tracking on scaled displays by converting native tracked window bounds to Electron DIP coordinates before applying overlay bounds.

View File

@@ -0,0 +1,36 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { normalizeOverlayWindowBoundsForPlatform } from './overlay-window-bounds';
test('normalizeOverlayWindowBoundsForPlatform returns original geometry outside Windows', () => {
const geometry = { x: 150, y: 90, width: 1200, height: 675 };
assert.deepEqual(normalizeOverlayWindowBoundsForPlatform(geometry, 'linux', null), geometry);
});
test('normalizeOverlayWindowBoundsForPlatform converts Windows physical pixels to DIP', () => {
assert.deepEqual(
normalizeOverlayWindowBoundsForPlatform(
{
x: 150,
y: 75,
width: 1920,
height: 1080,
},
'win32',
{
screenToDipRect: (_window, rect) => ({
x: Math.round(rect.x / 1.5),
y: Math.round(rect.y / 1.5),
width: Math.round(rect.width / 1.5),
height: Math.round(rect.height / 1.5),
}),
},
),
{
x: 100,
y: 50,
width: 1280,
height: 720,
},
);
});

View File

@@ -0,0 +1,25 @@
import type { WindowGeometry } from '../../types';
type ScreenDipConverter = {
screenToDipRect: (
window: Electron.BrowserWindow | null,
rect: Electron.Rectangle,
) => Electron.Rectangle;
};
export function normalizeOverlayWindowBoundsForPlatform(
geometry: WindowGeometry,
platform: NodeJS.Platform,
screen: ScreenDipConverter | null,
): WindowGeometry {
if (platform !== 'win32' || !screen) {
return geometry;
}
return screen.screenToDipRect(null, {
x: geometry.x,
y: geometry.y,
width: geometry.width,
height: geometry.height,
});
}

View File

@@ -1,4 +1,4 @@
import { BrowserWindow, type Session } from 'electron';
import { BrowserWindow, screen, type Session } from 'electron';
import * as path from 'path';
import { WindowGeometry } from '../../types';
import { createLogger } from '../../logger';
@@ -8,6 +8,7 @@ import {
type OverlayWindowKind,
} from './overlay-window-input';
import { buildOverlayWindowOptions } from './overlay-window-options';
import { normalizeOverlayWindowBoundsForPlatform } from './overlay-window-bounds';
const logger = createLogger('main:overlay-window');
const overlayWindowLayerByInstance = new WeakMap<BrowserWindow, OverlayWindowKind>();
@@ -33,12 +34,7 @@ export function updateOverlayWindowBounds(
window: BrowserWindow | null,
): void {
if (!geometry || !window || window.isDestroyed()) return;
window.setBounds({
x: geometry.x,
y: geometry.y,
width: geometry.width,
height: geometry.height,
});
window.setBounds(normalizeOverlayWindowBoundsForPlatform(geometry, process.platform, screen));
}
export function ensureOverlayWindowLevel(window: BrowserWindow): void {