mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-06-09 15:13:32 -07:00
fix(overlay): Linux X11/XWayland stacking, stale pause state, multi-copy selector (#101)
This commit is contained in:
@@ -19,6 +19,7 @@ The desktop app keeps `src/main.ts` as composition root and pushes behavior into
|
||||
|
||||
- [Domains](./domains.md) - who owns what
|
||||
- [Layering](./layering.md) - how modules should depend on each other
|
||||
- [Subtitle Overlay Priming](./subtitle-overlay-priming.md) - visible-overlay subtitle startup flow
|
||||
- Public contributor summary: [`docs-site/architecture.md`](../../docs-site/architecture.md)
|
||||
|
||||
## Current Shape
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<!-- read_when: changing visible overlay startup, Linux/X11 overlay window shape, mpv subtitle callbacks, or subtitle tokenization emission -->
|
||||
|
||||
# Subtitle Overlay Priming
|
||||
|
||||
Status: active
|
||||
Last verified: 2026-06-01
|
||||
Owner: Kyle Yasuda
|
||||
Read when: debugging subtitle state or blank Linux/X11 overlay windows when the visible overlay is shown or recreated
|
||||
|
||||
Visible-overlay subtitle priming fills the overlay from mpv's current subtitle properties before
|
||||
waiting for the next live mpv subtitle event. This avoids a stale or blank overlay when the user
|
||||
manually shows the visible overlay while playback is already sitting on a subtitle.
|
||||
|
||||
On Linux/X11, visible-overlay show and later mpv bounds refreshes restore the Electron window shape
|
||||
to the full current overlay bounds. Electron's `BrowserWindow.setShape()` applies a bounding shape,
|
||||
not an input-only region; stale shapes can leave a mapped 1920x1080 overlay with smaller X11 shape
|
||||
extents such as `800x600+0+0`, so renderer and websocket subtitle state are correct while bottom
|
||||
subtitles do not draw.
|
||||
|
||||
## Entry Points
|
||||
|
||||
- `src/main.ts` calls `primeCurrentSubtitleForVisibleOverlay()` when manual visible-overlay show
|
||||
paths run.
|
||||
- `src/main.ts` calls `restoreVisibleOverlayWindowShapeForShow()` before visible-overlay show
|
||||
actions on Linux, and `resetVisibleOverlayInputState()` restores a full shape instead of applying
|
||||
an empty shape.
|
||||
- `src/main.ts` also restores the Linux/X11 shape after applying mpv overlay bounds, so a newly
|
||||
created 800x600 hidden Electron window cannot keep clipping after it is resized to mpv geometry.
|
||||
- `primeCurrentSubtitleForVisibleOverlay()` delegates to
|
||||
`primeVisibleOverlaySubtitleFromMpv()` in `src/main/runtime/current-subtitle-snapshot.ts`.
|
||||
- `restoreVisibleOverlayWindowShapeForShow()` delegates to `restoreLinuxOverlayWindowShape()` in
|
||||
`src/main/runtime/linux-overlay-window-shape.ts`.
|
||||
- Inputs are callback deps, not globals: `getMpvClient`, `setCurrentSubText`,
|
||||
`getCurrentSubtitleData`, `consumeCachedSubtitle`, `onSubtitleChange`,
|
||||
`refreshCurrentSubtitle`, `emitSubtitle`, optional secondary-subtitle callbacks, and `logDebug`.
|
||||
|
||||
## Primary Subtitle Flow
|
||||
|
||||
1. Read the connected mpv client through `getMpvClient()`. Exit if no connected client.
|
||||
2. Request mpv `sub-text`. On failure, log a
|
||||
`[visible-overlay-subtitle-prime] failed to read sub-text` debug line and exit.
|
||||
3. Normalize non-string `sub-text` to `''`, then call `setCurrentSubText(text)` so app state
|
||||
matches mpv before any overlay emission.
|
||||
4. Empty text: call `onSubtitleChange(text)`, emit `{ text, tokens: null }`, then prime secondary
|
||||
subtitles.
|
||||
5. Current cached payload: if `getCurrentSubtitleData()?.text === text`, call
|
||||
`emitSubtitle(payload)` and `refreshCurrentSubtitle(text)`, then prime secondary subtitles.
|
||||
6. Tokenization cache hit: call `consumeCachedSubtitle(text)`, `onSubtitleChange(text)`, and
|
||||
`emitSubtitle(cachedPayload)`, then prime secondary subtitles.
|
||||
7. Cache miss: call `refreshCurrentSubtitle(text)` and let normal tokenization emit the final
|
||||
payload.
|
||||
|
||||
In `src/main.ts`, both `onSubtitleChange` and `refreshCurrentSubtitle` pause
|
||||
`subtitlePrefetchService`, notify it with `onSeek(lastObservedTimePos)`, and then call the matching
|
||||
`subtitleProcessingController` method. This gives the visible overlay priority over background
|
||||
prefetch work and re-centers prefetch around the live playback time.
|
||||
|
||||
## Emitted State
|
||||
|
||||
- `emitSubtitle(payload)` maps to `emitSubtitlePayload(payload)`, which sends the normal
|
||||
annotated subtitle payload to overlay windows and subtitle websocket listeners.
|
||||
- Secondary priming reads mpv `secondary-sub-text`, stores it in
|
||||
`mpvClient.currentSecondarySubText`, and broadcasts `secondary-subtitle:set` to overlay windows.
|
||||
- If secondary `requestProperty` fails, the primary flow stays complete and only a debug line is
|
||||
written.
|
||||
|
||||
## Linux/X11 Window Shape
|
||||
|
||||
- `restoreLinuxOverlayWindowShape()` reads `BrowserWindow.getBounds()` and calls `setShape()` with
|
||||
one full-window rectangle: `{ x: 0, y: 0, width, height }`.
|
||||
- Restore the shape after `setBounds()`/mpv geometry updates, not only before showing the overlay.
|
||||
Manual startup can create the hidden overlay at Electron's default 800x600 size before the window
|
||||
tracker applies the real mpv bounds.
|
||||
- Do not use `setShape([])` as a passive reset for the visible overlay. On the tested X11/XWayland
|
||||
path, empty or stale bounding shapes produced invisible or clipped subtitles even though the
|
||||
overlay window remained mapped above mpv.
|
||||
- Pointer pass-through should continue to use `setIgnoreMouseEvents(true, { forward: true })` and
|
||||
the Linux cursor-poll fallback, not bounding-shape clipping.
|
||||
|
||||
## Config And Migration
|
||||
|
||||
No config or schema migration. This workflow reuses existing mpv properties, overlay IPC events,
|
||||
subtitle tokenization cache, and prefetch controls.
|
||||
Reference in New Issue
Block a user