summaryrefslogtreecommitdiffstats
path: root/src/canvas/qvsyncanimationdriver.cpp
blob: ff4e63de614a55f0f7de31e048c4ce92c865fd15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "qvsyncanimationdriver_p.h"

#include "private/qabstractanimation_p.h"
#include <private/qthread_p.h>

#include <QtGui/qevent.h>
#include <QtGui/qwidget.h>
#include <QtGui/qapplication.h>

#ifdef Q_WS_QPA
#include <qplatformglcontext_qpa.h>
#endif

#include <qdebug.h>

class QVSyncAnimationDriverPrivate : public QAnimationDriverPrivate
{
public:
    QWidget *window;
    bool aborted;
};


class WidgetAccessor : public QWidget
{
public:
    void paint() {
        QPaintEvent e(rect());
        paintEvent(&e);
    }
};


QVSyncAnimationDriver::QVSyncAnimationDriver(QObject *parent)
    : QAnimationDriver(*(new QVSyncAnimationDriverPrivate), parent)
{
    Q_D(QVSyncAnimationDriver);
    d->window = 0;
    d->aborted = false;

    qApp->installEventFilter(this);
}

void QVSyncAnimationDriver::setWidget(QWidget *window)
{
    d_func()->window = window;
}

QWidget *QVSyncAnimationDriver::widget() const
{
    return d_func()->window;
}

void QVSyncAnimationDriver::started()
{
    Q_D(QVSyncAnimationDriver);

    if (!d->window) {
        qWarning("VSyncDriver: no window to drive animation on...\n");
        return;
    }

    QEvent *event = new QEvent(QEvent::Type(QEvent::User + 1));
    QApplication::postEvent(this, event);
}

bool QVSyncAnimationDriver::event(QEvent *e)
{
    Q_D(QVSyncAnimationDriver);

    if (e->type() == QEvent::User + 1) {
        while (isRunning() && !d->aborted && !d->threadData->quitNow) {
            QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
            QApplication::processEvents(QEventLoop::AllEvents, 1);
            advance();
            ((WidgetAccessor *) d->window)->paint();

#ifdef Q_WS_QPA
    QPlatformGLContext *ctx = d->window->platformWindow()->glContext();
    ctx->swapBuffers();
#endif

        }
    }

    return QAnimationDriver::event(e);
}

bool QVSyncAnimationDriver::eventFilter(QObject *object, QEvent *event) {
    Q_D(QVSyncAnimationDriver);

    if (isRunning()) {

#ifdef Q_WS_QPA
        if (object == d->window && event->type() == QEvent::UpdateRequest)
            return true;
        else
#endif

        if (object == QApplication::instance() && event->type() == QEvent::Quit) {
            // If we get a close event while running, we are actually inside the processEvents()
            // block and need to exit an extra level to exit the final exec().
            d->aborted = true;
            QApplication::quit();
        } else if (object == d->window && event->type() == QEvent::Paint) {
            // Since we are now blocking on vsync and we do a single fullscreen update,
            // want to only respond to a single update pr 16.66 ms increment, which is
            // the one we explicitly send to the window. All others we reject.
            return true;
        }
    }

    return QObject::eventFilter(object, event);
}

void QVSyncAnimationDriver::stopped()
{
    // I don't need to do nothing as baseclass sets isRunning to false for us..
}