fix: refresh overlay on Hyprland fullscreen

This commit is contained in:
2026-04-26 19:22:56 -07:00
parent 9e4ad907fe
commit ab41837d3d
19 changed files with 381 additions and 21 deletions

View File

@@ -59,6 +59,7 @@ const MPV_SUBTITLE_PROPERTY_OBSERVATIONS: string[] = [
'sub-ass-override',
'sub-use-margins',
'pause',
'fullscreen',
'duration',
'media-title',
'secondary-sub-visibility',

View File

@@ -93,6 +93,7 @@ function createDeps(overrides: Partial<MpvProtocolHandleMessageDeps> = {}): {
emitTimePosChange: () => {},
emitDurationChange: () => {},
emitPauseChange: () => {},
emitFullscreenChange: (payload) => state.events.push(payload),
autoLoadSecondarySubTrack: () => {},
setCurrentVideoPath: () => {},
emitSecondarySubtitleVisibility: (payload) => state.events.push(payload),
@@ -160,6 +161,17 @@ test('dispatchMpvProtocolMessage enforces sub-visibility hidden when overlay sup
]);
});
test('dispatchMpvProtocolMessage emits fullscreen changes', async () => {
const { deps, state } = createDeps();
await dispatchMpvProtocolMessage(
{ event: 'property-change', name: 'fullscreen', data: true },
deps,
);
assert.deepEqual(state.events, [{ fullscreen: true }]);
});
test('dispatchMpvProtocolMessage skips sub-visibility suppression when overlay is hidden', async () => {
const { deps, state } = createDeps({
isVisibleOverlayVisible: () => false,

View File

@@ -65,6 +65,7 @@ export interface MpvProtocolHandleMessageDeps {
emitTimePosChange: (payload: { time: number }) => void;
emitDurationChange: (payload: { duration: number }) => void;
emitPauseChange: (payload: { paused: boolean }) => void;
emitFullscreenChange: (payload: { fullscreen: boolean }) => void;
emitSubtitleMetricsChange: (payload: Partial<MpvSubtitleRenderMetrics>) => void;
setCurrentSecondarySubText: (text: string) => void;
resolvePendingRequest: (requestId: number, message: MpvMessage) => boolean;
@@ -291,6 +292,8 @@ export async function dispatchMpvProtocolMessage(
}
} else if (msg.name === 'pause') {
deps.emitPauseChange({ paused: asBoolean(msg.data, false) });
} else if (msg.name === 'fullscreen') {
deps.emitFullscreenChange({ fullscreen: asBoolean(msg.data, false) });
} else if (msg.name === 'media-title') {
deps.emitMediaTitleChange({
title: typeof msg.data === 'string' ? msg.data.trim() : null,

View File

@@ -57,6 +57,22 @@ test('MpvIpcClient handles sub-text property change and broadcasts tokenized sub
assert.equal(events[0]!.isOverlayVisible, false);
});
test('MpvIpcClient emits fullscreen property changes', async () => {
const events: Array<{ fullscreen: boolean }> = [];
const client = new MpvIpcClient('/tmp/mpv.sock', makeDeps());
client.on('fullscreen-change', (payload) => {
events.push(payload);
});
await invokeHandleMessage(client, {
event: 'property-change',
name: 'fullscreen',
data: true,
});
assert.deepEqual(events, [{ fullscreen: true }]);
});
test('MpvIpcClient clears cached media title when media path changes', async () => {
const client = new MpvIpcClient('/tmp/mpv.sock', makeDeps());

View File

@@ -119,6 +119,7 @@ export interface MpvIpcClientEventMap {
'time-pos-change': { time: number };
'duration-change': { duration: number };
'pause-change': { paused: boolean };
'fullscreen-change': { fullscreen: boolean };
'secondary-subtitle-change': { text: string };
'subtitle-track-change': { sid: number | null };
'subtitle-track-list-change': { trackList: unknown[] | null };
@@ -330,6 +331,9 @@ export class MpvIpcClient implements MpvClient {
this.playbackPaused = payload.paused;
this.emit('pause-change', payload);
},
emitFullscreenChange: (payload) => {
this.emit('fullscreen-change', payload);
},
emitSecondarySubtitleChange: (payload) => {
this.emit('secondary-subtitle-change', payload);
},

View File

@@ -67,6 +67,8 @@ export function ensureOverlayWindowLevel(window: BrowserWindow): void {
return;
}
window.setAlwaysOnTop(true);
window.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
window.moveTop();
}
export function enforceOverlayLayerOrder(options: {