fix(overlay): handle X11 display scaling across monitors (#193)

This commit is contained in:
2026-08-11 22:24:01 -07:00
committed by GitHub
parent ee25536d90
commit 57ddd19953
14 changed files with 272 additions and 37 deletions
@@ -47,6 +47,29 @@ WINDOW=44040194
assert.deepEqual(reader.getCursorScreenPoint({ x: 877, y: 718 }), { x: 1700, y: 1050 });
});
test('createLinuxX11CursorPointReader converts physical X11 coordinates to Electron DIP', async () => {
const convertedPoints: Array<{ x: number; y: number }> = [];
const reader = createLinuxX11CursorPointReader({
env: { DISPLAY: ':1' },
platform: 'linux',
runCommand: async () => `X=1424
Y=697
SCREEN=0
WINDOW=44040194
`,
screenToDipPoint: (point) => {
convertedPoints.push(point);
return { x: 1139, y: 557 };
},
});
reader.refresh();
await new Promise((resolve) => setImmediate(resolve));
assert.deepEqual(reader.getCursorScreenPoint({ x: 0, y: 0 }), { x: 1139, y: 557 });
assert.deepEqual(convertedPoints, [{ x: 1424, y: 697 }]);
});
test('createLinuxX11CursorPointReader does not spawn off X11 Linux', () => {
const calls: string[] = [];
const reader = createLinuxX11CursorPointReader({
+3 -1
View File
@@ -36,11 +36,13 @@ export function createLinuxX11CursorPointReader(options?: {
now?: () => number;
platform?: NodeJS.Platform;
runCommand?: CommandRunner;
screenToDipPoint?: (point: PointerPoint) => PointerPoint;
}) {
const env = options?.env ?? process.env;
const now = options?.now ?? (() => Date.now());
const platform = options?.platform ?? process.platform;
const runCommand = options?.runCommand ?? execFileUtf8;
const screenToDipPoint = options?.screenToDipPoint ?? ((point: PointerPoint) => point);
let latest: { point: PointerPoint; updatedAtMs: number } | null = null;
let inFlight = false;
let retryAfterMs = 0;
@@ -63,7 +65,7 @@ export function createLinuxX11CursorPointReader(options?: {
retryAfterMs = now() + COMMAND_FAILURE_RETRY_DELAY_MS;
return;
}
latest = { point, updatedAtMs: now() };
latest = { point: screenToDipPoint(point), updatedAtMs: now() };
retryAfterMs = 0;
})
.catch(() => {
@@ -289,7 +289,9 @@ export function createVisibleOverlayInteractionRuntime(deps: VisibleOverlayInter
if (initialArgs && isHeadlessInitialCommand(initialArgs)) {
return null;
}
return createWindowTrackerCore(override, targetMpvSocketPath);
return createWindowTrackerCore(override, targetMpvSocketPath, (point) =>
screen.screenToDipPoint(point),
);
}
function bindVisibleOverlayOwner(): void {
@@ -627,7 +629,9 @@ export function createVisibleOverlayInteractionRuntime(deps: VisibleOverlayInter
ensureWindowsVisibleOverlayForegroundPollLoop();
const linuxX11CursorPointReader = createLinuxX11CursorPointReader();
const linuxX11CursorPointReader = createLinuxX11CursorPointReader({
screenToDipPoint: (point) => screen.screenToDipPoint(point),
});
function getLinuxOverlayPointerMeasurement() {
const measurement = overlayContentMeasurementStore.getLatestByLayer('visible');