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

View File

@@ -32,7 +32,10 @@ test('linux mpv fullscreen overlay refresh burst schedules overlay refresh work
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('hide'));

View File

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