1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qsgcanvas.h"
43 #include "qsgcanvas_p.h"
46 #include "qsgitem_p.h"
48 #include <private/qsgrenderer_p.h>
49 #include <private/qsgflashnode_p.h>
51 #include <QtGui/qpainter.h>
52 #include <QtGui/qgraphicssceneevent.h>
53 #include <QtGui/qmatrix4x4.h>
54 #include <QtGui/qinputcontext.h>
55 #include <QtCore/qvarlengtharray.h>
56 #include <QtCore/qabstractanimation.h>
58 #include <private/qdeclarativedebugtrace_p.h>
62 DEFINE_BOOL_CONFIG_OPTION(qmlThreadedRenderer, QML_THREADED_RENDERER)
68 Prior to being added to a valid canvas items can set and clear focus with no
69 effect. Only once items are added to a canvas (by way of having a parent set that
70 already belongs to a canvas) do the focus rules apply. Focus goes back to
71 having no effect if an item is removed from a canvas.
73 When an item is moved into a new focus scope (either being added to a canvas
74 for the first time, or having its parent changed), if the focus scope already has
75 a scope focused item that takes precedence over the item being added. Otherwise,
76 the focus of the added tree is used. In the case of of a tree of items being
77 added to a canvas for the first time, which may have a conflicted focus state (two
78 or more items in one scope having focus set), the same rule is applied item by item -
79 thus the first item that has focus will get it (assuming the scope doesn't already
80 have a scope focused item), and the other items will have their focus cleared.
83 // #define FOCUS_DEBUG
84 // #define MOUSE_DEBUG
85 // #define TOUCH_DEBUG
86 // #define DIRTY_DEBUG
87 // #define THREAD_DEBUG
89 // #define FRAME_TIMING
92 static QTime frameTimer;
93 int sceneGraphRenderTime;
98 class QSGAnimationDriver : public QAnimationDriver
101 QSGAnimationDriver(QWidget *w, QObject *parent)
102 : QAnimationDriver(parent), widget(w)
115 QSGItem::UpdatePaintNodeData::UpdatePaintNodeData()
120 QSGRootItem::QSGRootItem()
124 QSGThreadedRendererAnimationDriver::QSGThreadedRendererAnimationDriver(QSGCanvasPrivate *r, QObject *parent)
125 : QAnimationDriver(parent)
130 void QSGThreadedRendererAnimationDriver::started()
133 qWarning("AnimationDriver: Main Thread: started");
135 renderer->mutex.lock();
136 renderer->animationRunning = true;
138 renderer->wait.wakeOne();
139 renderer->mutex.unlock();
144 void QSGThreadedRendererAnimationDriver::stopped()
147 qWarning("AnimationDriver: Main Thread: stopped");
149 renderer->mutex.lock();
150 renderer->animationRunning = false;
151 renderer->mutex.unlock();
154 void QSGCanvas::paintEvent(QPaintEvent *)
158 if (!d->threadedRendering) {
160 int lastFrame = frameTimer.restart();
163 if (d->animationDriver->isRunning())
164 d->animationDriver->advance();
167 int animationTime = frameTimer.elapsed();
170 Q_ASSERT(d->context);
174 QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::FramePaint);
175 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Painting);
178 int polishTime = frameTimer.elapsed();
184 int makecurrentTime = frameTimer.elapsed();
190 int syncTime = frameTimer.elapsed();
193 d->renderSceneGraph();
196 printf("FrameTimes, last=%d, animations=%d, polish=%d, makeCurrent=%d, sync=%d, sgrender=%d, readback=%d, total=%d\n",
199 polishTime - animationTime,
200 makecurrentTime - polishTime,
201 syncTime - makecurrentTime,
202 sceneGraphRenderTime - syncTime,
203 readbackTime - sceneGraphRenderTime,
204 frameTimer.elapsed());
207 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Painting);
209 if (d->animationDriver->isRunning())
214 void QSGCanvas::resizeEvent(QResizeEvent *e)
217 if (d->threadedRendering) {
219 QGLWidget::resizeEvent(e);
220 d->widgetSize = e->size();
223 d->widgetSize = e->size();
224 d->viewportSize = d->widgetSize;
225 QGLWidget::resizeEvent(e);
229 void QSGCanvas::showEvent(QShowEvent *e)
233 QGLWidget::showEvent(e);
235 if (d->threadedRendering) {
236 d->contextInThread = true;
238 if (!d->animationDriver)
239 d->animationDriver = new QSGThreadedRendererAnimationDriver(d, this);
240 d->animationDriver->install();
243 d->wait.wait(&d->mutex);
248 if (!d->context || !d->context->isReady()) {
249 d->initializeSceneGraph();
250 d->animationDriver = new QSGAnimationDriver(this, this);
253 d->animationDriver->install();
257 void QSGCanvas::hideEvent(QHideEvent *e)
261 if (d->threadedRendering) {
263 d->exitThread = true;
265 d->wait.wait(&d->mutex);
266 d->exitThread = false;
271 d->animationDriver->uninstall();
273 QGLWidget::hideEvent(e);
277 void QSGCanvasPrivate::initializeSceneGraph()
280 context = QSGContext::createDefaultContext();
282 if (context->isReady())
285 QGLContext *glctx = const_cast<QGLContext *>(QGLContext::currentContext());
286 context->initialize(glctx);
288 if (!threadedRendering) {
290 QObject::connect(context->renderer(), SIGNAL(sceneGraphChanged()), q, SLOT(maybeUpdate()),
291 Qt::DirectConnection);
294 if (!QSGItemPrivate::get(rootItem)->itemNode()->parent()) {
295 context->rootNode()->appendChildNode(QSGItemPrivate::get(rootItem)->itemNode());
298 emit q_func()->sceneGraphInitialized();
301 void QSGCanvasPrivate::polishItems()
303 while (!itemsToPolish.isEmpty()) {
304 QSet<QSGItem *>::Iterator iter = itemsToPolish.begin();
305 QSGItem *item = *iter;
306 itemsToPolish.erase(iter);
307 QSGItemPrivate::get(item)->polishScheduled = false;
308 item->updatePolish();
313 void QSGCanvasPrivate::syncSceneGraph()
319 void QSGCanvasPrivate::renderSceneGraph()
321 QGLContext *glctx = const_cast<QGLContext *>(QGLContext::currentContext());
323 context->renderer()->setDeviceRect(QRect(QPoint(0, 0), viewportSize));
324 context->renderer()->setViewportRect(QRect(QPoint(0, 0), viewportSize));
325 context->renderer()->setProjectMatrixToDeviceRect();
327 context->renderNextFrame();
330 sceneGraphRenderTime = frameTimer.elapsed();
336 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
337 readbackTime = frameTimer.elapsed();
340 glctx->swapBuffers();
344 void QSGCanvas::sceneGraphChanged()
347 d->needsRepaint = true;
351 void QSGCanvasPrivate::runThread()
354 qWarning("QSGRenderer: Render thread running");
358 printf("QSGCanvas::runThread(), rendering in a thread...\n");
361 initializeSceneGraph();
363 QObject::connect(context->renderer(), SIGNAL(sceneGraphChanged()),
364 q, SLOT(sceneGraphChanged()),
365 Qt::DirectConnection);
368 wait.wakeOne(); // Wake the main thread waiting for us to start
377 if (s != viewportSize) {
378 glViewport(0, 0, s.width(), s.height());
383 qWarning("QSGRenderer: Render Thread: Waiting for main thread to stop");
385 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
390 qWarning("QSGRenderer: Render Thread: Shutting down...");
396 qWarning("QSGRenderer: Render Thread: Main thread has stopped, syncing scene");
399 // Do processing while main thread is frozen
403 qWarning("QSGRenderer: Render Thread: Resuming main thread");
406 // Read animationRunning while inside the locked section
407 bool continous = animationRunning;
412 bool enterIdle = false;
415 qWarning("QSGRenderer: Render Thread: rendering scene");
418 needsRepaint = false;
419 } else if (continous) {
421 qWarning("QSGRenderer: Render Thread: waiting a while...");
432 qWarning("QSGRenderer: Render Thread: Nothing has changed, going idle...");
438 qWarning("QSGRenderer: Render Thread: waking up from idle");
446 qWarning("QSGRenderer: Render Thread: shutting down, waking up main thread");
454 QSGCanvasPrivate::QSGCanvasPrivate()
457 , mouseGrabberItem(0)
461 , contextInThread(false)
462 , threadedRendering(false)
464 , animationRunning(false)
467 , renderThreadAwakened(false)
468 , thread(new MyThread(this))
471 threadedRendering = qmlThreadedRenderer();
474 QSGCanvasPrivate::~QSGCanvasPrivate()
478 void QSGCanvasPrivate::init(QSGCanvas *c)
484 q->setAttribute(Qt::WA_AcceptTouchEvents);
485 q->setFocusPolicy(Qt::StrongFocus);
487 rootItem = new QSGRootItem;
488 QSGItemPrivate *rootItemPrivate = QSGItemPrivate::get(rootItem);
489 rootItemPrivate->canvas = q;
490 rootItemPrivate->flags |= QSGItem::ItemIsFocusScope;
491 rootItemPrivate->focus = true;
492 rootItemPrivate->activeFocus = true;
493 activeFocusItem = rootItem;
495 context = QSGContext::createDefaultContext();
498 void QSGCanvasPrivate::sceneMouseEventForTransform(QGraphicsSceneMouseEvent &sceneEvent,
499 const QTransform &transform)
501 sceneEvent.setPos(transform.map(sceneEvent.scenePos()));
502 sceneEvent.setLastPos(transform.map(sceneEvent.lastScenePos()));
503 for (int ii = 0; ii < 5; ++ii) {
504 if (sceneEvent.buttons() & (1 << ii)) {
505 sceneEvent.setButtonDownPos((Qt::MouseButton)(1 << ii),
506 transform.map(sceneEvent.buttonDownScenePos((Qt::MouseButton)(1 << ii))));
511 void QSGCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
513 for (int i=0; i<touchPoints.count(); i++) {
514 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
515 touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
516 touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
517 touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
521 QEvent::Type QSGCanvasPrivate::sceneMouseEventTypeFromMouseEvent(QMouseEvent *event)
523 switch(event->type()) {
525 Q_ASSERT(!"Unknown event type");
526 case QEvent::MouseButtonPress:
527 return QEvent::GraphicsSceneMousePress;
528 case QEvent::MouseButtonRelease:
529 return QEvent::GraphicsSceneMouseRelease;
530 case QEvent::MouseButtonDblClick:
531 return QEvent::GraphicsSceneMouseDoubleClick;
532 case QEvent::MouseMove:
533 return QEvent::GraphicsSceneMouseMove;
538 Fill in the data in \a sceneEvent based on \a event. This method leaves the item local positions in
539 \a sceneEvent untouched. Use sceneMouseEventForTransform() to fill in those details.
541 void QSGCanvasPrivate::sceneMouseEventFromMouseEvent(QGraphicsSceneMouseEvent &sceneEvent, QMouseEvent *event)
547 if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
548 if ((event->button() & event->buttons()) == event->buttons()) {
549 lastMousePosition = event->pos();
552 switch (event->button()) {
554 Q_ASSERT(!"Unknown button");
556 buttonDownPositions[0] = event->pos();
558 case Qt::RightButton:
559 buttonDownPositions[1] = event->pos();
561 case Qt::MiddleButton:
562 buttonDownPositions[2] = event->pos();
565 buttonDownPositions[3] = event->pos();
568 buttonDownPositions[4] = event->pos();
573 sceneEvent.setScenePos(event->pos());
574 sceneEvent.setScreenPos(event->globalPos());
575 sceneEvent.setLastScenePos(lastMousePosition);
576 sceneEvent.setLastScreenPos(q->mapToGlobal(lastMousePosition));
577 sceneEvent.setButtons(event->buttons());
578 sceneEvent.setButton(event->button());
579 sceneEvent.setModifiers(event->modifiers());
580 sceneEvent.setWidget(q);
582 for (int ii = 0; ii < 5; ++ii) {
583 if (sceneEvent.buttons() & (1 << ii)) {
584 sceneEvent.setButtonDownScenePos((Qt::MouseButton)(1 << ii), buttonDownPositions[ii]);
585 sceneEvent.setButtonDownScreenPos((Qt::MouseButton)(1 << ii), q->mapToGlobal(buttonDownPositions[ii]));
589 lastMousePosition = event->pos();
593 Fill in the data in \a hoverEvent based on \a mouseEvent. This method leaves the item local positions in
594 \a hoverEvent untouched (these are filled in later).
596 void QSGCanvasPrivate::sceneHoverEventFromMouseEvent(QGraphicsSceneHoverEvent &hoverEvent, QMouseEvent *mouseEvent)
599 hoverEvent.setWidget(q);
600 hoverEvent.setScenePos(mouseEvent->pos());
601 hoverEvent.setScreenPos(mouseEvent->globalPos());
602 if (lastMousePosition.isNull()) lastMousePosition = mouseEvent->pos();
603 hoverEvent.setLastScenePos(lastMousePosition);
604 hoverEvent.setLastScreenPos(q->mapToGlobal(lastMousePosition));
605 hoverEvent.setModifiers(mouseEvent->modifiers());
606 hoverEvent.setAccepted(mouseEvent->isAccepted());
608 lastMousePosition = mouseEvent->pos();
612 Translates the data in \a touchEvent to this canvas. This method leaves the item local positions in
613 \a touchEvent untouched (these are filled in later).
615 void QSGCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
619 touchEvent->setWidget(q);
621 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
622 for (int i = 0; i < touchPoints.count(); ++i) {
623 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
625 touchPoint.setScreenRect(touchPoint.sceneRect());
626 touchPoint.setStartScreenPos(touchPoint.startScenePos());
627 touchPoint.setLastScreenPos(touchPoint.lastScenePos());
629 touchPoint.setSceneRect(touchPoint.rect());
630 touchPoint.setStartScenePos(touchPoint.startPos());
631 touchPoint.setLastScenePos(touchPoint.lastPos());
633 if (touchPoint.isPrimary())
634 lastMousePosition = touchPoint.pos().toPoint();
636 touchEvent->setTouchPoints(touchPoints);
639 void QSGCanvasPrivate::setFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions options)
647 qWarning() << "QSGCanvasPrivate::setFocusInScope():";
648 qWarning() << " scope:" << (QObject *)scope;
649 qWarning() << " scopeSubFocusItem:" << (QObject *)QSGItemPrivate::get(scope)->subFocusItem;
650 qWarning() << " item:" << (QObject *)item;
651 qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
654 QSGItemPrivate *scopePrivate = QSGItemPrivate::get(scope);
655 QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
657 QSGItem *oldActiveFocusItem = 0;
658 QSGItem *newActiveFocusItem = 0;
660 QVarLengthArray<QSGItem *, 20> changed;
662 // Does this change the active focus?
663 if (scopePrivate->activeFocus) {
664 oldActiveFocusItem = activeFocusItem;
665 newActiveFocusItem = item;
666 while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
667 newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
669 Q_ASSERT(oldActiveFocusItem);
672 if (QInputContext *ic = inputContext())
677 QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
678 q->sendEvent(oldActiveFocusItem, &event);
680 QSGItem *afi = oldActiveFocusItem;
681 while (afi != scope) {
682 if (QSGItemPrivate::get(afi)->activeFocus) {
683 QSGItemPrivate::get(afi)->activeFocus = false;
686 afi = afi->parentItem();
690 QSGItem *oldSubFocusItem = scopePrivate->subFocusItem;
691 // Correct focus chain in scope
692 if (oldSubFocusItem) {
693 QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
694 while (sfi != scope) {
695 QSGItemPrivate::get(sfi)->subFocusItem = 0;
696 sfi = sfi->parentItem();
700 scopePrivate->subFocusItem = item;
701 QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
702 while (sfi != scope) {
703 QSGItemPrivate::get(sfi)->subFocusItem = item;
704 sfi = sfi->parentItem();
708 if (oldSubFocusItem) {
709 QSGItemPrivate::get(oldSubFocusItem)->focus = false;
710 changed << oldSubFocusItem;
713 if (!(options & DontChangeFocusProperty)) {
714 itemPrivate->focus = true;
718 if (newActiveFocusItem) {
719 activeFocusItem = newActiveFocusItem;
721 QSGItemPrivate::get(newActiveFocusItem)->activeFocus = true;
722 changed << newActiveFocusItem;
724 QSGItem *afi = newActiveFocusItem->parentItem();
725 while (afi != scope) {
726 if (afi->isFocusScope()) {
727 QSGItemPrivate::get(afi)->activeFocus = true;
730 afi = afi->parentItem();
733 updateInputMethodData();
735 QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
736 q->sendEvent(newActiveFocusItem, &event);
738 updateInputMethodData();
741 if (!changed.isEmpty())
742 notifyFocusChangesRecur(changed.data(), changed.count() - 1);
745 void QSGCanvasPrivate::clearFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions options)
753 qWarning() << "QSGCanvasPrivate::clearFocusInScope():";
754 qWarning() << " scope:" << (QObject *)scope;
755 qWarning() << " item:" << (QObject *)item;
756 qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
759 QSGItemPrivate *scopePrivate = QSGItemPrivate::get(scope);
761 QSGItem *oldActiveFocusItem = 0;
762 QSGItem *newActiveFocusItem = 0;
764 QVarLengthArray<QSGItem *, 20> changed;
766 Q_ASSERT(item == scopePrivate->subFocusItem);
768 // Does this change the active focus?
769 if (scopePrivate->activeFocus) {
770 oldActiveFocusItem = activeFocusItem;
771 newActiveFocusItem = scope;
773 Q_ASSERT(oldActiveFocusItem);
776 if (QInputContext *ic = inputContext())
781 QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
782 q->sendEvent(oldActiveFocusItem, &event);
784 QSGItem *afi = oldActiveFocusItem;
785 while (afi != scope) {
786 if (QSGItemPrivate::get(afi)->activeFocus) {
787 QSGItemPrivate::get(afi)->activeFocus = false;
790 afi = afi->parentItem();
794 QSGItem *oldSubFocusItem = scopePrivate->subFocusItem;
795 // Correct focus chain in scope
796 if (oldSubFocusItem) {
797 QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
798 while (sfi != scope) {
799 QSGItemPrivate::get(sfi)->subFocusItem = 0;
800 sfi = sfi->parentItem();
803 scopePrivate->subFocusItem = 0;
805 if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
806 QSGItemPrivate::get(oldSubFocusItem)->focus = false;
807 changed << oldSubFocusItem;
810 if (newActiveFocusItem) {
811 Q_ASSERT(newActiveFocusItem == scope);
812 activeFocusItem = scope;
814 updateInputMethodData();
816 QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
817 q->sendEvent(newActiveFocusItem, &event);
819 updateInputMethodData();
822 if (!changed.isEmpty())
823 notifyFocusChangesRecur(changed.data(), changed.count() - 1);
826 void QSGCanvasPrivate::notifyFocusChangesRecur(QSGItem **items, int remaining)
828 QDeclarativeGuard<QSGItem> item(*items);
831 notifyFocusChangesRecur(items + 1, remaining - 1);
834 QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
836 if (itemPrivate->notifiedFocus != itemPrivate->focus) {
837 itemPrivate->notifiedFocus = itemPrivate->focus;
838 emit item->focusChanged(itemPrivate->focus);
841 if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
842 itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
843 itemPrivate->itemChange(QSGItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
844 emit item->activeFocusChanged(itemPrivate->activeFocus);
849 void QSGCanvasPrivate::updateInputMethodData()
852 bool enabled = activeFocusItem
853 && (QSGItemPrivate::get(activeFocusItem)->flags & QSGItem::ItemAcceptsInputMethod);
854 q->setAttribute(Qt::WA_InputMethodEnabled, enabled);
855 q->setInputMethodHints(enabled ? activeFocusItem->inputMethodHints() : Qt::ImhNone);
858 QVariant QSGCanvas::inputMethodQuery(Qt::InputMethodQuery query) const
860 Q_D(const QSGCanvas);
861 if (!d->activeFocusItem || !(QSGItemPrivate::get(d->activeFocusItem)->flags & QSGItem::ItemAcceptsInputMethod))
863 QVariant value = d->activeFocusItem->inputMethodQuery(query);
866 QVariant::Type type = value.type();
867 if (type == QVariant::RectF || type == QVariant::Rect) {
868 const QTransform transform = QSGItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
869 value = transform.mapRect(value.toRectF());
870 } else if (type == QVariant::PointF || type == QVariant::Point) {
871 const QTransform transform = QSGItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
872 value = transform.map(value.toPointF());
877 void QSGCanvasPrivate::dirtyItem(QSGItem *)
883 void QSGCanvasPrivate::cleanup(QSGNode *n)
887 Q_ASSERT(!cleanupNodeList.contains(n));
888 cleanupNodeList.append(n);
892 static QGLFormat tweakFormat(const QGLFormat &format = QGLFormat::defaultFormat())
894 QGLFormat f = format;
895 f.setSwapInterval(1);
899 QSGCanvas::QSGCanvas(QWidget *parent, Qt::WindowFlags f)
900 : QGLWidget(*(new QSGCanvasPrivate), tweakFormat(), parent, (QGLWidget *) 0, f)
907 QSGCanvas::QSGCanvas(const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
908 : QGLWidget(*(new QSGCanvasPrivate), tweakFormat(format), parent, (QGLWidget *) 0, f)
915 QSGCanvas::QSGCanvas(QSGCanvasPrivate &dd, QWidget *parent, Qt::WindowFlags f)
916 : QGLWidget(dd, tweakFormat(), parent, 0, f)
923 QSGCanvas::QSGCanvas(QSGCanvasPrivate &dd, const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
924 : QGLWidget(dd, tweakFormat(format), parent, 0, f)
931 QSGCanvas::~QSGCanvas()
935 // ### should we change ~QSGItem to handle this better?
936 // manually cleanup for the root item (item destructor only handles these when an item is parented)
937 QSGItemPrivate *rootItemPrivate = QSGItemPrivate::get(d->rootItem);
938 rootItemPrivate->removeFromDirtyList();
939 rootItemPrivate->canvas = 0;
941 delete d->rootItem; d->rootItem = 0;
947 QSGItem *QSGCanvas::rootItem() const
949 Q_D(const QSGCanvas);
954 QSGItem *QSGCanvas::activeFocusItem() const
956 Q_D(const QSGCanvas);
958 return d->activeFocusItem;
961 QSGItem *QSGCanvas::mouseGrabberItem() const
963 Q_D(const QSGCanvas);
965 return d->mouseGrabberItem;
969 void QSGCanvasPrivate::clearHover()
975 QGraphicsSceneHoverEvent hoverEvent;
976 hoverEvent.setWidget(q);
978 QPoint cursorPos = QCursor::pos();
979 hoverEvent.setScenePos(q->mapFromGlobal(cursorPos));
980 hoverEvent.setLastScenePos(hoverEvent.scenePos());
981 hoverEvent.setScreenPos(cursorPos);
982 hoverEvent.setLastScreenPos(hoverEvent.screenPos());
984 QSGItem *item = hoverItem;
986 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, &hoverEvent);
990 bool QSGCanvas::event(QEvent *e)
994 if (e->type() == QEvent::User) {
995 Q_ASSERT(d->threadedRendering);
999 qWarning("QSGRenderer: Main Thread: Stopped");
1004 d->renderThreadAwakened = false;
1008 // The thread is exited when the widget has been hidden. We then need to
1009 // skip the waiting, otherwise we would be waiting for a wakeup that never
1011 if (d->thread->isRunning())
1012 d->wait.wait(&d->mutex);
1014 qWarning("QSGRenderer: Main Thread: Resumed");
1018 if (d->animationRunning)
1019 d->animationDriver->advance();
1022 switch (e->type()) {
1024 case QEvent::TouchBegin:
1025 case QEvent::TouchUpdate:
1026 case QEvent::TouchEnd:
1028 QTouchEvent *touch = static_cast<QTouchEvent *>(e);
1029 d->translateTouchEvent(touch);
1030 d->deliverTouchEvent(touch);
1031 if (!touch->isAccepted())
1036 d->lastMousePosition = QPoint();
1042 return QGLWidget::event(e);
1045 void QSGCanvas::keyPressEvent(QKeyEvent *e)
1049 sendEvent(d->activeFocusItem, e);
1052 void QSGCanvas::keyReleaseEvent(QKeyEvent *e)
1056 sendEvent(d->activeFocusItem, e);
1059 void QSGCanvas::inputMethodEvent(QInputMethodEvent *e)
1063 sendEvent(d->activeFocusItem, e);
1066 bool QSGCanvasPrivate::deliverInitialMousePressEvent(QSGItem *item, QGraphicsSceneMouseEvent *event)
1070 QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
1071 if (itemPrivate->opacity == 0.0)
1074 if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
1075 QPointF p = item->mapFromScene(event->scenePos());
1076 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1080 QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
1081 for (int ii = children.count() - 1; ii >= 0; --ii) {
1082 QSGItem *child = children.at(ii);
1083 if (!child->isVisible() || !child->isEnabled())
1085 if (deliverInitialMousePressEvent(child, event))
1089 if (itemPrivate->acceptedMouseButtons & event->button()) {
1090 QPointF p = item->mapFromScene(event->scenePos());
1091 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1092 sceneMouseEventForTransform(*event, itemPrivate->canvasToItemTransform());
1094 mouseGrabberItem = item;
1095 q->sendEvent(item, event);
1096 if (event->isAccepted())
1098 mouseGrabberItem->ungrabMouse();
1099 mouseGrabberItem = 0;
1106 bool QSGCanvasPrivate::deliverMouseEvent(QGraphicsSceneMouseEvent *sceneEvent)
1110 if (!mouseGrabberItem &&
1111 sceneEvent->type() == QEvent::GraphicsSceneMousePress &&
1112 (sceneEvent->button() & sceneEvent->buttons()) == sceneEvent->buttons()) {
1114 return deliverInitialMousePressEvent(rootItem, sceneEvent);
1117 if (mouseGrabberItem) {
1118 QSGItemPrivate *mgPrivate = QSGItemPrivate::get(mouseGrabberItem);
1119 sceneMouseEventForTransform(*sceneEvent, mgPrivate->canvasToItemTransform());
1121 sceneEvent->accept();
1122 q->sendEvent(mouseGrabberItem, sceneEvent);
1123 if (sceneEvent->isAccepted())
1130 void QSGCanvas::mousePressEvent(QMouseEvent *event)
1135 qWarning() << "QSGCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
1138 QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
1139 d->sceneMouseEventFromMouseEvent(sceneEvent, event);
1141 d->deliverMouseEvent(&sceneEvent);
1142 event->setAccepted(sceneEvent.isAccepted());
1145 void QSGCanvas::mouseReleaseEvent(QMouseEvent *event)
1150 qWarning() << "QSGCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
1153 if (!d->mouseGrabberItem) {
1154 QGLWidget::mouseReleaseEvent(event);
1158 QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
1159 d->sceneMouseEventFromMouseEvent(sceneEvent, event);
1161 d->deliverMouseEvent(&sceneEvent);
1162 event->setAccepted(sceneEvent.isAccepted());
1164 d->mouseGrabberItem = 0;
1167 void QSGCanvas::mouseDoubleClickEvent(QMouseEvent *event)
1172 qWarning() << "QSGCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
1175 QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
1176 d->sceneMouseEventFromMouseEvent(sceneEvent, event);
1178 if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
1179 if (d->deliverInitialMousePressEvent(d->rootItem, &sceneEvent))
1186 d->deliverMouseEvent(&sceneEvent);
1187 event->setAccepted(sceneEvent.isAccepted());
1190 void QSGCanvasPrivate::sendHoverEvent(QEvent::Type type, QSGItem *item,
1191 QGraphicsSceneHoverEvent *event)
1194 const QTransform transform = QSGItemPrivate::get(item)->canvasToItemTransform();
1196 //create copy of event
1197 QGraphicsSceneHoverEvent hoverEvent(type);
1198 hoverEvent.setWidget(event->widget());
1199 hoverEvent.setPos(transform.map(event->scenePos()));
1200 hoverEvent.setScenePos(event->scenePos());
1201 hoverEvent.setScreenPos(event->screenPos());
1202 hoverEvent.setLastPos(transform.map(event->lastScenePos()));
1203 hoverEvent.setLastScenePos(event->lastScenePos());
1204 hoverEvent.setLastScreenPos(event->lastScreenPos());
1205 hoverEvent.setModifiers(event->modifiers());
1206 hoverEvent.setAccepted(event->isAccepted());
1208 q->sendEvent(item, &hoverEvent);
1211 void QSGCanvas::mouseMoveEvent(QMouseEvent *event)
1216 qWarning() << "QSGCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
1219 if (!d->mouseGrabberItem) {
1220 QGraphicsSceneHoverEvent hoverEvent;
1221 d->sceneHoverEventFromMouseEvent(hoverEvent, event);
1223 bool delivered = d->deliverHoverEvent(d->rootItem, &hoverEvent);
1225 //take care of any exits
1227 QSGItem *item = d->hoverItem;
1229 d->sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, &hoverEvent);
1232 event->setAccepted(hoverEvent.isAccepted());
1236 QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
1237 d->sceneMouseEventFromMouseEvent(sceneEvent, event);
1239 d->deliverMouseEvent(&sceneEvent);
1240 event->setAccepted(sceneEvent.isAccepted());
1243 bool QSGCanvasPrivate::deliverHoverEvent(QSGItem *item, QGraphicsSceneHoverEvent *event)
1245 QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
1246 if (itemPrivate->opacity == 0.0)
1249 if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
1250 QPointF p = item->mapFromScene(event->scenePos());
1251 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1255 QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
1256 for (int ii = children.count() - 1; ii >= 0; --ii) {
1257 QSGItem *child = children.at(ii);
1258 if (!child->isEnabled())
1260 if (deliverHoverEvent(child, event))
1264 if (itemPrivate->hoverEnabled) {
1265 QPointF p = item->mapFromScene(event->scenePos());
1266 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1267 if (hoverItem == item) {
1269 sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, event);
1271 //exit from previous
1273 QSGItem *item = hoverItem;
1275 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, event);
1280 sendHoverEvent(QEvent::GraphicsSceneHoverEnter, item, event);
1289 bool QSGCanvasPrivate::deliverWheelEvent(QSGItem *item, QGraphicsSceneWheelEvent *event)
1292 QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
1293 if (itemPrivate->opacity == 0.0)
1296 if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
1297 QPointF p = item->mapFromScene(event->scenePos());
1298 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1302 QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
1303 for (int ii = children.count() - 1; ii >= 0; --ii) {
1304 QSGItem *child = children.at(ii);
1305 if (!child->isEnabled())
1307 if (deliverWheelEvent(child, event))
1311 QPointF p = item->mapFromScene(event->scenePos());
1312 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1313 event->setPos(itemPrivate->canvasToItemTransform().map(event->scenePos()));
1315 q->sendEvent(item, event);
1316 if (event->isAccepted())
1323 #ifndef QT_NO_WHEELEVENT
1324 void QSGCanvas::wheelEvent(QWheelEvent *event)
1328 qWarning() << "QSGCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1330 QGraphicsSceneWheelEvent wheelEvent(QEvent::GraphicsSceneWheel);
1331 wheelEvent.setWidget(this);
1332 wheelEvent.setScenePos(event->pos());
1333 wheelEvent.setScreenPos(event->globalPos());
1334 wheelEvent.setButtons(event->buttons());
1335 wheelEvent.setModifiers(event->modifiers());
1336 wheelEvent.setDelta(event->delta());
1337 wheelEvent.setOrientation(event->orientation());
1338 wheelEvent.setAccepted(false);
1340 d->deliverWheelEvent(d->rootItem, &wheelEvent);
1341 event->setAccepted(wheelEvent.isAccepted());
1343 #endif // QT_NO_WHEELEVENT
1345 bool QSGCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1348 if (event->type() == QEvent::TouchBegin)
1349 qWarning("touchBeginEvent");
1350 else if (event->type() == QEvent::TouchUpdate)
1351 qWarning("touchUpdateEvent");
1352 else if (event->type() == QEvent::TouchEnd)
1353 qWarning("touchEndEvent");
1356 QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1358 if (event->type() == QTouchEvent::TouchBegin) { // all points are new touch points
1359 QSet<int> acceptedNewPoints;
1360 deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1361 if (acceptedNewPoints.count() > 0)
1363 return event->isAccepted();
1366 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1367 QList<QTouchEvent::TouchPoint> newPoints;
1369 for (int i=0; i<touchPoints.count(); i++) {
1370 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1371 switch (touchPoint.state()) {
1372 case Qt::TouchPointPressed:
1373 newPoints << touchPoint;
1375 case Qt::TouchPointMoved:
1376 case Qt::TouchPointStationary:
1377 case Qt::TouchPointReleased:
1378 if (itemForTouchPointId.contains(touchPoint.id())) {
1379 item = itemForTouchPointId[touchPoint.id()];
1381 updatedPoints[item].append(touchPoint);
1389 if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1390 QSet<int> acceptedNewPoints;
1391 int prevCount = updatedPoints.count();
1392 deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1393 if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1397 if (event->touchPointStates() & Qt::TouchPointReleased) {
1398 for (int i=0; i<touchPoints.count(); i++) {
1399 if (touchPoints[i].state() == Qt::TouchPointReleased)
1400 itemForTouchPointId.remove(touchPoints[i].id());
1404 return event->isAccepted();
1407 bool QSGCanvasPrivate::deliverTouchPoints(QSGItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1410 QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
1412 if (itemPrivate->opacity == 0.0)
1415 if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
1416 QRectF bounds(0, 0, item->width(), item->height());
1417 for (int i=0; i<newPoints.count(); i++) {
1418 QPointF p = item->mapFromScene(newPoints[i].scenePos());
1419 if (!bounds.contains(p))
1424 QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
1425 for (int ii = children.count() - 1; ii >= 0; --ii) {
1426 QSGItem *child = children.at(ii);
1427 if (!child->isEnabled())
1429 if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1433 QList<QTouchEvent::TouchPoint> matchingPoints;
1434 if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1435 QRectF bounds(0, 0, item->width(), item->height());
1436 for (int i=0; i<newPoints.count(); i++) {
1437 if (acceptedNewPoints->contains(newPoints[i].id()))
1439 QPointF p = item->mapFromScene(newPoints[i].scenePos());
1440 if (bounds.contains(p))
1441 matchingPoints << newPoints[i];
1445 if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1446 QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1447 eventPoints.append(matchingPoints);
1448 transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1450 Qt::TouchPointStates eventStates;
1451 for (int i=0; i<eventPoints.count(); i++)
1452 eventStates |= eventPoints[i].state();
1453 // if all points have the same state, set the event type accordingly
1454 QEvent::Type eventType;
1455 switch (eventStates) {
1456 case Qt::TouchPointPressed:
1457 eventType = QEvent::TouchBegin;
1459 case Qt::TouchPointReleased:
1460 eventType = QEvent::TouchEnd;
1463 eventType = QEvent::TouchUpdate;
1467 if (eventStates != Qt::TouchPointStationary) {
1468 QTouchEvent touchEvent(eventType);
1469 touchEvent.setWidget(q);
1470 touchEvent.setDeviceType(event->deviceType());
1471 touchEvent.setModifiers(event->modifiers());
1472 touchEvent.setTouchPointStates(eventStates);
1473 touchEvent.setTouchPoints(eventPoints);
1475 touchEvent.accept();
1476 q->sendEvent(item, &touchEvent);
1478 if (touchEvent.isAccepted()) {
1479 for (int i=0; i<matchingPoints.count(); i++) {
1480 itemForTouchPointId[matchingPoints[i].id()] = item;
1481 acceptedNewPoints->insert(matchingPoints[i].id());
1487 updatedPoints->remove(item);
1488 if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1494 bool QSGCanvasPrivate::sendFilteredMouseEvent(QSGItem *target, QSGItem *item, QGraphicsSceneMouseEvent *event)
1499 if (sendFilteredMouseEvent(target->parentItem(), item, event))
1502 QSGItemPrivate *targetPrivate = QSGItemPrivate::get(target);
1503 if (targetPrivate->filtersChildMouseEvents)
1504 if (target->childMouseEventFilter(item, event))
1510 bool QSGCanvas::sendEvent(QSGItem *item, QEvent *e)
1515 qWarning("QSGCanvas::sendEvent: Cannot send event to a null item");
1521 switch (e->type()) {
1522 case QEvent::KeyPress:
1523 case QEvent::KeyRelease:
1524 QSGItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1525 while (!e->isAccepted() && (item = item->parentItem())) {
1527 QSGItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1530 case QEvent::InputMethod:
1531 QSGItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1532 while (!e->isAccepted() && (item = item->parentItem())) {
1534 QSGItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1537 case QEvent::FocusIn:
1538 case QEvent::FocusOut:
1539 QSGItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1541 case QEvent::GraphicsSceneMousePress:
1542 case QEvent::GraphicsSceneMouseRelease:
1543 case QEvent::GraphicsSceneMouseDoubleClick:
1544 case QEvent::GraphicsSceneMouseMove:
1545 // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
1547 QGraphicsSceneMouseEvent *se = static_cast<QGraphicsSceneMouseEvent *>(e);
1548 if (!d->sendFilteredMouseEvent(item->parentItem(), item, se)) {
1550 QSGItemPrivate::get(item)->deliverMouseEvent(se);
1554 case QEvent::GraphicsSceneWheel:
1555 QSGItemPrivate::get(item)->deliverWheelEvent(static_cast<QGraphicsSceneWheelEvent *>(e));
1557 case QEvent::GraphicsSceneHoverEnter:
1558 case QEvent::GraphicsSceneHoverLeave:
1559 case QEvent::GraphicsSceneHoverMove:
1560 QSGItemPrivate::get(item)->deliverHoverEvent(static_cast<QGraphicsSceneHoverEvent *>(e));
1562 case QEvent::TouchBegin:
1563 case QEvent::TouchUpdate:
1564 case QEvent::TouchEnd:
1565 QSGItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1574 void QSGCanvasPrivate::cleanupNodes()
1576 for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1577 delete cleanupNodeList.at(ii);
1578 cleanupNodeList.clear();
1581 void QSGCanvasPrivate::updateDirtyNodes()
1584 qWarning() << "QSGCanvasPrivate::updateDirtyNodes():";
1589 QSGItem *updateList = dirtyItemList;
1591 if (updateList) QSGItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1593 while (updateList) {
1594 QSGItem *item = updateList;
1595 QSGItemPrivate *itemPriv = QSGItemPrivate::get(item);
1596 itemPriv->removeFromDirtyList();
1599 qWarning() << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1601 updateDirtyNode(item);
1605 void QSGCanvasPrivate::updateDirtyNode(QSGItem *item)
1607 #ifdef QML_RUNTIME_TESTING
1608 bool didFlash = false;
1611 QSGItemPrivate *itemPriv = QSGItemPrivate::get(item);
1612 quint32 dirty = itemPriv->dirtyAttributes;
1613 itemPriv->dirtyAttributes = 0;
1615 if ((dirty & QSGItemPrivate::TransformUpdateMask) ||
1616 (dirty & QSGItemPrivate::Size && itemPriv->origin != QSGItem::TopLeft &&
1617 (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1621 if (itemPriv->x != 0. || itemPriv->y != 0.)
1622 matrix.translate(itemPriv->x, itemPriv->y);
1624 if (dirty & QSGItemPrivate::ComplexTransformUpdateMask) {
1625 for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1626 itemPriv->transforms.at(ii)->applyTo(&matrix);
1629 if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1630 QPointF origin = itemPriv->computeTransformOrigin();
1631 matrix.translate(origin.x(), origin.y());
1632 if (itemPriv->scale != 1.)
1633 matrix.scale(itemPriv->scale, itemPriv->scale);
1634 if (itemPriv->rotation != 0.)
1635 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1636 matrix.translate(-origin.x(), -origin.y());
1639 itemPriv->itemNode()->setMatrix(matrix);
1642 bool clipEffectivelyChanged = dirty & QSGItemPrivate::Clip &&
1643 ((item->clip() == false) != (itemPriv->clipNode == 0));
1644 bool effectRefEffectivelyChanged = dirty & QSGItemPrivate::EffectReference &&
1645 ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1647 if (clipEffectivelyChanged) {
1648 QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1649 QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1652 Q_ASSERT(itemPriv->clipNode == 0);
1653 itemPriv->clipNode = new QSGDefaultClipNode(QRectF(0, 0, itemPriv->width, itemPriv->height));
1656 parent->removeChildNode(child);
1657 parent->appendChildNode(itemPriv->clipNode);
1659 itemPriv->clipNode->appendChildNode(child);
1662 Q_ASSERT(itemPriv->clipNode != 0);
1663 parent->removeChildNode(itemPriv->clipNode);
1665 itemPriv->clipNode->removeChildNode(child);
1666 delete itemPriv->clipNode;
1667 itemPriv->clipNode = 0;
1669 parent->appendChildNode(child);
1673 if (dirty & QSGItemPrivate::ChildrenUpdateMask) {
1674 while (itemPriv->childContainerNode()->childCount())
1675 itemPriv->childContainerNode()->removeChildNode(itemPriv->childContainerNode()->childAtIndex(0));
1678 if (effectRefEffectivelyChanged) {
1679 QSGNode *parent = itemPriv->clipNode;
1681 parent = itemPriv->opacityNode;
1683 parent = itemPriv->itemNode();
1684 QSGNode *child = itemPriv->groupNode;
1686 if (itemPriv->effectRefCount) {
1687 Q_ASSERT(itemPriv->rootNode == 0);
1688 itemPriv->rootNode = new QSGRootNode;
1691 parent->removeChildNode(child);
1692 parent->appendChildNode(itemPriv->rootNode);
1694 itemPriv->rootNode->appendChildNode(child);
1696 Q_ASSERT(itemPriv->rootNode != 0);
1697 parent->removeChildNode(itemPriv->rootNode);
1699 itemPriv->rootNode->removeChildNode(child);
1700 delete itemPriv->rootNode;
1701 itemPriv->rootNode = 0;
1703 parent->appendChildNode(child);
1707 if (dirty & QSGItemPrivate::ChildrenUpdateMask) {
1708 QSGNode *groupNode = itemPriv->groupNode;
1710 for (int count = groupNode->childCount(); count; --count)
1711 groupNode->removeChildNode(groupNode->childAtIndex(0));
1714 QList<QSGItem *> orderedChildren = itemPriv->paintOrderChildItems();
1717 itemPriv->paintNodeIndex = 0;
1718 for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1719 QSGItemPrivate *childPrivate = QSGItemPrivate::get(orderedChildren.at(ii));
1720 if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1722 if (childPrivate->itemNode()->parent())
1723 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1725 itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1726 itemPriv->paintNodeIndex++;
1729 if (itemPriv->paintNode)
1730 itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1732 for (; ii < orderedChildren.count(); ++ii) {
1733 QSGItemPrivate *childPrivate = QSGItemPrivate::get(orderedChildren.at(ii));
1734 if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1736 if (childPrivate->itemNode()->parent())
1737 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1739 itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1743 if ((dirty & QSGItemPrivate::Size || clipEffectivelyChanged) && itemPriv->clipNode) {
1744 itemPriv->clipNode->setRect(QRectF(0, 0, itemPriv->width, itemPriv->height));
1745 itemPriv->clipNode->update();
1748 if (dirty & (QSGItemPrivate::OpacityValue | QSGItemPrivate::Visible | QSGItemPrivate::HideReference)) {
1749 qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1750 ? itemPriv->opacity : qreal(0);
1752 if (opacity != 1 && !itemPriv->opacityNode) {
1753 itemPriv->opacityNode = new QSGOpacityNode;
1755 QSGNode *parent = itemPriv->itemNode();
1756 QSGNode *child = itemPriv->clipNode;
1758 child = itemPriv->rootNode;
1760 child = itemPriv->groupNode;
1763 parent->removeChildNode(child);
1764 parent->appendChildNode(itemPriv->opacityNode);
1766 itemPriv->opacityNode->appendChildNode(child);
1768 if (itemPriv->opacityNode)
1769 itemPriv->opacityNode->setOpacity(opacity);
1772 if (dirty & QSGItemPrivate::ContentUpdateMask) {
1774 if (itemPriv->flags & QSGItem::ItemHasContents) {
1775 updatePaintNodeData.transformNode = itemPriv->itemNode();
1776 itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1778 Q_ASSERT(itemPriv->paintNode == 0 ||
1779 itemPriv->paintNode->parent() == 0 ||
1780 itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1782 if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1783 if (itemPriv->childContainerNode()->childCount() == itemPriv->paintNodeIndex)
1784 itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1786 itemPriv->childContainerNode()->insertChildNodeBefore(itemPriv->paintNode, itemPriv->childContainerNode()->childAtIndex(itemPriv->paintNodeIndex));
1788 } else if (itemPriv->paintNode) {
1789 delete itemPriv->paintNode;
1794 // Check consistency.
1795 const QSGNode *nodeChain[] = {
1796 itemPriv->itemNodeInstance,
1797 itemPriv->opacityNode,
1800 itemPriv->groupNode,
1801 itemPriv->paintNode,
1806 while (ip < 5 && nodeChain[ip] == 0)
1811 while (ic < 5 && nodeChain[ic] == 0)
1813 const QSGNode *parent = nodeChain[ip];
1814 const QSGNode *child = nodeChain[ic];
1816 Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1818 Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1819 Q_ASSERT(child->parent() == parent);
1820 bool containsChild = false;
1821 for (int i = 0; i < parent->childCount(); ++i)
1822 containsChild |= (parent->childAtIndex(i) == child);
1823 Q_ASSERT(containsChild);
1829 #ifdef QML_RUNTIME_TESTING
1830 if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1831 QSGFlashNode *flash = new QSGFlashNode();
1832 flash->setRect(item->boundingRect());
1833 itemPriv->childContainerNode()->appendChildNode(flash);
1844 void QSGCanvas::maybeUpdate()
1848 if (d->threadedRendering) {
1849 if (!d->renderThreadAwakened) {
1850 d->renderThreadAwakened = true;
1851 bool locked = d->mutex.tryLock();
1852 if (d->idle && locked) {
1854 qWarning("QSGRenderer: now maybe I should update...");
1861 } else if (!d->animationDriver || !d->animationDriver->isRunning()) {
1867 \fn void QSGEngine::sceneGraphInitialized();
1869 This signal is emitted when the scene graph has been initialized.
1871 This signal will be emitted from the scene graph rendering thread.
1875 Returns the QSGEngine used for this scene.
1877 The engine will only be available once the scene graph has been
1878 initialized. Register for the sceneGraphEngine() signal to get
1879 notification about this.
1882 QSGEngine *QSGCanvas::sceneGraphEngine() const
1884 Q_D(const QSGCanvas);
1885 if (d->context->isReady())
1886 return d->context->engine();