aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/items/qsgcanvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/items/qsgcanvas.cpp')
-rw-r--r--src/declarative/items/qsgcanvas.cpp218
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