Footage: one watcher thread that wakes the interface only when a file changed, instead of a 2 s poll

Settings ▸ Import ▸ Reload Footage Changed on Disk used to spawn a stat thread every two seconds
from the UI thread, request a repaint 100 ms later to collect it, and request another repaint every
2 s in between, for every project with items, focused or not: the whole interface redrew on a timer
for footage that hadn't changed.

`footage_reload::Watcher` is one long-lived worker: the interface tells it what to watch (recomputed
when the project revision or the preference changes) and whether the window is in front; it stamps
the files every 2 s while the window is in front, every 10 s while another app has the front, at once
on focus regain and on a new set, and hands the stamps over — calling `ctx.request_repaint()` — only
when one differs from its last look. Nothing watched means the thread sleeps. `apply_stamps` and the
reload semantics are unchanged; `start_scan`/`poll_scan`/`Session::footage_scan` are gone. No new
dependencies: the stat loop is also what footage on a network share relies on, where FSEvents would
not report another machine's writes.

Tests: the watcher wakes the interface for the first stamps and for each change and never for an
unchanged file; behind another app it rests until the window is back; nothing watched is nothing
stamped and a new set is reported whole (and dropping it ends the thread); the host test
`the_watcher_notices_a_footage_file_changed_on_disk` saves a PSD from "another app" and sees it
reloaded once.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Jason Luker
2026-10-29 15:41:53 -07:00
co-authored by Claude Fable 5.1
parent 2a61a05fd4
commit 26e6145cee
8 changed files with 328 additions and 70 deletions
+5 -3
View File
@@ -120,9 +120,11 @@ Commands (CLI, MCP, control channel):
- `import.reportMissingFrames`: gaps in an image sequence's numbering are reported on import
(they show as colour-bar placeholders, as in After Effects; see [footage.md](footage.md))
- `import.autoReloadFootage`: Automatically Reload Footage, `off`, `nonSequence` (the default, as
in After Effects) or `all` (image sequences too). Every two seconds,
and as soon as the window comes back to the front, the desktop app compares each footage file's
size and modification time with what they were, and reloads what another app saved: a
in After Effects) or `all` (image sequences too). Every two seconds while its window is in
front (every ten seconds while another app has the front), and as soon as the window comes back
to the front, the desktop app compares each footage file's size and modification time with what
they were, on a worker thread that only wakes the interface when something changed, and reloads
what another app saved: a
Photoshop file edited in PhotoCraft or Photoshop shows its new pixels without File ▸ Reload
Footage. It is not an undo step and doesn't modify the project; a layer item stays on its layer
(found again by name), and a file that can't be read yet (still being written) is tried again once it changes again.