Cancel pending Linux MPV fullscreen overlay refresh bursts

- return a cancel handle from the Linux refresh burst scheduler
- clear pending refresh bursts when overlays hide or windows close
- tighten the burst test polling to wait for the async refresh
This commit is contained in:
2026-04-27 20:31:00 -07:00
parent bacc90cd24
commit 490f693361
3 changed files with 40 additions and 14 deletions

View File

@@ -34,6 +34,7 @@ import { applyControllerConfigUpdate } from './main/controller-config-update.js'
import { openPlaylistBrowser as openPlaylistBrowserRuntime } from './main/runtime/playlist-browser-open'; import { openPlaylistBrowser as openPlaylistBrowserRuntime } from './main/runtime/playlist-browser-open';
import { createDiscordRpcClient } from './main/runtime/discord-rpc-client.js'; import { createDiscordRpcClient } from './main/runtime/discord-rpc-client.js';
import { import {
type CancelLinuxMpvFullscreenOverlayRefreshBurst,
clearLinuxMpvFullscreenOverlayRefreshTimeouts, clearLinuxMpvFullscreenOverlayRefreshTimeouts,
scheduleLinuxVisibleOverlayFullscreenRefreshBurst, scheduleLinuxVisibleOverlayFullscreenRefreshBurst,
} from './main/runtime/linux-mpv-fullscreen-overlay-refresh'; } from './main/runtime/linux-mpv-fullscreen-overlay-refresh';
@@ -1399,6 +1400,9 @@ const subtitleProcessingController = createSubtitleProcessingController(
let subtitlePrefetchService: SubtitlePrefetchService | null = null; let subtitlePrefetchService: SubtitlePrefetchService | null = null;
let subtitlePrefetchRefreshTimer: ReturnType<typeof setTimeout> | null = null; let subtitlePrefetchRefreshTimer: ReturnType<typeof setTimeout> | null = null;
let lastObservedTimePos = 0; let lastObservedTimePos = 0;
let cancelLinuxMpvFullscreenOverlayRefreshBurst:
| CancelLinuxMpvFullscreenOverlayRefreshBurst
| null = null;
const SEEK_THRESHOLD_SECONDS = 3; const SEEK_THRESHOLD_SECONDS = 3;
function clearScheduledSubtitlePrefetchRefresh(): void { function clearScheduledSubtitlePrefetchRefresh(): void {
@@ -1408,6 +1412,11 @@ function clearScheduledSubtitlePrefetchRefresh(): void {
} }
} }
function cancelPendingLinuxMpvFullscreenOverlayRefreshBurst(): void {
cancelLinuxMpvFullscreenOverlayRefreshBurst?.();
cancelLinuxMpvFullscreenOverlayRefreshBurst = null;
}
const subtitlePrefetchInitController = createSubtitlePrefetchInitController({ const subtitlePrefetchInitController = createSubtitlePrefetchInitController({
getCurrentService: () => subtitlePrefetchService, getCurrentService: () => subtitlePrefetchService,
setCurrentService: (service) => { setCurrentService: (service) => {
@@ -3106,8 +3115,10 @@ const {
stopTexthookerService: () => texthookerService.stop(), stopTexthookerService: () => texthookerService.stop(),
clearWindowsVisibleOverlayForegroundPollLoop: () => clearWindowsVisibleOverlayForegroundPollLoop: () =>
clearWindowsVisibleOverlayForegroundPollLoop(), clearWindowsVisibleOverlayForegroundPollLoop(),
clearLinuxMpvFullscreenOverlayRefreshTimeouts: () => clearLinuxMpvFullscreenOverlayRefreshTimeouts: () => {
clearLinuxMpvFullscreenOverlayRefreshTimeouts(), cancelLinuxMpvFullscreenOverlayRefreshBurst = null;
clearLinuxMpvFullscreenOverlayRefreshTimeouts();
},
getMainOverlayWindow: () => overlayManager.getMainWindow(), getMainOverlayWindow: () => overlayManager.getMainWindow(),
clearMainOverlayWindow: () => overlayManager.setMainWindow(null), clearMainOverlayWindow: () => overlayManager.setMainWindow(null),
getModalOverlayWindow: () => overlayManager.getModalWindow(), getModalOverlayWindow: () => overlayManager.getModalWindow(),
@@ -3813,6 +3824,7 @@ const {
lastObservedTimePos = time; lastObservedTimePos = time;
}, },
onFullscreenChange: () => { onFullscreenChange: () => {
cancelLinuxMpvFullscreenOverlayRefreshBurst =
scheduleLinuxVisibleOverlayFullscreenRefreshBurst({ scheduleLinuxVisibleOverlayFullscreenRefreshBurst({
overlayManager: { overlayManager: {
getMainWindow: () => overlayManager.getMainWindow(), getMainWindow: () => overlayManager.getMainWindow(),
@@ -5149,6 +5161,7 @@ const { createMainWindow: createMainWindowHandler, createModalWindow: createModa
onWindowContentReady: () => overlayVisibilityRuntime.updateVisibleOverlayVisibility(), onWindowContentReady: () => overlayVisibilityRuntime.updateVisibleOverlayVisibility(),
onWindowClosed: (windowKind) => { onWindowClosed: (windowKind) => {
if (windowKind === 'visible') { if (windowKind === 'visible') {
cancelPendingLinuxMpvFullscreenOverlayRefreshBurst();
overlayManager.setMainWindow(null); overlayManager.setMainWindow(null);
} else { } else {
overlayManager.setModalWindow(null); overlayManager.setModalWindow(null);
@@ -5396,6 +5409,9 @@ function ensureOverlayWindowsReadyForVisibilityActions(): void {
function setVisibleOverlayVisible(visible: boolean): void { function setVisibleOverlayVisible(visible: boolean): void {
ensureOverlayWindowsReadyForVisibilityActions(); ensureOverlayWindowsReadyForVisibilityActions();
if (!visible) {
cancelPendingLinuxMpvFullscreenOverlayRefreshBurst();
}
if (visible) { if (visible) {
void ensureOverlayMpvSubtitlesHidden(); void ensureOverlayMpvSubtitlesHidden();
} }
@@ -5405,13 +5421,18 @@ function setVisibleOverlayVisible(visible: boolean): void {
function toggleVisibleOverlay(): void { function toggleVisibleOverlay(): void {
ensureOverlayWindowsReadyForVisibilityActions(); ensureOverlayWindowsReadyForVisibilityActions();
if (!overlayManager.getVisibleOverlayVisible()) { if (overlayManager.getVisibleOverlayVisible()) {
cancelPendingLinuxMpvFullscreenOverlayRefreshBurst();
} else {
void ensureOverlayMpvSubtitlesHidden(); void ensureOverlayMpvSubtitlesHidden();
} }
toggleVisibleOverlayHandler(); toggleVisibleOverlayHandler();
syncOverlayMpvSubtitleSuppression(); syncOverlayMpvSubtitleSuppression();
} }
function setOverlayVisible(visible: boolean): void { function setOverlayVisible(visible: boolean): void {
if (!visible) {
cancelPendingLinuxMpvFullscreenOverlayRefreshBurst();
}
if (visible) { if (visible) {
void ensureOverlayMpvSubtitlesHidden(); void ensureOverlayMpvSubtitlesHidden();
} }

View File

@@ -32,7 +32,10 @@ test('linux mpv fullscreen overlay refresh burst schedules overlay refresh work
ensureOverlayWindowLevel: () => calls.push('ensureOverlayWindowLevel'), ensureOverlayWindowLevel: () => calls.push('ensureOverlayWindowLevel'),
}); });
await new Promise((resolve) => setTimeout(resolve, 10)); const deadline = Date.now() + 200;
while (!calls.includes('updateVisibleOverlayVisibility') && Date.now() < deadline) {
await new Promise((resolve) => setTimeout(resolve, 5));
}
assert.ok(calls.includes('updateVisibleOverlayVisibility')); assert.ok(calls.includes('updateVisibleOverlayVisibility'));
assert.ok(calls.includes('hide')); assert.ok(calls.includes('hide'));

View File

@@ -15,6 +15,7 @@ export type LinuxMpvFullscreenOverlayRefreshDeps = {
}; };
ensureOverlayWindowLevel: (window: LinuxMpvFullscreenOverlayWindow) => void; ensureOverlayWindowLevel: (window: LinuxMpvFullscreenOverlayWindow) => void;
}; };
export type CancelLinuxMpvFullscreenOverlayRefreshBurst = () => void;
const LINUX_MPV_FULLSCREEN_OVERLAY_REFRESH_DELAYS_MS = [0, 50, 150, 300, 600] as const; const LINUX_MPV_FULLSCREEN_OVERLAY_REFRESH_DELAYS_MS = [0, 50, 150, 300, 600] as const;
let linuxMpvFullscreenOverlayRefreshTimeouts: Array<ReturnType<typeof setTimeout>> = []; let linuxMpvFullscreenOverlayRefreshTimeouts: Array<ReturnType<typeof setTimeout>> = [];
@@ -47,9 +48,9 @@ function refreshLinuxVisibleOverlayAfterMpvFullscreenChange(
export function scheduleLinuxVisibleOverlayFullscreenRefreshBurst( export function scheduleLinuxVisibleOverlayFullscreenRefreshBurst(
deps: LinuxMpvFullscreenOverlayRefreshDeps, deps: LinuxMpvFullscreenOverlayRefreshDeps,
): void { ): CancelLinuxMpvFullscreenOverlayRefreshBurst {
if (process.platform !== 'linux') { if (process.platform !== 'linux') {
return; return () => {};
} }
clearLinuxMpvFullscreenOverlayRefreshTimeouts(); clearLinuxMpvFullscreenOverlayRefreshTimeouts();
@@ -63,6 +64,7 @@ export function scheduleLinuxVisibleOverlayFullscreenRefreshBurst(
refreshTimeout.unref?.(); refreshTimeout.unref?.();
linuxMpvFullscreenOverlayRefreshTimeouts.push(refreshTimeout); linuxMpvFullscreenOverlayRefreshTimeouts.push(refreshTimeout);
} }
return clearLinuxMpvFullscreenOverlayRefreshTimeouts;
} }
export { clearLinuxMpvFullscreenOverlayRefreshTimeouts }; export { clearLinuxMpvFullscreenOverlayRefreshTimeouts };