Skip to content

feat(wallpaper): animation rotation engine#14

Closed
Charliechen114514 wants to merge 4 commits into
mainfrom
feat/wallpaper-animation-engine
Closed

feat(wallpaper): animation rotation engine#14
Charliechen114514 wants to merge 4 commits into
mainfrom
feat/wallpaper-animation-engine

Conversation

@Charliechen114514

Copy link
Copy Markdown
Member

Summary

CFDesktop's wallpaper layer swapped images instantly with no transition or timed rotation. This ports CCIMXDesktop's WallPaperEngine + animation handler semantics, re-expressed as backend-agnostic per-frame QImage compositing (no QLabel/QWidget coupling), driven through the shell layer strategy. Includes a follow-up perf pass to remove per-frame allocation.

Changes

  • TransitionComposer (new): pure composeTransitionFrame() / composeTransitionFrameInto() blend prev+cur per progress for Gradient (cross-fade) / Movement (slide) / Fixed.
  • WallPaperEngine (new): config-driven QTimer rotation with Sequential/Random selectors (selectNextWallpaper pure fn) and size()>1 / Fixed / disable_animation guards.
  • WallPaperAccessStorage: add tokenIds() for the Random selector.
  • WallpaperShellLayerStrategy: transition state machine driven by QVariantAnimation; beginTransition arms state, the layer switch fires onWallpaperChanged which runs the per-frame animation; triggerNextWallpaper() reuses the path for a future chooser UI.
  • wallpaper_setup: make_layer() reads scaling/background_color from config (previously hard-coded zombie keys).
  • Config: 6 new switch_* keys in WALLPAPER_CONFIG_TEMPLATE (desktop_settings.template.h.in).
  • Tests: 16 cases (composer / selector / engine); full suite 13/13.

Decisions

  • Selectors: both Sequential + Random (switch_selector), default Sequential.
  • 6ULL / low-perf: config-only disable_animation (no HWTier wiring this batch).
  • QVariantAnimation (not QPropertyAnimation) — keeps the strategy a plain IShellLayerStrategy impl, no QObject multi-inheritance / MOC / Q_PROPERTY.
  • The engine never switches the layer itself (a switch synchronously fires the layer callback); it only emits a request, the strategy arms state then switches.

Perf pass

composeTransitionFrameInto() writes back into cached_scaled_image (reusing the buffer — no per-frame ~8MB allocation at 1080p) and drops the redundant fill(black). First frame detaches once; subsequent frames are in-place.

Verification

  • Three-layer grep ✅ / Doxygen lint ✅ / fast build ✅ / full tests 13/13 ✅.
  • Manual end-to-end on WSLg: pending (this PR).

🤖 Generated with Claude Code

The resource-pack discovery (PR #13) landed; the wallpaper layer still
swaps images instantly with no timed rotation or transition animation.
Add a self-contained handoff doc for the next batch: porting CCIMXDesktop's
WallPaperEngine + WallPaperAnimationHandler (Fixed/Gradient/Movement +
QTimer), re-expressed for CFDesktop's backend-agnostic WallPaperLayer —
compose old+new QImage per frame driven by QPropertyAnimation, repaint
each frame, instead of CCIMXDesktop's QLabel double-buffer.

- new document/todo/desktop/wallpaper_animation_engine.md: context,
  source references, target architecture, step-by-step todos, config
  keys, constraints (three-layer/doxygen/ownership/no-silent-fallback/
  perf), verification, open decisions, file cheat-sheet.
- 13_widget_apps.md: wallpaper section points to the new plan.
- status/current.md: the "deferred to next batch" line now links to it.
Port CCIMXDesktop's WallPaperEngine + animation handler semantics into
CFDesktop's backend-agnostic wallpaper layer, re-expressed as per-frame
QImage compositing instead of QLabel double-buffering.

- TransitionComposer: pure composeTransitionFrame() blends prev+cur per
  progress for Gradient (cross-fade), Movement (slide), Fixed.
- WallPaperEngine: config-driven QTimer rotation with Sequential/Random
  selectors (selectNextWallpaper pure fn) and size/Fixed/disable guards.
- WallPaperAccessStorage: add tokenIds() for the Random selector.
- WallpaperShellLayerStrategy: transition state machine driven by
  QVariantAnimation; beginTransition arms state, the layer switch fires
  onWallpaperChanged which runs the per-frame animation. triggerNextWallpaper
  reuses the path for future manual switching.
- wallpaper_setup: make_layer() reads scaling/background_color from config
  (previously hard-coded zombie keys).
- Config: 6 new switch_* keys in WALLPAPER_CONFIG_TEMPLATE.
- Tests: 16 cases (composer/selector/engine), all green; full suite 13/13.
- wallpaper_animation_engine.md: status -> done; append implementation
  record (files, 3 doc corrections, decisions, engineering choices,
  verification).
- status/current.md: wallpaper line reflects the landed engine.
- 13_widget_apps.md: wallpaper rotation section marked landed.
composeTransitionFrame allocated a new target-sized QImage (~8MB at
1080p) and filled it black on every animation frame — ~1GB of malloc/free
over a 120-frame transition, the main source of stutter.

- Add composeTransitionFrameInto(dst, ...) that composes in place with no
  fill (prev+cur fully cover dst for every mode).
- WallpaperShellLayerStrategy::composeFrame now writes back into
  cached_scaled_image, reusing the buffer (first write detaches once,
  subsequent frames are in place).
- composeTransitionFrame (test convenience) becomes fill + composeInto, so
  existing unit tests are unchanged.
@Charliechen114514 Charliechen114514 deleted the feat/wallpaper-animation-engine branch June 30, 2026 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant