Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
QtQuickClock.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 fuddlesworth
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
7#include <PhosphorAnimation/phosphoranimation_export.h>
8
9#include <QPointer>
10
11#include <atomic>
12#include <chrono>
13#include <memory>
14
15class QQuickWindow;
16
17namespace PhosphorAnimation {
18
113class PHOSPHORANIMATION_EXPORT QtQuickClock final : public IMotionClock
114{
115public:
121 explicit QtQuickClock(QQuickWindow* window);
122 ~QtQuickClock() override;
123
124 // IMotionClock
125 std::chrono::nanoseconds now() const override;
126 qreal refreshRate() const override;
127 void requestFrame() override;
128 const void* epochIdentity() const override;
129
131 QQuickWindow* window() const;
132
133private:
134 class SignalAdapter; // QObject helper defined in the .cpp
135 friend class SignalAdapter;
136
137 // Cached timestamp captured in the `beforeRendering` slot so
138 // `now()` returns the vsync-aligned reading for the frame being
139 // rendered. Written from the render thread by the SignalAdapter;
140 // may be read from the GUI thread (QML animation drivers that
141 // don't honour the render-thread-only contract). Stored as
142 // atomic<int64_t>; the writer uses release and the reader uses
143 // acquire so a cross-thread reader sees a well-published value
144 // rather than just a tear-free one.
145 //
146 // `mutable` because the logically-const `now()` reader CAS-seeds
147 // the cache on the pre-handoff fallback path to guarantee
148 // monotonicity across the fallback→cache transition. Updating an
149 // internal cache from a const observer is the canonical mutable
150 // use case; the logical const contract ("now() returns the current
151 // time") is unaffected.
152 mutable std::atomic<std::chrono::nanoseconds::rep> m_nowCache{0};
153 // Set the first time `beforeRendering` fires — the render loop
154 // has become responsible for advancing `m_nowCache`. Until then
155 // `now()` falls back to reading `steady_clock` directly so an
156 // animation bound to a never-shown `QQuickWindow` (test mode,
157 // hidden offscreen render loop) doesn't freeze at the prime
158 // timestamp with dt=0 on every advance.
159 //
160 // One-shot: never flips back to false even if the window is
161 // hidden and `beforeRendering` stops firing. This is intentional —
162 // once the render loop has written a post-vsync-aligned timestamp
163 // into `m_nowCache`, subsequent `now()` readers should see THAT
164 // reading (via the cache load) instead of a fresh `steady_clock`
165 // read that might skew ahead of the last paint by an entire hidden
166 // frame budget. If the window is later re-shown the next
167 // `beforeRendering` fire overwrites the cache with a fresh
168 // vsync-aligned reading; readers during the hidden interval see a
169 // stale-but-monotonic timestamp, which produces `dt=0` progressions
170 // (correct — nothing is rendering, so no motion) rather than
171 // spurious forward steps. If a consumer needs to release resources
172 // on window hide, the QObject destroyed signal is the right hook —
173 // not the clock's internal latch.
174 std::atomic<bool> m_renderLoopActive{false};
175 QPointer<QQuickWindow> m_window;
176 std::unique_ptr<SignalAdapter> m_adapter;
177};
178
179} // namespace PhosphorAnimation
Abstract clock interface for the motion runtime.
Definition IMotionClock.h:18
Qt Quick adapter implementing IMotionClock.
Definition QtQuickClock.h:114
const void * epochIdentity() const override
Opaque epoch identity for rebindClock compatibility.
void requestFrame() override
Schedule another paint tick. Idempotent within a single frame.
std::chrono::nanoseconds now() const override
Monotonically non-decreasing steady-clock reading (nanoseconds).
QtQuickClock(QQuickWindow *window)
Construct a clock bound to window.
QQuickWindow * window() const
The QQuickWindow this clock is bound to. May be null.
qreal refreshRate() const override
Nominal refresh rate in Hz, or zero if unknown.
Definition AnimatedValue.h:31