Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickanimatorcontroller.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Gunnar Sletta <gunnar@sletta.org>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
7
8#include <private/qquickitem_p.h>
9#include <private/qsgrenderloop_p.h>
10
11#include <private/qanimationgroupjob_p.h>
12
13#include <QtGui/qscreen.h>
14
15#include <QtCore/qcoreapplication.h>
16
18
19QQuickAnimatorController::~QQuickAnimatorController()
20{
21}
22
23QQuickAnimatorController::QQuickAnimatorController(QQuickWindow *window)
24 : m_window(window)
25{
26}
27
28static void qquickanimator_invalidate_jobs(QAbstractAnimationJob *job)
29{
30 if (job->isRenderThreadJob()) {
31 static_cast<QQuickAnimatorJob *>(job)->invalidate();
32 } else if (job->isGroup()) {
33 for (QAbstractAnimationJob *a : *static_cast<QAnimationGroupJob *>(job)->children())
34 qquickanimator_invalidate_jobs(a);
35 }
36}
37
38void QQuickAnimatorController::windowNodesDestroyed()
39{
40 for (const QSharedPointer<QAbstractAnimationJob> &toStop : std::as_const(m_rootsPendingStop)) {
41 qquickanimator_invalidate_jobs(toStop.data());
42 toStop->stop();
43 }
44 m_rootsPendingStop.clear();
45
46 // Clear animation roots and iterate over a temporary to avoid that job->stop()
47 // modifies the m_animationRoots and messes with our iteration
48 const auto roots = m_animationRoots;
49 m_animationRoots.clear();
50 for (const QSharedPointer<QAbstractAnimationJob> &job : roots) {
51 qquickanimator_invalidate_jobs(job.data());
52
53 // Stop it and add it to the list of pending start so it might get
54 // started later on.
55 job->stop();
56 m_rootsPendingStart.insert(job);
57 }
58}
59
60void QQuickAnimatorController::advance()
61{
62 bool running = false;
63 for (const QSharedPointer<QAbstractAnimationJob> &job : std::as_const(m_animationRoots)) {
64 if (job->isRunning()) {
65 running = true;
66 break;
67 }
68 }
69
70 for (QQuickAnimatorJob *job : std::as_const(m_runningAnimators))
71 job->commit();
72
73 if (running)
74 m_window->update();
75}
76
77static void qquickanimator_sync_before_start(QAbstractAnimationJob *job)
78{
79 if (job->isRenderThreadJob()) {
80 static_cast<QQuickAnimatorJob *>(job)->preSync();
81 } else if (job->isGroup()) {
82 for (QAbstractAnimationJob *a : *static_cast<QAnimationGroupJob *>(job)->children())
83 qquickanimator_sync_before_start(a);
84 }
85}
86
87void QQuickAnimatorController::beforeNodeSync()
88{
89 for (const QSharedPointer<QAbstractAnimationJob> &toStop : std::as_const(m_rootsPendingStop)) {
90 toStop->stop();
91 m_animationRoots.remove(toStop.data());
92 }
93 m_rootsPendingStop.clear();
94
95
96 for (QQuickAnimatorJob *job : std::as_const(m_runningAnimators))
97 job->preSync();
98
99 // Start pending jobs
100 for (const QSharedPointer<QAbstractAnimationJob> &job : std::as_const(m_rootsPendingStart)) {
101 Q_ASSERT(!job->isRunning());
102
103 // We want to make sure that presync is called before
104 // updateAnimationTime is called the very first time, so before
105 // starting a tree of jobs, we go through it and call preSync on all
106 // its animators.
107 qquickanimator_sync_before_start(job.data());
108
109 // The start the job..
110 job->start();
111 m_animationRoots.insert(job.data(), job);
112 }
113 m_rootsPendingStart.clear();
114
115 // Issue an update directly on the window to force another render pass.
116 if (m_animationRoots.size())
117 m_window->update();
118}
119
120void QQuickAnimatorController::afterNodeSync()
121{
122 for (QQuickAnimatorJob *job : std::as_const(m_runningAnimators))
123 job->postSync();
124}
125
126void QQuickAnimatorController::animationFinished(QAbstractAnimationJob *job)
127{
128 m_animationRoots.remove(job);
129}
130
131void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job,
132 QAbstractAnimationJob::State newState,
133 QAbstractAnimationJob::State oldState)
134{
135 Q_ASSERT(job->isRenderThreadJob());
136 QQuickAnimatorJob *animator = static_cast<QQuickAnimatorJob *>(job);
137 if (newState == QAbstractAnimationJob::Running) {
138 m_runningAnimators.insert(animator);
139 } else if (oldState == QAbstractAnimationJob::Running) {
140 animator->commit();
141 m_runningAnimators.remove(animator);
142 }
143}
144
145
146void QQuickAnimatorController::requestSync()
147{
148 // Force a "sync" pass as the newly started animation needs to sync properties from GUI.
149 m_window->maybeUpdate();
150}
151
152// All this is being executed on the GUI thread while the animator controller
153// is locked.
154void QQuickAnimatorController::start_helper(QAbstractAnimationJob *job)
155{
156 if (job->isRenderThreadJob()) {
157 QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
158 j->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
159 j->initialize(this);
160 } else if (job->isGroup()) {
161 for (QAbstractAnimationJob *a : *static_cast<QAnimationGroupJob *>(job)->children())
162 start_helper(a);
163 }
164}
165
166// Called by the proxy when it is time to kick off an animation job
167void QQuickAnimatorController::start(const QSharedPointer<QAbstractAnimationJob> &job)
168{
169 m_rootsPendingStart.insert(job);
170 m_rootsPendingStop.remove(job);
171 job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
172 start_helper(job.data());
173 requestSync();
174}
175
176
177// Called by the proxy when it is time to stop an animation job.
178void QQuickAnimatorController::cancel(const QSharedPointer<QAbstractAnimationJob> &job)
179{
180 m_rootsPendingStart.remove(job);
181 m_rootsPendingStop.insert(job);
182}
183
184
185QT_END_NAMESPACE
186
187#include "moc_qquickanimatorcontroller_p.cpp"
static void qquickanimator_invalidate_jobs(QAbstractAnimationJob *job)
static void qquickanimator_sync_before_start(QAbstractAnimationJob *job)