refactor: delete two orphans, and record why the reparent design changed

`resolveVideoSource` chose between a local file and a remote URL for video
playback. Backend-owned stream selection took that decision into Rust —
`media_local_selection` for a downloaded file, `get_stream_selection` for a
streamed one — and its last caller went with it. What remained was the function
plus sixty lines of tests exercising nothing that ships.

`fittedVideoSize` computed the rendered size of a video letterboxed into its
container. Nothing has ever called it: it arrived with the fix that made the
video fill its viewport and was superseded by `object-fit: contain` in the same
change. There is some irony in a helper that models letterboxing sitting unused
beside a container that was not letterboxing at all — the bug fixed in the
previous commit was CSS, and this function would not have helped.

A survey for exported symbols referenced only by their own tests finds 22 more.
Most are legitimate — test mocks, deliberate reset hooks, public utility APIs —
and the rest are unrelated to this work, so they are left for a cleanup that can
be reviewed on its own terms rather than smuggled into a playback branch.

Also records in the spec why DR-231's design changed. Reparenting Tauri's
webview into a GtkOverlay aborts the process on the first click: Linux calls
`attach_resize_handler` unconditionally (the Windows path guards it with
`is_decorated()`), and its handler walks webview -> GtkBox -> GtkWindow with an
unwrap that an overlay breaks. So the webview is not moved at all — mpv draws
into the default vbox's own `draw` handler via `gdk_cairo_draw_from_gl()`, and
GTK's container-before-children order puts the webview on top for free. No
reparent, one less widget, and nothing a Tauri upgrade can invalidate by
assuming its own layout.
This commit is contained in:
2026-08-22 13:45:04 +02:00
parent 0445a6d0aa
commit 7545de6cc7
6 changed files with 211 additions and 387 deletions
+29 -5
View File
@@ -143,17 +143,41 @@ differs per platform:
| Platform | Surface | Status |
|---|---|---|
| Linux (X11 + Wayland) | `GtkOverlay`: `GtkGLArea` main child, Tauri's webview reparented as overlay child, via `WebviewWindow::gtk_window()` / `default_vbox()` | Proven by the spike, bar the reparent |
| Linux (X11 + Wayland) | `gdk_cairo_draw_from_gl()` in the default vbox's `draw` handler, over a `GdkGLContext` on its `GdkWindow`. No reparenting — see below | Render path proven by the spike; the *overlay* approach it used is rejected |
| Windows | Native HWND child beneath a transparent WebView2 | Phase 2 |
`vo=libmpv` plus `mpv_render_context_create` with `MPV_RENDER_PARAM_OPENGL_FBO`.
Webview transparency via `with_transparent(true)` — no window-level transparency;
the spike showed it is neither used nor needed.
**The untested half of G1 is the reparent.** The spike built its own overlay; the
app must adopt Tauri's. Same widgets, one extra step, but it is the only place
Tauri-specific behaviour can still bite — so it is the first gate, proven before
anything is built on it.
**G1's untested half failed, and the design changed because of it.**
Reparenting Tauri's webview into a `GtkOverlay` attaches cleanly and then aborts
the process on the first click. `tauri-runtime-wry` connects a
button-press handler to the webview that walks a hard-coded path:
```rust
webview.parent() // "This one should be GtkBox"
.parent() // ...and this one the GtkWindow
.downcast::<gtk::Window>().unwrap()
```
An overlay makes that chain `webview → GtkOverlay → GtkBox`, the downcast fails,
and the panic is non-unwinding so it kills the app. Nothing in configuration
avoids it: on Linux `attach_resize_handler` is called **unconditionally** (the
Windows equivalent is guarded by `is_decorated()`), and the decoration check that
would make the handler inert runs *after* the unwrap.
**So the webview is not moved at all.** mpv draws into the *default vbox's own
`draw` handler* instead, via `gdk_cairo_draw_from_gl()` over a `GdkGLContext`
created on that widget's `GdkWindow`. GTK3 draws a container before its children,
so the webview composites on top for free — the same z-order the overlay was for,
without touching the widget tree Tauri walks.
That is strictly better than the overlay it replaces: no reparent, no extra
widget, and the arrangement cannot be broken by a Tauri upgrade that assumes its
own layout. It is also why "the surface attached successfully" is not the gate —
a click is.
Three traps from the spike, each of which cost a debugging cycle and each of
which looks like a platform limitation and is not:
+180 -194
View File
@@ -1,11 +1,11 @@
# Code Traceability Matrix
**Generated:** 8/22/2026, 10:39:30 AM
**Generated:** 8/22/2026, 11:26:46 AM
## Summary
- **Total Files Scanned:** 394
- **Total TRACES Found:** 1093
- **Total TRACES Found:** 1092
- **Requirements Covered:**
- User Requirements (UR): 79
- Integration Requirements (IR): 26
@@ -3037,14 +3037,11 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
### DR-123
**Locations:** 7 file(s)
**Locations:** 6 file(s)
- **File:** [`src/lib/api/bindings.ts`](../src/lib/api/bindings.ts#L389)
- **Line:** 389
- **Context:** `Unknown`
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L12)
- **Line:** 12
- **Context:** `Unknown`
- **File:** [`src/routes/player/[id]/+page.svelte`](../src/routes/player/[id]/+page.svelte#L405)
- **Line:** 405
- **Context:** `Unknown`
@@ -3265,8 +3262,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
**Locations:** 2 file(s)
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L55)
- **Line:** 55
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
- **File:** [`src/routes/player/[id]/+page.svelte`](../src/routes/player/[id]/+page.svelte#L314)
- **Line:** 314
@@ -7523,22 +7520,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 8
- **Context:** `Unknown`
### IT-016
**Locations:** 1 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3026)
- **Line:** 3026
- **Context:** `Unknown`
### IT-017
**Locations:** 1 file(s)
- **File:** [`src-tauri/src/commands/catalog.rs`](../src-tauri/src/commands/catalog.rs#L878)
- **Line:** 878
- **Context:** `Unknown`
### UT-003
**Locations:** 1 file(s)
@@ -7739,6 +7720,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
**Locations:** 1 file(s)
- **File:** [`src-tauri/src/player/backend.rs`](../src-tauri/src/player/backend.rs#L251)
- **Line:** 251
- **Context:** `Unknown`
### UT-030
**Locations:** 1 file(s)
- **File:** [`src-tauri/src/player/backend.rs`](../src-tauri/src/player/backend.rs#L251)
- **Line:** 251
- **Context:** `Unknown`
@@ -8779,14 +8768,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 929
- **Context:** `Unknown`
### UT-062
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/backgroundAudio.test.ts`](../src/lib/utils/backgroundAudio.test.ts#L7)
- **Line:** 7
- **Context:** `Unknown`
### UT-066
**Locations:** 1 file(s)
@@ -8795,12 +8776,12 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 4
- **Context:** `Unknown`
### UT-071
### UT-067
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/formatBytes.test.ts`](../src/lib/utils/formatBytes.test.ts#L4)
- **Line:** 4
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3026)
- **Line:** 3026
- **Context:** `Unknown`
### UT-072
@@ -8956,46 +8937,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 15
- **Context:** `Unknown`
### UT-094
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/safeArea.test.ts`](../src/lib/utils/safeArea.test.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-095
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/safeArea.test.ts`](../src/lib/utils/safeArea.test.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-096
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/safeArea.test.ts`](../src/lib/utils/safeArea.test.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-097
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/safeArea.test.ts`](../src/lib/utils/safeArea.test.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-098
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/layoutShell.test.ts`](../src/lib/utils/layoutShell.test.ts#L158)
- **Line:** 158
- **Context:** `Unknown`
### UT-099
**Locations:** 3 file(s)
@@ -9033,6 +8974,34 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 3869
- **Context:** `Unknown`
### UT-101
**Locations:** 4 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L2014)
- **Line:** 2014
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L4370)
- **Line:** 4370
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L4405)
- **Line:** 4405
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/mod.rs`](../src-tauri/src/repository/mod.rs#L238)
- **Line:** 238
- **Context:** `Unknown`
### UT-102
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L688)
- **Line:** 688
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L4605)
- **Line:** 4605
- **Context:** `Unknown`
### UT-103
**Locations:** 6 file(s)
@@ -9133,14 +9102,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 1106
- **Context:** `Unknown`
### UT-118
**Locations:** 1 file(s)
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L12)
- **Line:** 12
- **Context:** `Unknown`
### UT-123
**Locations:** 2 file(s)
@@ -9156,8 +9117,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
**Locations:** 1 file(s)
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L55)
- **Line:** 55
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-131
@@ -10189,6 +10150,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 4413
- **Context:** `Unknown`
### IT-017
**Locations:** 1 file(s)
- **File:** [`src-tauri/src/commands/catalog.rs`](../src-tauri/src/commands/catalog.rs#L878)
- **Line:** 878
- **Context:** `Unknown`
### UT-060
**Locations:** 4 file(s)
@@ -10206,6 +10175,22 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 110
- **Context:** `Unknown`
### UT-062
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/backgroundAudio.test.ts`](../src/lib/utils/backgroundAudio.test.ts#L7)
- **Line:** 7
- **Context:** `Unknown`
### UT-071
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/formatBytes.test.ts`](../src/lib/utils/formatBytes.test.ts#L4)
- **Line:** 4
- **Context:** `Unknown`
### UT-086
**Locations:** 2 file(s)
@@ -10250,6 +10235,46 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 8
- **Context:** `Unknown`
### UT-094
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/safeArea.test.ts`](../src/lib/utils/safeArea.test.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-095
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/safeArea.test.ts`](../src/lib/utils/safeArea.test.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-096
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/safeArea.test.ts`](../src/lib/utils/safeArea.test.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-097
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/safeArea.test.ts`](../src/lib/utils/safeArea.test.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
### UT-098
**Locations:** 1 file(s)
- **File:** [`src/lib/utils/layoutShell.test.ts`](../src/lib/utils/layoutShell.test.ts#L158)
- **Line:** 158
- **Context:** `Unknown`
### UT-108
**Locations:** 2 file(s)
@@ -10261,20 +10286,51 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 550
- **Context:** `Unknown`
### UT-109
### UT-111
**Locations:** 1 file(s)
**Locations:** 3 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3306)
- **Line:** 3306
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L62)
- **Line:** 62
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L2548)
- **Line:** 2548
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L2588)
- **Line:** 2588
- **Context:** `Unknown`
### UT-110
### UT-112
**Locations:** 1 file(s)
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3362)
- **Line:** 3362
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L501)
- **Line:** 501
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3253)
- **Line:** 3253
- **Context:** `Unknown`
### UT-113
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L276)
- **Line:** 276
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3144)
- **Line:** 3144
- **Context:** `Unknown`
### UT-114
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L333)
- **Line:** 333
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3087)
- **Line:** 3087
- **Context:** `Unknown`
### UT-116
@@ -10702,6 +10758,17 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 3394
- **Context:** `Unknown`
### UT-171
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/commands/catalog.rs`](../src-tauri/src/commands/catalog.rs#L916)
- **Line:** 916
- **Context:** `Unknown`
- **File:** [`src-tauri/src/commands/catalog.rs`](../src-tauri/src/commands/catalog.rs#L957)
- **Line:** 957
- **Context:** `Unknown`
### UT-172
**Locations:** 3 file(s)
@@ -11096,7 +11163,7 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
### UR-071
**Locations:** 67 file(s)
**Locations:** 66 file(s)
- **File:** [`src/lib/api/bindings.ts`](../src/lib/api/bindings.ts#L389)
- **Line:** 389
@@ -11110,11 +11177,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **File:** [`src/lib/api/bindings.ts`](../src/lib/api/bindings.ts#L2085)
- **Line:** 2085
- **Context:** `Unknown`
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L12)
- **Line:** 12
- **Context:** `Unknown`
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L55)
- **Line:** 55
- **File:** [`src/lib/player/localSource.ts`](../src/lib/player/localSource.ts#L17)
- **Line:** 17
- **Context:** `Unknown`
- **File:** [`src/routes/player/[id]/+page.svelte`](../src/routes/player/[id]/+page.svelte#L314)
- **Line:** 314
@@ -12318,14 +12382,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 1286
- **Context:** `Unknown`
### UT-030
**Locations:** 1 file(s)
- **File:** [`src-tauri/src/player/backend.rs`](../src-tauri/src/player/backend.rs#L251)
- **Line:** 251
- **Context:** `Unknown`
### UT-031
**Locations:** 1 file(s)
@@ -12350,81 +12406,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 251
- **Context:** `Unknown`
### UT-101
**Locations:** 4 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L2014)
- **Line:** 2014
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L4370)
- **Line:** 4370
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L4405)
- **Line:** 4405
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/mod.rs`](../src-tauri/src/repository/mod.rs#L238)
- **Line:** 238
- **Context:** `Unknown`
### UT-102
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L688)
- **Line:** 688
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L4605)
- **Line:** 4605
- **Context:** `Unknown`
### UT-111
**Locations:** 3 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L62)
- **Line:** 62
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L2548)
- **Line:** 2548
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L2588)
- **Line:** 2588
- **Context:** `Unknown`
### UT-112
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L501)
- **Line:** 501
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3253)
- **Line:** 3253
- **Context:** `Unknown`
### UT-113
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L276)
- **Line:** 276
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3144)
- **Line:** 3144
- **Context:** `Unknown`
### UT-114
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L333)
- **Line:** 333
- **Context:** `Unknown`
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3087)
- **Line:** 3087
- **Context:** `Unknown`
### UT-115
**Locations:** 2 file(s)
@@ -12615,17 +12596,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 3788
- **Context:** `Unknown`
### UT-171
**Locations:** 2 file(s)
- **File:** [`src-tauri/src/commands/catalog.rs`](../src-tauri/src/commands/catalog.rs#L916)
- **Line:** 916
- **Context:** `Unknown`
- **File:** [`src-tauri/src/commands/catalog.rs`](../src-tauri/src/commands/catalog.rs#L957)
- **Line:** 957
- **Context:** `Unknown`
### UT-173
**Locations:** 5 file(s)
@@ -12974,7 +12944,7 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 1239
- **Context:** `Unknown`
### UT-067
### IT-016
**Locations:** 1 file(s)
@@ -12982,4 +12952,20 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-006, JA-007, JA-008, JA-009, JA-010,
- **Line:** 3026
- **Context:** `Unknown`
### UT-109
**Locations:** 1 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3306)
- **Line:** 3306
- **Context:** `Unknown`
### UT-110
**Locations:** 1 file(s)
- **File:** [`src-tauri/src/repository/offline.rs`](../src-tauri/src/repository/offline.rs#L3362)
- **Line:** 3362
- **Context:** `Unknown`