cmux-next: background and Chief picture settings (video playback, battery, keep clear of panes, picture motion)

Closed
TE
10d ago
+16078-17374

Phase 5 of the backgrounds plan: the settings Leo approved (through the coordinator). It's one schema PR, so the Air Blue coordinator clears WINDOW once.

Stacked: this branch is next-batch/leo-backgrounds (feat-cmux-next plus #21743, which carries #21709 and #21731, plus #21720 and #21740/#21737) with two commits on top. Review only fb08d69c804 (background video and framing) and 9d8f72c2ab3 (Chief picture motion). It needs #21709's framing and #21720's video players.

What changes

KeyChoicesDefault
appearance.backgroundVideoPlay / Only While cmux Is Active / Still PicturePlay
appearance.backgroundVideoOnBatteryKeep Playing / PauseKeep Playing (Low Power Mode already pauses)
appearance.backgroundAvoidPaneson/offon
home.chiefPictureMotionAlways / On Hover / NeverOn Hover (Never under Reduce Motion)
  • Rows sit under Appearance > Window Background (BackdropPlaybackSettingsSchema). They're agent-settable like appearance.background.
  • Parsing: BackdropPlaybackConfigParser uses ConfigFieldReader, so a bad value keeps the default and adds a diagnostic. SettingsApplier copies the result into DesignSettings.backdropPlayback.
  • Video (BackdropVideoView):
    • Still Picture never plays. It counts as unseen, so its decoder is given back after the phase 2 minute and the first frame stays.
    • Only While cmux Is Active follows NSApp.isActive (didBecome/ResignActive).
    • Pause on battery follows BackdropPower, a small IOKit power-source watcher on the main run loop.
    • Settings changes apply live through ObservationStream.
  • Framing (WindowMaterialView): with Keep Paintings Clear of Panes off, art frames itself in the whole window. The toggle applies live.
  • Chief pictures (home.chiefPictureMotion, a Home > Chief Pictures row, agent-settable):
    • Pages get the motion as data-picture-motion on <html>, carried with the theme (WebTheme.pictureMotion), the same way data-status-indicators is. ChiefPictureMotion.effective makes it Never under Reduce Motion.
    • The web Avatar shows a GIF or animated WebP as its first frame, drawn once to a still. It moves only when the setting is Always, or while the pointer is over it when it's On Hover.
    • The native Home header shows the first frame unless the setting is Always. It follows the setting and Reduce Motion live.
    • The sidebar tile is always a still square copy (squared() now covers animated pictures too), so a non-square GIF is no longer stretched there. The tile is a 20 pt icon, where motion is only noise.
    • Native hover animation in the header isn't wired: the header view is vendored MessagesLab, so On Hover shows the still there.
  • CmuxNextApp: 4 source lines down against base (no App changes in this commit).

WINDOW (settings schema)

Settings schema: 4 new keys. Air Blue coordinator, please clear.

  • Exports not hand-edited: schemas/settings/settings-schema.json, the MDM docs and the defaults snapshot are regenerated by the base-autofix bot (regenerate-settings-exports.sh), per that script.
  • Not in this PR:
    • built-in video ids in appearance.background, because there are no built-in videos yet; the value grammar change waits for the first one
    • the "Adjust Background…" catalog action, which needs an App handler, and the App is at its cap; phase 6's Settings button covers it for now

Strings

14 new keys, all 21 locales, in CmuxNextSettings/Localizable.xcstrings. It reuses the existing settings.group.windowBackground and settings.choice.always, onHover and never.

Tests

  • CmuxNextSettingsTests/BackdropPlaybackSettingTests:
    • defaults
    • every value parses
    • bad values keep the default and add a diagnostic
    • the rows offer every choice with the right defaults, and agents may set them
  • CmuxNextAppTests/VideoWallpaperTests.thePlaybackSettingsHoldTheVideo:
    • Still holds the video and gives back the decoder
    • Only While Active follows the app
    • Pause follows battery and power
  • CmuxNextAppTests/BackdropArtFramingTests: with avoidPanes off, the art frames to the whole window, and back.
  • chiefPictureMotionParsesAndHasItsRow: parse, a bad value, the row and agent-settable.
  • ChiefPictureMotionTests:
    • first-frame stills for an animated picture
    • a still picture is left untouched
    • Reduce Motion makes it never move
  • ChiefPictureFilesTests.anAnimatedPictureGetsAStillTile: square and non-square GIFs both get a still square PNG.
  • Web test/home-chief-picture-motion.test.tsx (3/3 pass): always, never, hover in and out, and a PNG is never held back.

Verification

Changelog

Added: Settings for video backgrounds (play, only while cmux is active, or a still picture; pause on battery), for keeping paintings clear of the panes, and for when animated Chief pictures move.

🤖 Generated with Claude Code