Concrete PhosphorLayer::ISurfaceAnimator driving show/hide via phosphor-animation Profiles.
More...
#include <phosphor-animation/include/PhosphorAnimation/SurfaceAnimator.h>
Classes | |
| struct | Config |
| Per-role profile + scale tuning bundle. More... | |
Public Member Functions | |
| SurfaceAnimator (PhosphorAnimation::PhosphorProfileRegistry ®istry, Config defaults) | |
| Construct against an explicit registry with caller-supplied defaults. | |
| SurfaceAnimator (PhosphorAnimation::PhosphorProfileRegistry ®istry) | |
| Convenience: registry-only ctor with empty default config. | |
| SurfaceAnimator (PhosphorAnimation::PhosphorProfileRegistry ®istry, PhosphorAnimationShaders::AnimationShaderRegistry *shaderRegistry, Config defaults) | |
| Full constructor with shader registry for Phase 6 transition effects. | |
| ~SurfaceAnimator () override | |
| SurfaceAnimator (const SurfaceAnimator &)=delete | |
| SurfaceAnimator & | operator= (const SurfaceAnimator &)=delete |
| void | registerConfigForRole (const PhosphorLayer::Role &role, Config cfg) |
| Override the configuration for one Role. | |
| Config | configForRole (const PhosphorLayer::Role &role) const |
| Read-only config lookup. | |
| void | setDefaultConfig (Config cfg) |
| Mutable access to the default (unregistered-role fallback). | |
| Config | defaultConfig () const |
| void | setAnimationShaderRegistry (PhosphorAnimationShaders::AnimationShaderRegistry *registry) |
| Install the animation shader registry for Phase 6 shader transitions. | |
| void | beginShow (PhosphorLayer::Surface *surface, QQuickItem *rootItem, const PhosphorLayer::Role &configRole, CompletionCallback onComplete) |
| Role-override show/hide. | |
| void | beginHide (PhosphorLayer::Surface *surface, QQuickItem *rootItem, const PhosphorLayer::Role &configRole, CompletionCallback onComplete) |
| void | setEnabled (bool enabled) |
| Global animation enable/disable. | |
| bool | isEnabled () const |
Dynamic shader uniforms | |
Cross-runtime feature parity with overlay shaders for the per-frame uniforms that don't come from the per-effect static metadata. Most are auto-driven by the animator and need no consumer wiring: • The single uniform that NEEDS consumer wiring is | |
| void | setAudioSpectrum (const QVector< float > &spectrum) |
| Push the latest CAVA / audio-spectrum sample to every active animation shader item. | |
ISurfaceAnimator | |
| void | beginShow (PhosphorLayer::Surface *surface, QQuickItem *rootItem, CompletionCallback onComplete) override |
Begin a show transition for surface. | |
| void | beginHide (PhosphorLayer::Surface *surface, QQuickItem *rootItem, CompletionCallback onComplete) override |
Begin a hide transition for surface. | |
| void | cancel (PhosphorLayer::Surface *surface) override |
Interrupt any in-flight animation for surface. | |
Public Member Functions inherited from PhosphorLayer::ISurfaceAnimator | |
| ISurfaceAnimator ()=default | |
| virtual | ~ISurfaceAnimator ()=default |
Additional Inherited Members | |
Public Types inherited from PhosphorLayer::ISurfaceAnimator | |
| using | CompletionCallback = std::function< void()> |
| Invoked when a show/hide animation completes. | |
Concrete PhosphorLayer::ISurfaceAnimator driving show/hide via phosphor-animation Profiles.
Phase 5 of the phosphor-animation roadmap. Replaces every overlay's hand-rolled QML ParallelAnimation { id: showAnimation } block with a single library-driven runtime that resolves curve + duration from PhosphorProfileRegistry. Live profile reloads (drop a JSON, see it apply on next show) flow through the registry's existing watcher path — the animator re-resolves the path on every beginShow / beginHide and captures the resolved Profile by value into the underlying MotionSpec. In-flight animations therefore keep the Profile they started with through to completion; reloads apply to the next dispatch, not to a currently-running tick. (Verified by the profile_reload_during_flight_does_not_affect_inflight regression test in pal_test_surface_animator.)
The animator carries a default Config plus a per-Role override map. Consumers register configs at construction:
Each surface's role is read from surface->config().role at dispatch time. Surfaces whose role has no registered override use defaultConfig.
beginShow / beginHide drive the QQuickItem's opacity property (always, 0↔1) and optionally its scale property (when a scale-profile is configured). Both run in parallel against a shared steady-clock so frame timing aligns. Each property animation is a PhosphorAnimation::AnimatedValue<qreal> ticked at ~60 Hz by an internal QTimer (decoupled from QQuickWindow::beforeRendering so offscreen QPA tests work).
cancel(surface) stops in-flight animations for that surface only. The Phase-5.1 dispatch in Surface calls cancel on every Hidden→Shown / Shown→Hidden transition that supersedes a still- running animation, so the SurfaceAnimator does not have to detect overlap itself — the phosphor-layer side guarantees a clean cancel point before each beginShow / beginHide.
The animator's internal driver invokes a track's onComplete synchronously from inside its own tick loop. Consumers MUST NOT delete the SurfaceAnimator (or anything that owns it) from inside an onComplete callback — the tick loop continues iterating over the track map after invocation, and a destroyed animator strands the loop on freed memory. Deleting the Surface whose animation just completed is safe; the library cancels the animator's tracking entry on Surface destruction. If a callback genuinely needs to tear down the animator, defer the deletion via QTimer::singleShot(0, ...) or a QMetaObject::invokeMethod(..., Qt::QueuedConnection).
Heap-allocated by the consumer (typically the daemon's OverlayService) and passed to SurfaceFactory::Deps::animator. Must outlive every Surface created from that factory; the destructor cancels any still-tracked surface state but does NOT cascade-delete the surfaces themselves.
GUI-thread only. Every method touches QQuickItem / QHash state without synchronisation; the underlying AnimatedValue<T> runtime asserts the same. Construction and registerConfigForRole are typically called once during process / OverlayService startup but must still run on the GUI thread to satisfy the QHash invariant.
|
explicit |
Construct against an explicit registry with caller-supplied defaults.
The animator takes the registry by reference; the registry must outlive the animator. Composition roots (daemon / editor / settings) own one PhosphorProfileRegistry instance and thread it through; tests construct a per-fixture registry and pass it here. There is no default-singleton fallback — every caller injects their own dependency.
|
explicit |
Convenience: registry-only ctor with empty default config.
Equivalent to SurfaceAnimator(registry, Config{}) but spelled out as a separate overload so unity-build paths don't get confused by a default-arg Config{} on the primary ctor (the previous shape Config defaults = Config{} triggered a parse ambiguity in the unity TU between the value-initialised default arg and a function-declarator interpretation).
| PhosphorAnimationLayer::SurfaceAnimator::SurfaceAnimator | ( | PhosphorAnimation::PhosphorProfileRegistry & | registry, |
| PhosphorAnimationShaders::AnimationShaderRegistry * | shaderRegistry, | ||
| Config | defaults | ||
| ) |
Full constructor with shader registry for Phase 6 transition effects.
Same DI contract as the registry-only ctors — caller owns the AnimationShaderRegistry and threads it through; pass nullptr to disable shader transitions. (No singleton fallback; see SurfaceAnimator(registry, defaults) above for the rationale.)
|
override |
|
delete |
|
overridevirtual |
Begin a hide transition for surface.
The Surface is transitioning Shown → Hidden. The animator should fade/slide the content, then invoke onComplete. The library does not delay window->hide() waiting for this — the current contract is "animate for visual polish, but the surface is considered hidden
the moment hide() is called".
Implements PhosphorLayer::ISurfaceAnimator.
| void PhosphorAnimationLayer::SurfaceAnimator::beginHide | ( | PhosphorLayer::Surface * | surface, |
| QQuickItem * | rootItem, | ||
| const PhosphorLayer::Role & | configRole, | ||
| CompletionCallback | onComplete | ||
| ) |
|
overridevirtual |
Begin a show transition for surface.
The Surface has just become visible (Hidden → Shown). The animator can mutate rootItem (opacity, scale, y-offset) and drive an animation. Invoke onComplete when the transition finishes; the library uses this as a no-op today but a future version may defer compositor sync until the completion signal arrives.
Implements PhosphorLayer::ISurfaceAnimator.
| void PhosphorAnimationLayer::SurfaceAnimator::beginShow | ( | PhosphorLayer::Surface * | surface, |
| QQuickItem * | rootItem, | ||
| const PhosphorLayer::Role & | configRole, | ||
| CompletionCallback | onComplete | ||
| ) |
Role-override show/hide.
The surface's own role is used for layer-shell-protocol concerns (anchors, kbd, layer); the configRole argument is used for animation-config resolution — replacing the implicit configFor(surface->config().role) lookup the no-arg variants do. Required by the unified PassiveOverlayShell pattern: one shell wl_surface hosts multiple per-content slots (OSD, zone-selector, snap-assist, picker), each animated with their own per-content motion + shader profiles. Without role override they'd all share the shell's role-config, which would homogenise transitions across content types.
Pre-shell, every content had its own Surface and the no-arg variant resolved the right config from the surface's role directly. Post-shell, the surface's role is the shell's (PassiveShell) and we need to override per-content per-show.
|
overridevirtual |
Interrupt any in-flight animation for surface.
Called when the Surface is destroyed or the animation is superseded by an opposite transition (show-while-hiding).
Implements PhosphorLayer::ISurfaceAnimator.
| Config PhosphorAnimationLayer::SurfaceAnimator::configForRole | ( | const PhosphorLayer::Role & | role | ) | const |
Read-only config lookup.
Returns the registered config for role if one was set, otherwise defaultConfig.
| Config PhosphorAnimationLayer::SurfaceAnimator::defaultConfig | ( | ) | const |
| bool PhosphorAnimationLayer::SurfaceAnimator::isEnabled | ( | ) | const |
|
delete |
| void PhosphorAnimationLayer::SurfaceAnimator::registerConfigForRole | ( | const PhosphorLayer::Role & | role, |
| Config | cfg | ||
| ) |
Override the configuration for one Role.
The role's scopePrefix is used as the registration key. Lookup is longest-prefix-match (with ‘’-'boundary) against the surface'srole.scopePrefix, so consumers can register a config against a stable base role (e.g.PzRoles::LayoutOsdwith prefix"plasmazones-layout-osd") while the surfaces themselves carry per-instance roles derived via withScopePrefix("plasmazones-layout-osd-{screenId}-{gen}")` for compositor scope uniqueness. Without prefix matching, the unique per-instance suffix would make every lookup miss and silently fall back to the default config.
| void PhosphorAnimationLayer::SurfaceAnimator::setAnimationShaderRegistry | ( | PhosphorAnimationShaders::AnimationShaderRegistry * | registry | ) |
Install the animation shader registry for Phase 6 shader transitions.
May be called after construction (the daemon creates the registry after the overlay service). Null disables shader transitions.
| void PhosphorAnimationLayer::SurfaceAnimator::setAudioSpectrum | ( | const QVector< float > & | spectrum | ) |
Push the latest CAVA / audio-spectrum sample to every active animation shader item.
Mirrors the overlay path's OverlayService::onAudioSpectrumUpdated → audioSpectrum QML property write — animation shaders programmatically attached by SurfaceAnimator have no QML scene to bind through, so the consumer (typically the daemon's OverlayService) wires its IAudioSpectrumProvider::spectrumUpdated signal here. The spectrum is also re-pushed at attach time so a shader that installs mid-stream sees the latest data on its first frame instead of zero-initialised silence.
Pass an empty vector to clear (e.g. when audio visualization is disabled). Called at the audio framerate (typically 30-60 Hz); ShaderEffect::setAudioSpectrum no-ops on identity so an unchanged spectrum costs nothing.
| void PhosphorAnimationLayer::SurfaceAnimator::setDefaultConfig | ( | Config | cfg | ) |
Mutable access to the default (unregistered-role fallback).
Useful when the consumer wants to bind every overlay's default behaviour without enumerating roles.
| void PhosphorAnimationLayer::SurfaceAnimator::setEnabled | ( | bool | enabled | ) |
Global animation enable/disable.
When disabled, beginShow and beginHide snap the rootItem to the target opacity (1.0 / 0.0) and fire the completion callback synchronously — no opacity tween, no shader leg, no scale leg. Mirrors the kwin-effect's global gate: a single animationsEnabled setting kills every animation on both runtimes when toggled off.