11#include " incubator.hpp"
22
3+ #include < private/qsgrenderloop_p.h>
4+ #include < qabstractanimation.h>
5+ #include < qguiapplication.h>
36#include < qlogging.h>
7+ #include < qloggingcategory.h>
8+ #include < qminmax.h>
9+ #include < qnamespace.h>
10+ #include < qobject.h>
11+ #include < qobjectdefs.h>
412#include < qqmlincubator.h>
13+ #include < qscreen.h>
514#include < qtmetamacros.h>
615
716#include " logcat.hpp"
@@ -15,3 +24,112 @@ void QsQmlIncubator::statusChanged(QQmlIncubator::Status status) {
1524 default : break ;
1625 }
1726}
27+
28+ void QsIncubationController::initLoop () {
29+ auto * app = static_cast <QGuiApplication*>(QGuiApplication::instance ()); // NOLINT
30+ this ->renderLoop = QSGRenderLoop::instance ();
31+
32+ QObject::connect (
33+ app,
34+ &QGuiApplication::screenAdded,
35+ this ,
36+ &QsIncubationController::updateIncubationTime
37+ );
38+
39+ QObject::connect (
40+ app,
41+ &QGuiApplication::screenRemoved,
42+ this ,
43+ &QsIncubationController::updateIncubationTime
44+ );
45+
46+ this ->updateIncubationTime ();
47+
48+ QObject::connect (
49+ this ->renderLoop ,
50+ &QSGRenderLoop::timeToIncubate,
51+ this ,
52+ &QsIncubationController::incubate
53+ );
54+
55+ QAnimationDriver* animationDriver = this ->renderLoop ->animationDriver ();
56+ if (animationDriver) {
57+ QObject::connect (
58+ animationDriver,
59+ &QAnimationDriver::stopped,
60+ this ,
61+ &QsIncubationController::animationStopped
62+ );
63+ } else {
64+ qCInfo (logIncubator) << " Render loop does not have animation driver, animationStopped cannot "
65+ " be used to trigger incubation." ;
66+ }
67+ }
68+
69+ void QsIncubationController::setIncubationMode (bool render) {
70+ if (render == this ->followRenderloop ) return ;
71+ this ->followRenderloop = render;
72+
73+ if (render) {
74+ qCDebug (logIncubator) << " Incubation mode changed: render loop driven" ;
75+ } else {
76+ qCDebug (logIncubator) << " Incubation mode changed: event loop driven" ;
77+ }
78+
79+ if (!render && this ->incubatingObjectCount ()) this ->incubateLater ();
80+ }
81+
82+ void QsIncubationController::timerEvent (QTimerEvent* /* event*/ ) {
83+ this ->killTimer (this ->timerId );
84+ this ->timerId = 0 ;
85+ this ->incubate ();
86+ }
87+
88+ void QsIncubationController::incubateLater () {
89+ if (this ->followRenderloop ) {
90+ if (this ->timerId != 0 ) {
91+ this ->killTimer (this ->timerId );
92+ this ->timerId = 0 ;
93+ }
94+
95+ // Incubate again at the end of the event processing queue
96+ QMetaObject::invokeMethod (this , &QsIncubationController::incubate, Qt::QueuedConnection);
97+ } else if (this ->timerId == 0 ) {
98+ // Wait for a while before processing the next batch. Using a
99+ // timer to avoid starvation of system events.
100+ this ->timerId = this ->startTimer (this ->incubationTime );
101+ }
102+ }
103+
104+ void QsIncubationController::incubate () {
105+ if ((!this ->followRenderloop || this ->renderLoop ) && this ->incubatingObjectCount ()) {
106+ if (!this ->followRenderloop ) {
107+ this ->incubateFor (10 );
108+ if (this ->incubatingObjectCount ()) this ->incubateLater ();
109+ } else if (this ->renderLoop ->interleaveIncubation ()) {
110+ this ->incubateFor (this ->incubationTime );
111+ } else {
112+ this ->incubateFor (this ->incubationTime * 2 );
113+ if (this ->incubatingObjectCount ()) this ->incubateLater ();
114+ }
115+ }
116+ }
117+
118+ void QsIncubationController::animationStopped () { this ->incubate (); }
119+
120+ void QsIncubationController::incubatingObjectCountChanged (int count) {
121+ if (count
122+ && (!this ->followRenderloop
123+ || (this ->renderLoop && !this ->renderLoop ->interleaveIncubation ())))
124+ {
125+ this ->incubateLater ();
126+ }
127+ }
128+
129+ void QsIncubationController::updateIncubationTime () {
130+ auto * screen = QGuiApplication::primaryScreen ();
131+ if (!screen) return ;
132+
133+ // 1/3 frame on primary screen
134+ this ->incubationTime = qMax (1 , static_cast <int >(1000 / screen->refreshRate () / 3 ));
135+ }
0 commit comments