From 63e0ffb32a4a432ed57f31388fabff89b05cb8cc Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 1 Nov 2013 15:49:33 +0100 Subject: Refactored Animator internals Change the design from posting events for starting and stopping to use the scene graph's existing 'sync' point. This gives much higher predictability and makes both ownership and cleanup cleaner and also reduces intermediate states while events are waiting to be delivered. Task-number: QTBUG-34137 Change-Id: I069ac22acbddaa47925b8172ba98ac340fe9bf8d Reviewed-by: Michael Brasser --- src/quick/items/qquickwindow.cpp | 2 +- src/quick/items/qquickwindow.h | 2 +- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 13 +- src/quick/util/qquickanimatorcontroller.cpp | 185 ++++++++++++++++--------- src/quick/util/qquickanimatorcontroller_p.h | 63 +++------ src/quick/util/qquickanimatorjob.cpp | 103 +++++--------- src/quick/util/qquickanimatorjob_p.h | 12 +- 7 files changed, 193 insertions(+), 187 deletions(-) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 9798974788..28a5df789f 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -420,7 +420,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c) q->setFormat(sg->defaultSurfaceFormat()); animationController = new QQuickAnimatorController(); - animationController->window = q; + animationController->m_window = q; QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection); QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection); diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 6fd01a3119..9f31ee708a 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -177,7 +177,7 @@ private Q_SLOTS: private: friend class QQuickItem; - friend class QQuickWindowRenderLoop; + friend class QQuickAnimatorController; Q_DISABLE_COPY(QQuickWindow) }; diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 42c7c9c0ba..1d69034f5e 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -387,19 +387,16 @@ bool QSGRenderThread::event(QEvent *e) } window = se->window; - connect(animatorDriver, SIGNAL(started()), QQuickWindowPrivate::get(se->window)->animationController, SLOT(animationsStarted())); return true; } case WM_Obscure: { RLDEBUG1(" Render: WM_Obscure"); - WMWindowEvent *ce = static_cast(e); - Q_ASSERT(!window || window == ce->window); + Q_ASSERT(!window || window == static_cast(e)->window); if (window) { RLDEBUG1(" Render: - removed one..."); window = 0; - disconnect(animatorDriver, SIGNAL(started()), QQuickWindowPrivate::get(ce->window)->animationController, SLOT(animationsStarted())); } return true; } @@ -583,10 +580,14 @@ void QSGRenderThread::syncAndRender() #endif RLDEBUG(" Render: - rendering starting"); - if (animatorDriver->isRunning()) + QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); + + if (animatorDriver->isRunning()) { + d->animationController->lock(); animatorDriver->advance(); + d->animationController->unlock(); + } - QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0) { gl->makeCurrent(window); d->renderSceneGraph(windowSize); diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp index 82c66b431d..a2364f4586 100644 --- a/src/quick/util/qquickanimatorcontroller.cpp +++ b/src/quick/util/qquickanimatorcontroller.cpp @@ -48,54 +48,80 @@ #include +#include + QT_BEGIN_NAMESPACE QQuickAnimatorController::QQuickAnimatorController() - : window(0) + : m_window(0) { } QQuickAnimatorController::~QQuickAnimatorController() { - qDeleteAll(activeRootAnimations); + // The proxy job might already have been deleted, in which case we + // need to avoid calling functions on them. Then delete the job. + foreach (QAbstractAnimationJob *job, m_deleting) { + m_animatorRoots.take(job); + delete job; + } + + foreach (QQuickAnimatorProxyJob *proxy, m_animatorRoots) + proxy->controllerWasDeleted(); + qDeleteAll(m_animatorRoots.keys()); + + // Delete those who have been started, stopped and are now still + // pending for restart. + foreach (QAbstractAnimationJob *job, m_starting.keys()) { + if (!m_animatorRoots.contains(job)) + delete job; + } } void QQuickAnimatorController::itemDestroyed(QObject *o) { - deletedSinceLastFrame << (QQuickItem *) o; + m_deletedSinceLastFrame << (QQuickItem *) o; } void QQuickAnimatorController::advance() { bool running = false; - for (QSet::const_iterator it = activeRootAnimations.constBegin(); - !running && it != activeRootAnimations.constEnd(); ++it) { - if ((*it)->isRunning()) + for (QHash::const_iterator it = m_animatorRoots.constBegin(); + !running && it != m_animatorRoots.constEnd(); ++it) { + if (it.key()->isRunning()) running = true; } // It was tempting to only run over the active animations, but we need to push // the values for the transforms that finished in the last frame and those will // have been removed already... - for (QHash::const_iterator it = transforms.constBegin(); - it != transforms.constEnd(); ++it) { + lock(); + for (QHash::const_iterator it = m_transforms.constBegin(); + it != m_transforms.constEnd(); ++it) { + QQuickTransformAnimatorJob::Helper *xform = *it; + // Set to zero when the item was deleted in beforeNodeSync(). + if (!xform->item) + continue; (*it)->apply(); } + unlock(); if (running) - window->update(); + m_window->update(); } static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c) { if (job->isRenderThreadJob()) { QQuickAnimatorJob *j = static_cast(job); - if (!j->target()) + if (!j->target()) { return; - else if (c->deletedSinceLastFrame.contains(j->target())) + } else if (c->m_deletedSinceLastFrame.contains(j->target())) { j->targetWasDeleted(); - else + } else { + j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange); j->initialize(c); + } } else if (job->isGroup()) { QAnimationGroupJob *g = static_cast(job); for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling()) @@ -105,90 +131,117 @@ static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorC void QQuickAnimatorController::beforeNodeSync() { - // Force a render pass if we are adding new animations - // so that advance will be called.. - if (starting.size()) - window->update(); - - for (int i=0; iaddAnimationChangeListener(this, QAbstractAnimationJob::StateChange); + foreach (QAbstractAnimationJob *job, m_deleting) { + m_starting.take(job); + m_stopping.take(job); + m_animatorRoots.take(job); + job->stop(); + delete job; + } + m_deleting.clear(); + + if (m_starting.size()) + m_window->update(); + foreach (QQuickAnimatorProxyJob *proxy, m_starting) { + QAbstractAnimationJob *job = proxy->job(); + job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion); qquick_initialize_helper(job, this); + m_animatorRoots[job] = proxy; job->start(); + proxy->startedByController(); } - starting.clear(); + m_starting.clear(); - for (QSet::const_iterator it = activeLeafAnimations.constBegin(); - it != activeLeafAnimations.constEnd(); ++it) { - QQuickAnimatorJob *job = *it; + foreach (QQuickAnimatorProxyJob *proxy, m_stopping) { + QAbstractAnimationJob *job = proxy->job(); + job->stop(); + } + m_stopping.clear(); + + foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) { if (!job->target()) continue; - else if (deletedSinceLastFrame.contains(job->target())) + else if (m_deletedSinceLastFrame.contains(job->target())) job->targetWasDeleted(); else if (job->isTransform()) { - QQuickTransformAnimatorJob *xform = static_cast(*it); + QQuickTransformAnimatorJob *xform = static_cast(job); xform->transformHelper()->sync(); } } - deletedSinceLastFrame.clear(); + foreach (QQuickItem *wiped, m_deletedSinceLastFrame) { + QQuickTransformAnimatorJob::Helper *helper = m_transforms.value(wiped); + if (helper) + helper->item = 0; + } + + m_deletedSinceLastFrame.clear(); } void QQuickAnimatorController::afterNodeSync() { - for (QSet::const_iterator it = activeLeafAnimations.constBegin(); - it != activeLeafAnimations.constEnd(); ++it) { - QQuickAnimatorJob *job = *it; - if (job->isUniform() && job->target()) { - QQuickUniformAnimatorJob *job = static_cast(*it); - job->afterNodeSync(); - } + foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) { + if (job->isUniform() && job->target()) + static_cast(job)->afterNodeSync(); } } - -void QQuickAnimatorController::startAnimation(QAbstractAnimationJob *job) +void QQuickAnimatorController::animationFinished(QAbstractAnimationJob *job) { - mutex.lock(); - starting << job; - mutex.unlock(); + /* We are currently on the render thread and m_deleting is primarily + * being written on the GUI Thread and read during sync. However, we don't + * need to lock here as this is a direct result of animationDriver->advance() + * which is already locked. For non-threaded render loops no locking is + * needed in any case. + */ + if (!m_deleting.contains(job)) { + QQuickAnimatorProxyJob *proxy = m_animatorRoots[job]; + if (proxy) + QCoreApplication::postEvent(proxy, new QEvent(QEvent::User)); + // else already gone... + } } -void QQuickAnimatorController::animationsStarted() +void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job, + QAbstractAnimationJob::State newState, + QAbstractAnimationJob::State oldState) { - window->update(); + Q_ASSERT(job->isRenderThreadJob()); + QQuickAnimatorJob *animator = static_cast(job); + if (newState == QAbstractAnimationJob::Running) { + m_activeLeafAnimations << animator; + animator->setHasBeenRunning(true); + } else if (oldState == QAbstractAnimationJob::Running) { + m_activeLeafAnimations.remove(animator); + } } -void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job, - QAbstractAnimationJob::State newState, - QAbstractAnimationJob::State) + + +void QQuickAnimatorController::requestSync() { - if (newState == QAbstractAnimationJob::Running) - activeRootAnimations << job; - else - activeRootAnimations.remove(job); + // Force a "sync" pass as the newly started animation needs to sync properties from GUI. + m_window->maybeUpdate(); } -bool QQuickAnimatorController::event(QEvent *e) +// These functions are called on the GUI thread. +void QQuickAnimatorController::startJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job) { - if ((int) e->type() == StopAnimation) { - QAbstractAnimationJob *job = static_cast(e)->job; - mutex.lock(); - starting.removeOne(job); - mutex.unlock(); - job->stop(); - return true; + m_starting[job] = proxy; + requestSync(); +} - } else if ((uint) e->type() == DeleteAnimation) { - QAbstractAnimationJob *job = static_cast(e)->job; - mutex.lock(); - starting.removeOne(job); - mutex.unlock(); - job->stop(); - delete job; - return true; - } +void QQuickAnimatorController::stopJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job) +{ + m_stopping[job] = proxy; + requestSync(); +} - return QObject::event(e); +void QQuickAnimatorController::deleteJob(QAbstractAnimationJob *job) +{ + lock(); + m_deleting << job; + requestSync(); + unlock(); } QT_END_NAMESPACE diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h index ab08bf05db..6223a9938f 100644 --- a/src/quick/util/qquickanimatorcontroller_p.h +++ b/src/quick/util/qquickanimatorcontroller_p.h @@ -47,6 +47,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -55,27 +56,6 @@ class QQuickAnimatorController : public QObject, public QAnimationJobChangeListe Q_OBJECT public: - - enum EventType { - // GUI to RT events - StartAnimation = QEvent::User + 1, - StopAnimation, - DeleteAnimation, - - // RT back to GUI events - AnimationFinished - }; - - class Event : public QEvent { - public: - Event(QAbstractAnimationJob *j, EventType type) - : QEvent(QEvent::Type(type)) - , job(j) - { - } - QAbstractAnimationJob *job; - }; - QQuickAnimatorController(); ~QQuickAnimatorController(); @@ -83,32 +63,35 @@ public: void beforeNodeSync(); void afterNodeSync(); - bool event(QEvent *); + void animationFinished(QAbstractAnimationJob *job); + void animationStateChanged(QAbstractAnimationJob *job, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState); - void startAnimation(QAbstractAnimationJob *job); + void requestSync(); - void animationStateChanged(QAbstractAnimationJob *job, - QAbstractAnimationJob::State newState, - QAbstractAnimationJob::State oldState); + // These are called from the GUI thread (the proxy) + void startJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job); + void stopJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job); + void deleteJob(QAbstractAnimationJob *job); + + void lock() { m_mutex.lock(); } + void unlock() { m_mutex.unlock(); } public Q_SLOTS: - void animationsStarted(); void itemDestroyed(QObject *); public: - QList starting; - QList stopped; - - QSet activeRootAnimations; - QSet activeLeafAnimations; - - QHash transforms; - - QSet deletedSinceLastFrame; - - QQuickWindow *window; - - QMutex mutex; + // These are manipulated from the GUI thread and should only + // be updated during the sync() phase. + QHash m_starting; + QHash m_stopping; + QSet m_deleting; + + QHash m_animatorRoots; + QSet m_activeLeafAnimations; + QHash m_transforms; + QSet m_deletedSinceLastFrame; + QQuickWindow *m_window; + QMutex m_mutex; }; QT_END_NAMESPACE diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index fffb9fc65f..fa6f615649 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -72,8 +72,6 @@ QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObje // be negligiblie compared to animating and re-rendering the scene on the render thread. m_duration = -1; - job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion); - QObject *ctx = findAnimationContext(m_animation); if (!ctx) { qWarning("QtQuick: unable to find animation context for RT animation..."); @@ -100,7 +98,7 @@ void QQuickAnimatorProxyJob::deleteJob() { if (m_job) { if (m_controller && m_internalState != State_Starting) - QCoreApplication::postEvent(m_controller, new QQuickAnimatorController::Event(m_job, QQuickAnimatorController::DeleteAnimation)); + m_controller->deleteJob(m_job); else if (m_internalState == State_Starting) delete m_job; m_job = 0; @@ -122,18 +120,15 @@ void QQuickAnimatorProxyJob::updateCurrentTime(int) void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State) { if (m_state == Running) { - if (m_controller) { - m_internalState = State_Running; - startOnRenderThread(); - } else { - m_internalState = State_Starting; - } + m_internalState = State_Starting; + if (m_controller) + m_controller->startJob(this, m_job); } else if (newState == Stopped) { syncBackCurrentValues(); if (m_internalState == State_Starting) m_internalState = State_Stopped; else if (m_controller) { - QCoreApplication::postEvent(m_controller, new QQuickAnimatorController::Event(m_job, QQuickAnimatorController::StopAnimation)); + m_controller->stopJob(this, m_job); } } } @@ -143,23 +138,28 @@ void QQuickAnimatorProxyJob::windowChanged(QQuickWindow *window) setWindow(window); } +void QQuickAnimatorProxyJob::controllerWasDeleted() +{ + m_controller = 0; + m_job = 0; +} + void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window) { if (!window) { - m_controller = 0; // Stop will trigger syncBackCurrentValues so best to do it before // we delete m_job. stop(); deleteJob(); return; - } - m_controller = QQuickWindowPrivate::get(window)->animationController; - - if (window->openglContext()) - readyToAnimate(); - else - connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(sceneGraphInitialized())); + } else if (!m_controller && m_job) { + m_controller = QQuickWindowPrivate::get(window)->animationController; + if (window->openglContext()) + readyToAnimate(); + else + connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(sceneGraphInitialized())); + } } void QQuickAnimatorProxyJob::sceneGraphInitialized() @@ -170,36 +170,24 @@ void QQuickAnimatorProxyJob::sceneGraphInitialized() void QQuickAnimatorProxyJob::readyToAnimate() { - if (m_internalState == State_Starting) { - startOnRenderThread(); - } + if (m_internalState == State_Starting) + m_controller->startJob(this, m_job); } -void QQuickAnimatorProxyJob::animationFinished(QAbstractAnimationJob *job) +void QQuickAnimatorProxyJob::startedByController() { - QCoreApplication::postEvent(this, new QQuickAnimatorController::Event(job, QQuickAnimatorController::AnimationFinished)); + m_internalState = State_Running; } bool QQuickAnimatorProxyJob::event(QEvent *e) { - if ((uint) e->type() == QQuickAnimatorController::AnimationFinished) { - // Update the duration of this proxy to the current time and stop it so - // that parent animations can progress gracefully + if (e->type() == QEvent::User) { stop(); return true; } - return QObject::event(e); } -void QQuickAnimatorProxyJob::startOnRenderThread() -{ - m_internalState = State_Running; - // Force a "sync" pass as the newly started animation needs to sync properties from GUI. - m_controller->startAnimation(m_job); - QQuickWindowPrivate::get(m_controller->window)->dirtyItem(0); -} - static void qquick_syncback_helper(QAbstractAnimationJob *job) { if (job->isRenderThreadJob()) { @@ -216,7 +204,8 @@ static void qquick_syncback_helper(QAbstractAnimationJob *job) void QQuickAnimatorProxyJob::syncBackCurrentValues() { - qquick_syncback_helper(m_job); + if (m_job) + qquick_syncback_helper(m_job); } QQuickAnimatorJob::QQuickAnimatorJob() @@ -236,9 +225,9 @@ QQuickAnimatorJob::QQuickAnimatorJob() qreal QQuickAnimatorJob::value() const { qreal v; - m_controller->mutex.lock(); + m_controller->lock(); v = m_value; - m_controller->mutex.unlock(); + m_controller->unlock(); return v; } @@ -258,21 +247,6 @@ void QQuickAnimatorJob::targetWasDeleted() m_controller = 0; } -void QQuickAnimatorJob::updateState(State newState, State oldState) -{ - if (!m_controller) { - stop(); - return; - } - - if (newState == Running) { - m_controller->activeLeafAnimations << this; - m_hasBeenRunning = true; - } else if (oldState == Running) { - m_controller->activeLeafAnimations.remove(this); - } -} - QQuickTransformAnimatorJob::QQuickTransformAnimatorJob() : m_helper(0) { @@ -282,7 +256,7 @@ QQuickTransformAnimatorJob::QQuickTransformAnimatorJob() QQuickTransformAnimatorJob::~QQuickTransformAnimatorJob() { if (m_helper && --m_helper->ref == 0) { - m_controller->transforms.remove(m_helper->item); + m_controller->m_transforms.remove(m_helper->item); delete m_helper; } } @@ -292,11 +266,11 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller QQuickAnimatorJob::initialize(controller); if (m_controller) { - m_helper = m_controller->transforms.value(m_target); + m_helper = m_controller->m_transforms.value(m_target); if (!m_helper) { m_helper = new Helper(); m_helper->item = m_target; - m_controller->transforms.insert(m_target, m_helper); + m_controller->m_transforms.insert(m_target, m_helper); QObject::connect(m_target, SIGNAL(destroyed(QObject *)), m_controller, SLOT(itemDestroyed(QObject*)), Qt::DirectConnection); } else { ++m_helper->ref; @@ -307,11 +281,6 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller } } -QQuickTransformAnimatorJob::Helper::~Helper() -{ -} - - void QQuickTransformAnimatorJob::Helper::sync() { const quint32 mask = QQuickItemPrivate::Position @@ -383,7 +352,7 @@ void QQuickXAnimatorJob::updateCurrentTime(int time) { if (!m_controller) return; - Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread()); m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); m_helper->dx = m_value; @@ -400,7 +369,7 @@ void QQuickYAnimatorJob::updateCurrentTime(int time) { if (!m_controller) return; - Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread()); m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); m_helper->dy = m_value; @@ -453,7 +422,7 @@ void QQuickOpacityAnimatorJob::updateCurrentTime(int time) { if (!m_controller) return; - Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread()); m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); m_opacityNode->setOpacity(m_value); @@ -469,7 +438,7 @@ void QQuickScaleAnimatorJob::updateCurrentTime(int time) { if (!m_controller) return; - Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread()); m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); m_helper->scale = m_value; @@ -489,7 +458,7 @@ void QQuickRotationAnimatorJob::updateCurrentTime(int time) { if (!m_controller) return; - Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread()); float t = m_easing.valueForProgress(time / (qreal) m_duration); switch (m_direction) { @@ -564,7 +533,7 @@ void QQuickUniformAnimatorJob::updateCurrentTime(int time) { if (!m_controller) return; - Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread()); if (!m_node || m_uniformIndex == -1 || m_uniformType == -1) return; diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h index bc9c65c347..8aae121106 100644 --- a/src/quick/util/qquickanimatorjob_p.h +++ b/src/quick/util/qquickanimatorjob_p.h @@ -63,7 +63,7 @@ class QQuickShaderEffectNode; class QSGOpacityNode; -class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorProxyJob : public QObject, public QAbstractAnimationJob, public QAnimationJobChangeListener +class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorProxyJob : public QObject, public QAbstractAnimationJob { Q_OBJECT @@ -73,7 +73,10 @@ public: int duration() const { return m_duration; } - virtual void animationFinished(QAbstractAnimationJob *); + QAbstractAnimationJob *job() const { return m_job; } + + void startedByController(); + void controllerWasDeleted(); protected: bool event(QEvent *); @@ -91,7 +94,6 @@ private: void readyToAnimate(); void setWindow(QQuickWindow *window); static QObject *findAnimationContext(QQuickAbstractAnimation *); - void startOnRenderThread(); QQuickAnimatorController *m_controller; QQuickAbstractAnimation *m_animation; @@ -134,6 +136,7 @@ public: bool isUniform() const { return m_isUniform; } bool hasBeenRunning() const { return m_hasBeenRunning; } + void setHasBeenRunning(bool has) { m_hasBeenRunning = has; } qreal value() const; @@ -141,7 +144,6 @@ public: protected: QQuickAnimatorJob(); - void updateState(State newState, State oldState); QQuickItem *m_target; QQuickAnimatorController *m_controller; @@ -180,8 +182,6 @@ public: { } - ~Helper(); - void sync(); void apply(); -- cgit v1.2.3