diff options
Diffstat (limited to 'src/declarative/items/qsgcanvas.cpp')
-rw-r--r-- | src/declarative/items/qsgcanvas.cpp | 218 |
1 files changed, 181 insertions, 37 deletions
diff --git a/src/declarative/items/qsgcanvas.cpp b/src/declarative/items/qsgcanvas.cpp index f12f936b4e..30dc5cab02 100644 --- a/src/declarative/items/qsgcanvas.cpp +++ b/src/declarative/items/qsgcanvas.cpp @@ -45,6 +45,8 @@ #include "qsgitem.h" #include "qsgitem_p.h" +#include "qsgevent.h" + #include <private/qsgrenderer_p.h> #include <private/qsgflashnode_p.h> @@ -172,7 +174,7 @@ void QSGCanvas::paintEvent(QPaintEvent *) int lastFrame = frameTimer.restart(); #endif - if (d->animationDriver->isRunning()) + if (d->animationDriver && d->animationDriver->isRunning()) d->animationDriver->advance(); #ifdef FRAME_TIMING @@ -220,7 +222,7 @@ void QSGCanvas::paintEvent(QPaintEvent *) QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Painting); - if (d->animationDriver->isRunning()) + if (d->animationDriver && d->animationDriver->isRunning()) update(); } else { if (updatesEnabled()) { @@ -248,25 +250,32 @@ void QSGCanvas::showEvent(QShowEvent *e) QGLWidget::showEvent(e); - if (d->threadedRendering) { - if (!d->animationDriver) { - d->animationDriver = d->context->createAnimationDriver(this); - connect(d->animationDriver, SIGNAL(started()), d->thread, SLOT(animationStarted()), Qt::DirectConnection); - connect(d->animationDriver, SIGNAL(stopped()), d->thread, SLOT(animationStopped()), Qt::DirectConnection); - } - d->animationDriver->install(); - d->thread->startRenderThread(); - setUpdatesEnabled(true); - } else { - makeCurrent(); + if (!d->contextFailed) { + if (d->threadedRendering) { + if (d->vsyncAnimations) { + if (!d->animationDriver) { + d->animationDriver = d->context->createAnimationDriver(this); + connect(d->animationDriver, SIGNAL(started()), d->thread, SLOT(animationStarted()), Qt::DirectConnection); + connect(d->animationDriver, SIGNAL(stopped()), d->thread, SLOT(animationStopped()), Qt::DirectConnection); + } + d->animationDriver->install(); + } + d->thread->startRenderThread(); + setUpdatesEnabled(true); + } else { + makeCurrent(); - if (!d->context || !d->context->isReady()) { - d->initializeSceneGraph(); - d->animationDriver = d->context->createAnimationDriver(this); - connect(d->animationDriver, SIGNAL(started()), this, SLOT(update())); - } + if (!d->context || !d->context->isReady()) { + d->initializeSceneGraph(); + if (d->vsyncAnimations) { + d->animationDriver = d->context->createAnimationDriver(this); + connect(d->animationDriver, SIGNAL(started()), this, SLOT(update())); + } + } - d->animationDriver->install(); + if (d->animationDriver) + d->animationDriver->install(); + } } } @@ -274,15 +283,57 @@ void QSGCanvas::hideEvent(QHideEvent *e) { Q_D(QSGCanvas); - if (d->threadedRendering) { - d->thread->stopRenderThread(); - } + if (!d->contextFailed) { + if (d->threadedRendering) { + d->thread->stopRenderThread(); + } - d->animationDriver->uninstall(); + if (d->animationDriver) + d->animationDriver->uninstall(); + } QGLWidget::hideEvent(e); } + + +/*! + Sets weither this canvas should use vsync driven animations. + + This option can only be set on one single QSGCanvas, and that it's + vsync signal will then be used to drive all animations in the + process. + + This feature is primarily useful for single QSGCanvas, QML-only + applications. + + \warning Enabling vsync on multiple QSGCanvas instances has + undefined behavior. + */ +void QSGCanvas::setVSyncAnimations(bool enabled) +{ + Q_D(QSGCanvas); + if (isVisible()) { + qWarning("QSGCanvas::setVSyncAnimations: Cannot be changed when widget is shown"); + return; + } + d->vsyncAnimations = enabled; +} + + + +/*! + Returns true if this canvas should use vsync driven animations; + otherwise returns false. + */ +bool QSGCanvas::vsyncAnimations() const +{ + Q_D(const QSGCanvas); + return d->vsyncAnimations; +} + + + void QSGCanvas::focusOutEvent(QFocusEvent *event) { Q_D(QSGCanvas); @@ -374,9 +425,11 @@ QSGCanvasPrivate::QSGCanvasPrivate() , hoverItem(0) , dirtyItemList(0) , context(0) + , contextFailed(false) , threadedRendering(false) , animationRunning(false) , renderThreadAwakened(false) + , vsyncAnimations(false) , thread(0) , animationDriver(0) { @@ -391,6 +444,11 @@ void QSGCanvasPrivate::init(QSGCanvas *c) { QUnifiedTimer::instance(true)->setConsistentTiming(qmlFixedAnimationStep()); + if (!c->context() || !c->context()->isValid()) { + contextFailed = true; + qWarning("QSGCanvas: Couldn't acquire a GL context."); + } + q_ptr = c; Q_Q(QSGCanvas); @@ -877,18 +935,20 @@ QSGCanvas::~QSGCanvas() d->cleanupNodes(); - // We need to remove all references to textures pointing to "our" QSGContext - // from the QDeclarativePixmapCache. Call into the cache to remove the GL / Scene Graph - // part of those cache entries. - // To "play nice" with other GL apps that are potentially running in the GUI thread, - // We get the current context and only temporarily make our own current - QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext()); - makeCurrent(); - extern void qt_declarative_pixmapstore_clean(QSGContext *context); - qt_declarative_pixmapstore_clean(d->context); - delete d->context; - if (currentContext) - currentContext->makeCurrent(); + if (!d->contextFailed) { + // We need to remove all references to textures pointing to "our" QSGContext + // from the QDeclarativePixmapCache. Call into the cache to remove the GL / Scene Graph + // part of those cache entries. + // To "play nice" with other GL apps that are potentially running in the GUI thread, + // We get the current context and only temporarily make our own current + QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext()); + makeCurrent(); + extern void qt_declarative_pixmapstore_clean(QSGContext *context); + qt_declarative_pixmapstore_clean(d->context); + delete d->context; + if (currentContext) + currentContext->makeCurrent(); + } } QSGItem *QSGCanvas::rootItem() const @@ -944,7 +1004,7 @@ bool QSGCanvas::event(QEvent *e) d->thread->syncAlreadyHappened = false; - if (d->animationRunning) { + if (d->animationRunning && d->animationDriver) { #ifdef THREAD_DEBUG qDebug("GUI: Advancing animations...\n"); #endif @@ -975,6 +1035,12 @@ bool QSGCanvas::event(QEvent *e) d->clearHover(); d->lastMousePosition = QPoint(); break; + case QSGEvent::SGDragEnter: + case QSGEvent::SGDragExit: + case QSGEvent::SGDragMove: + case QSGEvent::SGDragDrop: + d->deliverDragEvent(static_cast<QSGDragEvent *>(e)); + break; default: break; } @@ -1434,6 +1500,78 @@ bool QSGCanvasPrivate::deliverTouchPoints(QSGItem *item, QTouchEvent *event, con return false; } +void QSGCanvasPrivate::deliverDragEvent(QSGDragEvent *event) +{ + Q_Q(QSGCanvas); + if (event->type() == QSGEvent::SGDragExit || event->type() == QSGEvent::SGDragDrop) { + if (QSGItem *grabItem = event->grabItem()) { + event->setPosition(grabItem->mapFromScene(event->scenePosition())); + q->sendEvent(grabItem, event); + } + } else if (!deliverDragEvent(rootItem, event)) { + if (QSGItem *grabItem = event->grabItem()) { + QSGDragEvent exitEvent(QSGEvent::SGDragExit, *event); + exitEvent.setPosition(grabItem->mapFromScene(event->scenePosition())); + q->sendEvent(grabItem, &exitEvent); + event->setDropItem(0); + event->setGrabItem(0); + } + event->setAccepted(false); + } +} + +bool QSGCanvasPrivate::deliverDragEvent(QSGItem *item, QSGDragEvent *event) +{ + Q_Q(QSGCanvas); + QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item); + if (itemPrivate->opacity == 0.0) + return false; + + if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) { + QPointF p = item->mapFromScene(event->scenePosition()); + if (!QRectF(0, 0, item->width(), item->height()).contains(p)) + return false; + } + + QList<QSGItem *> children = itemPrivate->paintOrderChildItems(); + for (int ii = children.count() - 1; ii >= 0; --ii) { + QSGItem *child = children.at(ii); + if (!child->isVisible() || !child->isEnabled()) + continue; + if (deliverDragEvent(child, event)) + return true; + } + + QPointF p = item->mapFromScene(event->scenePosition()); + if (QRectF(0, 0, item->width(), item->height()).contains(p)) { + event->setPosition(p); + + if (event->type() == QSGEvent::SGDragMove && item != event->grabItem()) { + QSGDragEvent enterEvent(QSGEvent::SGDragEnter, *event); + q->sendEvent(item, &enterEvent); + if (enterEvent.isAccepted()) { + if (QSGItem *grabItem = event->grabItem()) { + QSGDragEvent exitEvent(QSGEvent::SGDragExit, *event); + q->sendEvent(grabItem, &exitEvent); + } + event->setDropItem(enterEvent.dropItem()); + event->setGrabItem(item); + } else { + return false; + } + } + + q->sendEvent(item, event); + if (event->isAccepted()) { + event->setGrabItem(item); + return true; + } + event->setAccepted(true); + } + + return false; +} + bool QSGCanvasPrivate::sendFilteredMouseEvent(QSGItem *target, QSGItem *item, QGraphicsSceneMouseEvent *event) { if (!target) @@ -1509,6 +1647,12 @@ bool QSGCanvas::sendEvent(QSGItem *item, QEvent *e) case QEvent::TouchEnd: QSGItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e)); break; + case QSGEvent::SGDragEnter: + case QSGEvent::SGDragExit: + case QSGEvent::SGDragMove: + case QSGEvent::SGDragDrop: + QSGItemPrivate::get(item)->deliverDragEvent(static_cast<QSGDragEvent *>(e)); + break; default: break; } @@ -1950,7 +2094,7 @@ void QSGCanvasRenderThread::run() // but we don't want to lock an extra time. wake(); - if (!d->animationRunning && !isExternalUpdatePending) { + if (!d->animationRunning && !isExternalUpdatePending && !shouldExit) { #ifdef THREAD_DEBUG printf(" RenderThread: nothing to do, going to sleep...\n"); #endif |