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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickcanvas.h"
43 #include "qquickcanvas_p.h"
45 #include "qquickitem.h"
46 #include "qquickitem_p.h"
48 #include <QtQuick/private/qsgrenderer_p.h>
49 #include <QtQuick/private/qsgtexture_p.h>
50 #include <QtQuick/private/qsgflashnode_p.h>
51 #include <QtQuick/qsgengine.h>
53 #include <private/qquickwindowmanager_p.h>
55 #include <private/qguiapplication_p.h>
56 #include <QtGui/QInputPanel>
58 #include <private/qabstractanimation_p.h>
60 #include <QtGui/qpainter.h>
61 #include <QtGui/qevent.h>
62 #include <QtGui/qmatrix4x4.h>
63 #include <QtCore/qvarlengtharray.h>
64 #include <QtCore/qabstractanimation.h>
65 #include <QtDeclarative/qdeclarativeincubator.h>
67 #include <private/qdeclarativedebugtrace_p.h>
72 void QQuickCanvasPrivate::updateFocusItemTransform()
75 QQuickItem *focus = q->activeFocusItem();
76 if (focus && qApp->inputPanel()->inputItem() == focus)
77 qApp->inputPanel()->setInputItemTransform(QQuickItemPrivate::get(focus)->itemToCanvasTransform());
80 class QQuickCanvasIncubationController : public QObject, public QDeclarativeIncubationController
83 QQuickCanvasIncubationController(QQuickCanvasPrivate *canvas)
84 : m_canvas(canvas), m_eventSent(false) {}
87 virtual bool event(QEvent *e)
89 if (e->type() == QEvent::User) {
90 Q_ASSERT(m_eventSent);
92 bool *amtp = m_canvas->windowManager->allowMainThreadProcessing();
93 while (incubatingObjectCount()) {
98 QCoreApplication::processEvents();
103 return QObject::event(e);
106 virtual void incubatingObjectCountChanged(int count)
108 if (count && !m_eventSent) {
110 QCoreApplication::postEvent(this, new QEvent(QEvent::User));
115 QQuickCanvasPrivate *m_canvas;
125 Prior to being added to a valid canvas items can set and clear focus with no
126 effect. Only once items are added to a canvas (by way of having a parent set that
127 already belongs to a canvas) do the focus rules apply. Focus goes back to
128 having no effect if an item is removed from a canvas.
130 When an item is moved into a new focus scope (either being added to a canvas
131 for the first time, or having its parent changed), if the focus scope already has
132 a scope focused item that takes precedence over the item being added. Otherwise,
133 the focus of the added tree is used. In the case of of a tree of items being
134 added to a canvas for the first time, which may have a conflicted focus state (two
135 or more items in one scope having focus set), the same rule is applied item by item -
136 thus the first item that has focus will get it (assuming the scope doesn't already
137 have a scope focused item), and the other items will have their focus cleared.
141 // #define FOCUS_DEBUG
142 // #define MOUSE_DEBUG
143 // #define TOUCH_DEBUG
144 // #define DIRTY_DEBUG
146 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
151 QQuickRootItem::QQuickRootItem()
155 void QQuickCanvas::exposeEvent(QExposeEvent *)
158 d->windowManager->paint(this);
161 void QQuickCanvas::resizeEvent(QResizeEvent *)
164 d->windowManager->resize(this, size());
167 void QQuickCanvas::showEvent(QShowEvent *)
169 d_func()->windowManager->show(this);
172 void QQuickCanvas::hideEvent(QHideEvent *)
174 d_func()->windowManager->hide(this);
177 void QQuickCanvas::focusOutEvent(QFocusEvent *)
180 d->rootItem->setFocus(false);
183 void QQuickCanvas::focusInEvent(QFocusEvent *)
186 d->rootItem->setFocus(true);
190 void QQuickCanvasPrivate::polishItems()
192 while (!itemsToPolish.isEmpty()) {
193 QSet<QQuickItem *>::Iterator iter = itemsToPolish.begin();
194 QQuickItem *item = *iter;
195 itemsToPolish.erase(iter);
196 QQuickItemPrivate::get(item)->polishScheduled = false;
197 item->updatePolish();
199 updateFocusItemTransform();
202 void forceUpdate(QQuickItem *item)
204 if (item->flags() & QQuickItem::ItemHasContents)
206 QQuickItemPrivate::get(item)->dirty(QQuickItemPrivate::ChildrenUpdateMask);
208 QList <QQuickItem *> items = item->childItems();
209 for (int i=0; i<items.size(); ++i)
210 forceUpdate(items.at(i));
213 void QQuickCanvasPrivate::syncSceneGraph()
216 forceUpdate(rootItem);
218 QSGRootNode *rootNode = new QSGRootNode;
219 rootNode->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
220 renderer = context->createRenderer();
221 renderer->setRootNode(rootNode);
226 // Copy the current state of clearing from canvas into renderer.
227 renderer->setClearColor(clearColor);
228 QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
229 if (clearBeforeRendering)
230 mode |= QSGRenderer::ClearColorBuffer;
231 renderer->setClearMode(mode);
235 void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
238 renderer->setDeviceRect(QRect(QPoint(0, 0), size));
239 renderer->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
240 renderer->setProjectionMatrixToDeviceRect();
242 emit q->beforeRendering();
243 context->renderNextFrame(renderer, renderTarget);
244 emit q->afterRendering();
247 QQuickCanvasPrivate::QQuickCanvasPrivate()
250 , mouseGrabberItem(0)
255 , clearColor(Qt::white)
256 , clearBeforeRendering(true)
258 , incubationController(0)
262 QQuickCanvasPrivate::~QQuickCanvasPrivate()
266 void QQuickCanvasPrivate::init(QQuickCanvas *c)
272 rootItem = new QQuickRootItem;
273 QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
274 rootItemPrivate->canvas = q;
275 rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
277 // In the absence of a focus in event on some platforms assume the window will
278 // be activated immediately and set focus on the rootItem
279 // ### Remove when QTBUG-22415 is resolved.
280 //It is important that this call happens after the rootItem has a canvas..
281 rootItem->setFocus(true);
283 windowManager = QQuickWindowManager::instance();
284 context = windowManager->sceneGraphContext();
285 q->setSurfaceType(QWindow::OpenGLSurface);
286 q->setFormat(context->defaultSurfaceFormat());
288 QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
289 QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
290 QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection);
292 // ### TODO: remove QSGEngine
293 engine = new QSGEngine();
294 engine->setCanvas(q);
297 QDeclarativeListProperty<QObject> QQuickCanvasPrivate::data()
300 return QQuickItemPrivate::get(rootItem)->data();
303 void QQuickCanvasPrivate::initRootItem()
306 q->connect(q, SIGNAL(widthChanged(int)),
307 rootItem, SLOT(setWidth(int)));
308 q->connect(q, SIGNAL(heightChanged(int)),
309 rootItem, SLOT(setHeight(int)));
310 rootItem->setWidth(q->width());
311 rootItem->setHeight(q->height());
314 void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
316 for (int i=0; i<touchPoints.count(); i++) {
317 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
318 touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
319 touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
320 touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
326 Translates the data in \a touchEvent to this canvas. This method leaves the item local positions in
327 \a touchEvent untouched (these are filled in later).
329 void QQuickCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
331 // Q_Q(QQuickCanvas);
333 // touchEvent->setWidget(q); // ### refactor...
335 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
336 for (int i = 0; i < touchPoints.count(); ++i) {
337 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
339 touchPoint.setScreenRect(touchPoint.sceneRect());
340 touchPoint.setStartScreenPos(touchPoint.startScenePos());
341 touchPoint.setLastScreenPos(touchPoint.lastScenePos());
343 touchPoint.setSceneRect(touchPoint.rect());
344 touchPoint.setStartScenePos(touchPoint.startPos());
345 touchPoint.setLastScenePos(touchPoint.lastPos());
347 if (touchPoint.isPrimary())
348 lastMousePosition = touchPoint.pos().toPoint();
350 touchEvent->setTouchPoints(touchPoints);
353 void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
358 Q_ASSERT(scope || item == rootItem);
361 qWarning() << "QQuickCanvasPrivate::setFocusInScope():";
362 qWarning() << " scope:" << (QObject *)scope;
364 qWarning() << " scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
365 qWarning() << " item:" << (QObject *)item;
366 qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
369 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
370 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
372 QQuickItem *oldActiveFocusItem = 0;
373 QQuickItem *newActiveFocusItem = 0;
375 QVarLengthArray<QQuickItem *, 20> changed;
377 // Does this change the active focus?
378 if (item == rootItem || scopePrivate->activeFocus) {
379 oldActiveFocusItem = activeFocusItem;
380 newActiveFocusItem = item;
381 while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
382 newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
384 if (oldActiveFocusItem) {
386 qApp->inputPanel()->reset();
390 QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
391 q->sendEvent(oldActiveFocusItem, &event);
393 QQuickItem *afi = oldActiveFocusItem;
394 while (afi != scope) {
395 if (QQuickItemPrivate::get(afi)->activeFocus) {
396 QQuickItemPrivate::get(afi)->activeFocus = false;
399 afi = afi->parentItem();
404 if (item != rootItem) {
405 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
406 // Correct focus chain in scope
407 if (oldSubFocusItem) {
408 QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
409 while (sfi != scope) {
410 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
411 sfi = sfi->parentItem();
415 scopePrivate->subFocusItem = item;
416 QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
417 while (sfi != scope) {
418 QQuickItemPrivate::get(sfi)->subFocusItem = item;
419 sfi = sfi->parentItem();
423 if (oldSubFocusItem) {
424 QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
425 changed << oldSubFocusItem;
429 if (!(options & DontChangeFocusProperty)) {
430 // if (item != rootItem || QGuiApplication::focusWindow() == q) { // QTBUG-22415
431 itemPrivate->focus = true;
436 if (newActiveFocusItem && rootItem->hasFocus()) {
437 activeFocusItem = newActiveFocusItem;
439 QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
440 changed << newActiveFocusItem;
442 QQuickItem *afi = newActiveFocusItem->parentItem();
443 while (afi && afi != scope) {
444 if (afi->isFocusScope()) {
445 QQuickItemPrivate::get(afi)->activeFocus = true;
448 afi = afi->parentItem();
451 updateInputMethodData();
453 QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
454 q->sendEvent(newActiveFocusItem, &event);
456 updateInputMethodData();
459 if (!changed.isEmpty())
460 notifyFocusChangesRecur(changed.data(), changed.count() - 1);
463 void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
469 Q_ASSERT(scope || item == rootItem);
472 qWarning() << "QQuickCanvasPrivate::clearFocusInScope():";
473 qWarning() << " scope:" << (QObject *)scope;
474 qWarning() << " item:" << (QObject *)item;
475 qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
478 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
480 QQuickItem *oldActiveFocusItem = 0;
481 QQuickItem *newActiveFocusItem = 0;
483 QVarLengthArray<QQuickItem *, 20> changed;
485 Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
487 // Does this change the active focus?
488 if (item == rootItem || scopePrivate->activeFocus) {
489 oldActiveFocusItem = activeFocusItem;
490 newActiveFocusItem = scope;
492 Q_ASSERT(oldActiveFocusItem);
495 qApp->inputPanel()->reset();
499 QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
500 q->sendEvent(oldActiveFocusItem, &event);
502 QQuickItem *afi = oldActiveFocusItem;
503 while (afi != scope) {
504 if (QQuickItemPrivate::get(afi)->activeFocus) {
505 QQuickItemPrivate::get(afi)->activeFocus = false;
508 afi = afi->parentItem();
512 if (item != rootItem) {
513 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
514 // Correct focus chain in scope
515 if (oldSubFocusItem) {
516 QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
517 while (sfi != scope) {
518 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
519 sfi = sfi->parentItem();
522 scopePrivate->subFocusItem = 0;
524 if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
525 QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
526 changed << oldSubFocusItem;
528 } else if (!(options & DontChangeFocusProperty)) {
529 QQuickItemPrivate::get(item)->focus = false;
533 if (newActiveFocusItem) {
534 Q_ASSERT(newActiveFocusItem == scope);
535 activeFocusItem = scope;
537 updateInputMethodData();
539 QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
540 q->sendEvent(newActiveFocusItem, &event);
542 updateInputMethodData();
545 if (!changed.isEmpty())
546 notifyFocusChangesRecur(changed.data(), changed.count() - 1);
549 void QQuickCanvasPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
551 QDeclarativeGuard<QQuickItem> item(*items);
554 notifyFocusChangesRecur(items + 1, remaining - 1);
557 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
559 if (itemPrivate->notifiedFocus != itemPrivate->focus) {
560 itemPrivate->notifiedFocus = itemPrivate->focus;
561 emit item->focusChanged(itemPrivate->focus);
564 if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
565 itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
566 itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
567 emit item->activeFocusChanged(itemPrivate->activeFocus);
572 void QQuickCanvasPrivate::updateInputMethodData()
574 QQuickItem *inputItem = 0;
575 if (activeFocusItem && activeFocusItem->flags() & QQuickItem::ItemAcceptsInputMethod)
576 inputItem = activeFocusItem;
577 qApp->inputPanel()->setInputItem(inputItem);
580 void QQuickCanvasPrivate::dirtyItem(QQuickItem *)
586 void QQuickCanvasPrivate::cleanup(QSGNode *n)
590 Q_ASSERT(!cleanupNodeList.contains(n));
591 cleanupNodeList.append(n);
597 \qmlclass Window QQuickCanvas
598 \inqmlmodule QtQuick.Window 2
599 \brief The Window object creates a new top-level window.
601 The Window object creates a new top-level window for a QtQuick scene. It automatically sets up the
602 window for use with QtQuick 2.0 graphical elements.
607 \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene
609 QQuickCanvas provides the graphical scene management needed to interact with and display
610 a scene of QQuickItems.
612 A QQuickCanvas always has a single invisible root item. To add items to this canvas,
613 reparent the items to the root item or to an existing item in the scene.
615 For easily displaying a scene from a QML file, see \l{QQuickView}.
617 QQuickCanvas::QQuickCanvas(QWindow *parent)
618 : QWindow(*(new QQuickCanvasPrivate), parent)
624 QQuickCanvas::QQuickCanvas(QQuickCanvasPrivate &dd, QWindow *parent)
625 : QWindow(dd, parent)
631 QQuickCanvas::~QQuickCanvas()
635 d->windowManager->canvasDestroyed(this);
637 // ### should we change ~QQuickItem to handle this better?
638 // manually cleanup for the root item (item destructor only handles these when an item is parented)
639 QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
640 rootItemPrivate->removeFromDirtyList();
642 delete d->incubationController; d->incubationController = 0;
644 delete d->rootItem; d->rootItem = 0;
648 Returns the invisible root item of the scene.
650 A QQuickCanvas always has a single invisible root item. To add items to this canvas,
651 reparent the items to the root item or to an existing item in the scene.
653 QQuickItem *QQuickCanvas::rootItem() const
655 Q_D(const QQuickCanvas);
661 Returns the item which currently has active focus.
663 QQuickItem *QQuickCanvas::activeFocusItem() const
665 Q_D(const QQuickCanvas);
667 return d->activeFocusItem;
671 Returns the item which currently has the mouse grab.
673 QQuickItem *QQuickCanvas::mouseGrabberItem() const
675 Q_D(const QQuickCanvas);
677 return d->mouseGrabberItem;
682 \qmlproperty color QtQuick2.Window::Window::color
684 The background color for the window.
686 Setting this property is more efficient than using a separate Rectangle.
689 bool QQuickCanvasPrivate::clearHover()
691 if (hoverItems.isEmpty())
694 QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
696 bool accepted = false;
697 foreach (QQuickItem* item, hoverItems)
698 accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
704 bool QQuickCanvas::event(QEvent *e)
710 case QEvent::TouchBegin:
711 case QEvent::TouchUpdate:
712 case QEvent::TouchEnd:
714 QTouchEvent *touch = static_cast<QTouchEvent *>(e);
715 d->translateTouchEvent(touch);
716 d->deliverTouchEvent(touch);
717 if (!touch->isAccepted())
723 d->lastMousePosition = QPoint();
725 case QEvent::DragEnter:
726 case QEvent::DragLeave:
727 case QEvent::DragMove:
729 d->deliverDragEvent(&d->dragGrabber, e);
731 case QEvent::WindowDeactivate:
732 rootItem()->windowDeactivateEvent();
738 return QWindow::event(e);
741 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
745 if (d->activeFocusItem)
746 sendEvent(d->activeFocusItem, e);
749 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
753 if (d->activeFocusItem)
754 sendEvent(d->activeFocusItem, e);
757 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
761 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
762 if (itemPrivate->opacity == 0.0)
765 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
766 QPointF p = item->mapFromScene(event->windowPos());
767 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
771 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
772 for (int ii = children.count() - 1; ii >= 0; --ii) {
773 QQuickItem *child = children.at(ii);
774 if (!child->isVisible() || !child->isEnabled())
776 if (deliverInitialMousePressEvent(child, event))
780 if (itemPrivate->acceptedMouseButtons & event->button()) {
781 QPointF p = item->mapFromScene(event->windowPos());
782 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
783 QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
784 event->button(), event->buttons(), event->modifiers());
786 mouseGrabberItem = item;
787 q->sendEvent(item, &me);
788 event->setAccepted(me.isAccepted());
791 mouseGrabberItem->ungrabMouse();
792 mouseGrabberItem = 0;
799 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
803 lastMousePosition = event->windowPos();
805 if (!mouseGrabberItem &&
806 event->type() == QEvent::MouseButtonPress &&
807 (event->button() & event->buttons()) == event->buttons()) {
808 return deliverInitialMousePressEvent(rootItem, event);
811 if (mouseGrabberItem) {
812 QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
813 const QTransform &transform = mgPrivate->canvasToItemTransform();
814 QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
815 event->button(), event->buttons(), event->modifiers());
817 q->sendEvent(mouseGrabberItem, &me);
818 event->setAccepted(me.isAccepted());
826 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
831 qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
834 d->deliverMouseEvent(event);
837 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
842 qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
845 if (!d->mouseGrabberItem) {
846 QWindow::mouseReleaseEvent(event);
850 d->deliverMouseEvent(event);
851 d->mouseGrabberItem = 0;
854 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
859 qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
862 if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
863 if (d->deliverInitialMousePressEvent(d->rootItem, event))
870 d->deliverMouseEvent(event);
873 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
874 const QPointF &scenePos, const QPointF &lastScenePos,
875 Qt::KeyboardModifiers modifiers, bool accepted)
878 const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
880 //create copy of event
881 QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
882 hoverEvent.setAccepted(accepted);
884 q->sendEvent(item, &hoverEvent);
886 return hoverEvent.isAccepted();
889 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
894 qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
897 if (!d->mouseGrabberItem) {
898 if (d->lastMousePosition.isNull())
899 d->lastMousePosition = event->windowPos();
900 QPointF last = d->lastMousePosition;
901 d->lastMousePosition = event->windowPos();
903 bool accepted = event->isAccepted();
904 bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
906 //take care of any exits
907 accepted = d->clearHover();
909 event->setAccepted(accepted);
913 d->deliverMouseEvent(event);
916 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
917 Qt::KeyboardModifiers modifiers, bool &accepted)
919 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
920 if (itemPrivate->opacity == 0.0)
923 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
924 QPointF p = item->mapFromScene(scenePos);
925 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
929 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
930 for (int ii = children.count() - 1; ii >= 0; --ii) {
931 QQuickItem *child = children.at(ii);
932 if (!child->isVisible() || !child->isEnabled())
934 if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
938 if (itemPrivate->hoverEnabled) {
939 QPointF p = item->mapFromScene(scenePos);
940 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
941 if (!hoverItems.isEmpty() && hoverItems[0] == item) {
943 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
945 QList<QQuickItem *> itemsToHover;
946 QQuickItem* parent = item;
947 itemsToHover << item;
948 while ((parent = parent->parentItem()))
949 itemsToHover << parent;
951 // Leaving from previous hovered items until we reach the item or one of its ancestors.
952 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
953 sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
954 hoverItems.removeFirst();
957 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
958 // ### Shouldn't we send moves for the parent items as well?
959 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
961 // Enter items that are not entered yet.
963 if (!hoverItems.isEmpty())
964 startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
966 startIdx = itemsToHover.count() - 1;
968 for (int i = startIdx; i >= 0; i--) {
969 QQuickItem *itemToHover = itemsToHover[i];
970 if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
971 hoverItems.prepend(itemToHover);
972 sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
984 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
987 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
988 if (itemPrivate->opacity == 0.0)
991 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
992 QPointF p = item->mapFromScene(event->posF());
993 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
997 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
998 for (int ii = children.count() - 1; ii >= 0; --ii) {
999 QQuickItem *child = children.at(ii);
1000 if (!child->isVisible() || !child->isEnabled())
1002 if (deliverWheelEvent(child, event))
1006 QPointF p = item->mapFromScene(event->posF());
1007 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1008 QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1010 q->sendEvent(item, &wheel);
1011 if (wheel.isAccepted()) {
1020 #ifndef QT_NO_WHEELEVENT
1021 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1025 qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1028 d->deliverWheelEvent(d->rootItem, event);
1030 #endif // QT_NO_WHEELEVENT
1032 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1035 if (event->type() == QEvent::TouchBegin)
1036 qWarning("touchBeginEvent");
1037 else if (event->type() == QEvent::TouchUpdate)
1038 qWarning("touchUpdateEvent");
1039 else if (event->type() == QEvent::TouchEnd)
1040 qWarning("touchEndEvent");
1043 QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1045 if (event->type() == QTouchEvent::TouchBegin) { // all points are new touch points
1046 QSet<int> acceptedNewPoints;
1047 deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1048 if (acceptedNewPoints.count() > 0)
1050 return event->isAccepted();
1053 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1054 QList<QTouchEvent::TouchPoint> newPoints;
1055 QQuickItem *item = 0;
1056 for (int i=0; i<touchPoints.count(); i++) {
1057 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1058 switch (touchPoint.state()) {
1059 case Qt::TouchPointPressed:
1060 newPoints << touchPoint;
1062 case Qt::TouchPointMoved:
1063 case Qt::TouchPointStationary:
1064 case Qt::TouchPointReleased:
1065 if (itemForTouchPointId.contains(touchPoint.id())) {
1066 item = itemForTouchPointId[touchPoint.id()];
1068 updatedPoints[item].append(touchPoint);
1076 if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1077 QSet<int> acceptedNewPoints;
1078 int prevCount = updatedPoints.count();
1079 deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1080 if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1084 if (event->touchPointStates() & Qt::TouchPointReleased) {
1085 for (int i=0; i<touchPoints.count(); i++) {
1086 if (touchPoints[i].state() == Qt::TouchPointReleased)
1087 itemForTouchPointId.remove(touchPoints[i].id());
1091 return event->isAccepted();
1094 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1097 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1099 if (itemPrivate->opacity == 0.0)
1102 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1103 QRectF bounds(0, 0, item->width(), item->height());
1104 for (int i=0; i<newPoints.count(); i++) {
1105 QPointF p = item->mapFromScene(newPoints[i].scenePos());
1106 if (!bounds.contains(p))
1111 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1112 for (int ii = children.count() - 1; ii >= 0; --ii) {
1113 QQuickItem *child = children.at(ii);
1114 if (!child->isEnabled())
1116 if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1120 QList<QTouchEvent::TouchPoint> matchingPoints;
1121 if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1122 QRectF bounds(0, 0, item->width(), item->height());
1123 for (int i=0; i<newPoints.count(); i++) {
1124 if (acceptedNewPoints->contains(newPoints[i].id()))
1126 QPointF p = item->mapFromScene(newPoints[i].scenePos());
1127 if (bounds.contains(p))
1128 matchingPoints << newPoints[i];
1132 if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1133 QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1134 eventPoints.append(matchingPoints);
1135 transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1137 Qt::TouchPointStates eventStates;
1138 for (int i=0; i<eventPoints.count(); i++)
1139 eventStates |= eventPoints[i].state();
1140 // if all points have the same state, set the event type accordingly
1141 QEvent::Type eventType;
1142 switch (eventStates) {
1143 case Qt::TouchPointPressed:
1144 eventType = QEvent::TouchBegin;
1146 case Qt::TouchPointReleased:
1147 eventType = QEvent::TouchEnd;
1150 eventType = QEvent::TouchUpdate;
1154 if (eventStates != Qt::TouchPointStationary) {
1155 QTouchEvent touchEvent(eventType);
1156 touchEvent.setWindow(event->window());
1157 touchEvent.setTarget(item);
1158 touchEvent.setDevice(event->device());
1159 touchEvent.setModifiers(event->modifiers());
1160 touchEvent.setTouchPointStates(eventStates);
1161 touchEvent.setTouchPoints(eventPoints);
1162 touchEvent.setTimestamp(event->timestamp());
1164 touchEvent.accept();
1165 q->sendEvent(item, &touchEvent);
1167 if (touchEvent.isAccepted()) {
1168 for (int i=0; i<matchingPoints.count(); i++) {
1169 itemForTouchPointId[matchingPoints[i].id()] = item;
1170 acceptedNewPoints->insert(matchingPoints[i].id());
1176 updatedPoints->remove(item);
1177 if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1183 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1186 grabber->resetTarget();
1187 QQuickDragGrabber::iterator grabItem = grabber->begin();
1188 if (grabItem != grabber->end()) {
1189 Q_ASSERT(event->type() != QEvent::DragEnter);
1190 if (event->type() == QEvent::Drop) {
1191 QDropEvent *e = static_cast<QDropEvent *>(event);
1192 for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1193 QPointF p = (**grabItem)->mapFromScene(e->pos());
1194 QDropEvent translatedEvent(
1196 e->possibleActions(),
1199 e->keyboardModifiers());
1200 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1201 q->sendEvent(**grabItem, &translatedEvent);
1202 e->setAccepted(translatedEvent.isAccepted());
1203 e->setDropAction(translatedEvent.dropAction());
1204 grabber->setTarget(**grabItem);
1207 if (event->type() != QEvent::DragMove) { // Either an accepted drop or a leave.
1208 QDragLeaveEvent leaveEvent;
1209 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1210 q->sendEvent(**grabItem, &leaveEvent);
1212 } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1213 QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1214 if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1215 moveEvent->setAccepted(true);
1216 for (++grabItem; grabItem != grabber->end();) {
1217 QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1218 if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1219 QDragMoveEvent translatedEvent(
1221 moveEvent->possibleActions(),
1222 moveEvent->mimeData(),
1223 moveEvent->mouseButtons(),
1224 moveEvent->keyboardModifiers());
1225 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1226 q->sendEvent(**grabItem, &translatedEvent);
1229 QDragLeaveEvent leaveEvent;
1230 q->sendEvent(**grabItem, &leaveEvent);
1231 grabItem = grabber->release(grabItem);
1236 QDragLeaveEvent leaveEvent;
1237 q->sendEvent(**grabItem, &leaveEvent);
1241 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1242 QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1243 QDragEnterEvent enterEvent(
1245 e->possibleActions(),
1248 e->keyboardModifiers());
1249 QQuickDropEventEx::copyActions(&enterEvent, *e);
1250 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1254 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1257 bool accepted = false;
1258 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1259 if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
1262 QPointF p = item->mapFromScene(event->pos());
1263 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1264 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1265 QDragMoveEvent translatedEvent(
1267 event->possibleActions(),
1269 event->mouseButtons(),
1270 event->keyboardModifiers(),
1272 QQuickDropEventEx::copyActions(&translatedEvent, *event);
1273 q->sendEvent(item, &translatedEvent);
1274 if (event->type() == QEvent::DragEnter) {
1275 if (translatedEvent.isAccepted()) {
1276 grabber->grab(item);
1283 } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1287 QDragEnterEvent enterEvent(
1289 event->possibleActions(),
1291 event->mouseButtons(),
1292 event->keyboardModifiers());
1293 QQuickDropEventEx::copyActions(&enterEvent, *event);
1294 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1295 for (int ii = children.count() - 1; ii >= 0; --ii) {
1296 if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1303 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1308 QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1309 if (targetPrivate->filtersChildMouseEvents)
1310 if (target->childMouseEventFilter(item, event))
1313 if (sendFilteredMouseEvent(target->parentItem(), item, event))
1320 Propagates an event to a QQuickItem on the canvas
1322 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1327 qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1333 switch (e->type()) {
1334 case QEvent::KeyPress:
1335 case QEvent::KeyRelease:
1337 QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1338 while (!e->isAccepted() && (item = item->parentItem())) {
1340 QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1343 case QEvent::FocusIn:
1344 case QEvent::FocusOut:
1345 QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1347 case QEvent::MouseButtonPress:
1348 case QEvent::MouseButtonRelease:
1349 case QEvent::MouseButtonDblClick:
1350 case QEvent::MouseMove:
1351 // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
1352 if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1354 QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1358 QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1360 case QEvent::HoverEnter:
1361 case QEvent::HoverLeave:
1362 case QEvent::HoverMove:
1363 QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1365 case QEvent::TouchBegin:
1366 case QEvent::TouchUpdate:
1367 case QEvent::TouchEnd:
1368 // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
1369 if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1371 QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1374 case QEvent::DragEnter:
1375 case QEvent::DragMove:
1376 case QEvent::DragLeave:
1378 QQuickItemPrivate::get(item)->deliverDragEvent(e);
1387 void QQuickCanvasPrivate::cleanupNodes()
1389 for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1390 delete cleanupNodeList.at(ii);
1391 cleanupNodeList.clear();
1394 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1396 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1397 if (p->itemNodeInstance) {
1398 delete p->itemNodeInstance;
1399 p->itemNodeInstance = 0;
1406 for (int ii = 0; ii < p->childItems.count(); ++ii)
1407 cleanupNodesOnShutdown(p->childItems.at(ii));
1410 // This must be called from the render thread, with the main thread frozen
1411 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1415 cleanupNodesOnShutdown(rootItem);
1418 void QQuickCanvasPrivate::updateDirtyNodes()
1421 qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1426 QQuickItem *updateList = dirtyItemList;
1428 if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1430 while (updateList) {
1431 QQuickItem *item = updateList;
1432 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1433 itemPriv->removeFromDirtyList();
1436 qWarning() << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1438 updateDirtyNode(item);
1442 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1444 #ifdef QML_RUNTIME_TESTING
1445 bool didFlash = false;
1448 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1449 quint32 dirty = itemPriv->dirtyAttributes;
1450 itemPriv->dirtyAttributes = 0;
1452 if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1453 (dirty & QQuickItemPrivate::Size && itemPriv->origin != QQuickItem::TopLeft &&
1454 (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1458 if (itemPriv->x != 0. || itemPriv->y != 0.)
1459 matrix.translate(itemPriv->x, itemPriv->y);
1461 for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1462 itemPriv->transforms.at(ii)->applyTo(&matrix);
1464 if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1465 QPointF origin = item->transformOriginPoint();
1466 matrix.translate(origin.x(), origin.y());
1467 if (itemPriv->scale != 1.)
1468 matrix.scale(itemPriv->scale, itemPriv->scale);
1469 if (itemPriv->rotation != 0.)
1470 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1471 matrix.translate(-origin.x(), -origin.y());
1474 itemPriv->itemNode()->setMatrix(matrix);
1477 bool clipEffectivelyChanged = dirty & QQuickItemPrivate::Clip &&
1478 ((item->clip() == false) != (itemPriv->clipNode == 0));
1479 bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
1480 ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1482 if (clipEffectivelyChanged) {
1483 QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1484 QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1487 Q_ASSERT(itemPriv->clipNode == 0);
1488 itemPriv->clipNode = new QQuickDefaultClipNode(item->boundingRect());
1489 itemPriv->clipNode->update();
1492 parent->removeChildNode(child);
1493 parent->appendChildNode(itemPriv->clipNode);
1495 itemPriv->clipNode->appendChildNode(child);
1498 Q_ASSERT(itemPriv->clipNode != 0);
1499 parent->removeChildNode(itemPriv->clipNode);
1501 itemPriv->clipNode->removeChildNode(child);
1502 delete itemPriv->clipNode;
1503 itemPriv->clipNode = 0;
1505 parent->appendChildNode(child);
1509 if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1510 itemPriv->childContainerNode()->removeAllChildNodes();
1512 if (effectRefEffectivelyChanged) {
1513 QSGNode *parent = itemPriv->clipNode;
1515 parent = itemPriv->opacityNode;
1517 parent = itemPriv->itemNode();
1518 QSGNode *child = itemPriv->groupNode;
1520 if (itemPriv->effectRefCount) {
1521 Q_ASSERT(itemPriv->rootNode == 0);
1522 itemPriv->rootNode = new QSGRootNode;
1525 parent->removeChildNode(child);
1526 parent->appendChildNode(itemPriv->rootNode);
1528 itemPriv->rootNode->appendChildNode(child);
1530 Q_ASSERT(itemPriv->rootNode != 0);
1531 parent->removeChildNode(itemPriv->rootNode);
1533 itemPriv->rootNode->removeChildNode(child);
1534 delete itemPriv->rootNode;
1535 itemPriv->rootNode = 0;
1537 parent->appendChildNode(child);
1541 if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1542 QSGNode *groupNode = itemPriv->groupNode;
1544 groupNode->removeAllChildNodes();
1546 QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1549 for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1550 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1551 if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1553 if (childPrivate->itemNode()->parent())
1554 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1556 itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1558 itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1560 if (itemPriv->paintNode)
1561 itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1563 for (; ii < orderedChildren.count(); ++ii) {
1564 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1565 if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1567 if (childPrivate->itemNode()->parent())
1568 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1570 itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1574 if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode) {
1575 itemPriv->clipNode->setRect(item->boundingRect());
1576 itemPriv->clipNode->update();
1579 if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
1580 qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1581 ? itemPriv->opacity : qreal(0);
1583 if (opacity != 1 && !itemPriv->opacityNode) {
1584 itemPriv->opacityNode = new QSGOpacityNode;
1586 QSGNode *parent = itemPriv->itemNode();
1587 QSGNode *child = itemPriv->clipNode;
1589 child = itemPriv->rootNode;
1591 child = itemPriv->groupNode;
1594 parent->removeChildNode(child);
1595 parent->appendChildNode(itemPriv->opacityNode);
1597 itemPriv->opacityNode->appendChildNode(child);
1599 if (itemPriv->opacityNode)
1600 itemPriv->opacityNode->setOpacity(opacity);
1603 if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1605 if (itemPriv->flags & QQuickItem::ItemHasContents) {
1606 updatePaintNodeData.transformNode = itemPriv->itemNode();
1607 itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1609 Q_ASSERT(itemPriv->paintNode == 0 ||
1610 itemPriv->paintNode->parent() == 0 ||
1611 itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1613 if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1614 if (itemPriv->beforePaintNode)
1615 itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1617 itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1619 } else if (itemPriv->paintNode) {
1620 delete itemPriv->paintNode;
1621 itemPriv->paintNode = 0;
1625 if ((dirty & QQuickItemPrivate::PerformanceHints) && itemPriv->groupNode) {
1626 itemPriv->groupNode->setFlag(QSGNode::ChildrenDoNotOverlap, itemPriv->childrenDoNotOverlap);
1627 itemPriv->groupNode->setFlag(QSGNode::StaticSubtreeGeometry, itemPriv->staticSubtreeGeometry);
1631 // Check consistency.
1632 const QSGNode *nodeChain[] = {
1633 itemPriv->itemNodeInstance,
1634 itemPriv->opacityNode,
1637 itemPriv->groupNode,
1638 itemPriv->paintNode,
1643 while (ip < 5 && nodeChain[ip] == 0)
1648 while (ic < 5 && nodeChain[ic] == 0)
1650 const QSGNode *parent = nodeChain[ip];
1651 const QSGNode *child = nodeChain[ic];
1653 Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1655 Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1656 Q_ASSERT(child->parent() == parent);
1657 bool containsChild = false;
1658 for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1659 containsChild |= (n == child);
1660 Q_ASSERT(containsChild);
1666 #ifdef QML_RUNTIME_TESTING
1667 if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1668 QSGFlashNode *flash = new QSGFlashNode();
1669 flash->setRect(item->boundingRect());
1670 itemPriv->childContainerNode()->appendChildNode(flash);
1681 void QQuickCanvas::maybeUpdate()
1684 d->windowManager->maybeUpdate(this);
1687 void QQuickCanvas::cleanupSceneGraph()
1694 delete d->renderer->rootNode();
1701 Returns the opengl context used for rendering.
1703 If the scene graph is not ready, this function will return 0.
1705 \sa sceneGraphInitialized(), sceneGraphInvalidated()
1708 QOpenGLContext *QQuickCanvas::openglContext() const
1710 Q_D(const QQuickCanvas);
1711 if (d->context->isReady())
1712 return d->context->glContext();
1718 \fn void QSGContext::sceneGraphInitialized()
1720 This signal is emitted when the scene graph has been initialized.
1722 This signal will be emitted from the scene graph rendering thread.
1728 \fn void QSGContext::sceneGraphInvalidated()
1730 This signal is emitted when the scene graph has been invalidated.
1732 This signal implies that the opengl rendering context used
1733 has been invalidated and all user resources tied to that context
1736 This signal will be emitted from the scene graph rendering thread.
1740 Returns the QSGEngine used for this scene.
1742 The engine will only be available once the scene graph has been
1743 initialized. Register for the sceneGraphEngine() signal to get
1744 notification about this.
1749 QSGEngine *QQuickCanvas::sceneGraphEngine() const
1751 Q_D(const QQuickCanvas);
1752 qWarning("QQuickCanvas::sceneGraphEngine() is deprecated, use members of QQuickCanvas instead");
1753 if (d->context && d->context->isReady())
1761 Sets the render target for this canvas to be \a fbo.
1763 The specified fbo must be created in the context of the canvas
1764 or one that shares with it.
1767 This function can only be called from the thread doing
1771 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1774 if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1775 qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1779 d->renderTarget = fbo;
1785 Returns the render target for this canvas.
1787 The default is to render to the surface of the canvas, in which
1788 case the render target is 0.
1790 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
1792 Q_D(const QQuickCanvas);
1793 return d->renderTarget;
1798 Grabs the contents of the framebuffer and returns it as an image.
1800 This function might not work if the view is not visible.
1802 \warning Calling this function will cause performance problems.
1804 \warning This function can only be called from the GUI thread.
1806 QImage QQuickCanvas::grabFrameBuffer()
1809 return d->windowManager->grab(this);
1813 Returns an incubation controller that splices incubation between frames
1814 for this canvas. QQuickView automatically installs this controller for you,
1815 otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController}
1817 The controller is owned by the canvas and will be destroyed when the canvas
1820 QDeclarativeIncubationController *QQuickCanvas::incubationController() const
1822 Q_D(const QQuickCanvas);
1824 if (!d->incubationController)
1825 d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
1826 return d->incubationController;
1832 \enum QQuickCanvas::CreateTextureOption
1834 The CreateTextureOption enums are used to customize a texture is wrapped.
1836 \value TextureHasAlphaChannel The texture has an alpha channel and should
1837 be drawn using blending.
1839 \value TextureHasMipmaps The texture has mipmaps and can be drawn with
1842 \value TextureOwnsGLTexture The texture object owns the texture id and
1843 will delete the GL texture when the texture object is deleted.
1847 \fn void QQuickCanvas::beforeRendering()
1849 This signal is emitted before the scene starts rendering.
1851 Combined with the modes for clearing the background, this option
1852 can be used to paint using raw GL under QML content.
1854 The GL context used for rendering the scene graph will be bound
1857 Since this signal is emitted from the scene graph rendering thread, the receiver should
1858 be on the scene graph thread or the connection should be Qt::DirectConnection.
1863 \fn void QQuickCanvas::afterRendering()
1865 This signal is emitted after the scene has completed rendering, before swapbuffers is called.
1867 This signal can be used to paint using raw GL on top of QML content,
1868 or to do screen scraping of the current frame buffer.
1870 The GL context used for rendering the scene graph will be bound at this point.
1872 Since this signal is emitted from the scene graph rendering thread, the receiver should
1873 be on the scene graph thread or the connection should be Qt::DirectConnection.
1879 Sets weither the scene graph rendering of QML should clear the color buffer
1880 before it starts rendering to \a enbled.
1882 By disabling clearing of the color buffer, it is possible to do GL painting
1883 under the scene graph.
1885 The color buffer is cleared by default.
1887 \sa beforeRendering()
1890 void QQuickCanvas::setClearBeforeRendering(bool enabled)
1893 d->clearBeforeRendering = enabled;
1899 Returns weither clearing of the color buffer is done before rendering or not.
1902 bool QQuickCanvas::clearBeforeRendering() const
1904 Q_D(const QQuickCanvas);
1905 return d->clearBeforeRendering;
1911 Creates a new QSGTexture from the supplied \a image. If the image has an
1912 alpha channel, the corresponding texture will have an alpha channel.
1914 The caller of the function is responsible for deleting the returned texture.
1915 The actual GL texture will be deleted when the texture object is deleted.
1917 \warning This function will return 0 if the scene graph has not yet been
1920 This function can be called both from the GUI thread and the rendering thread.
1922 \sa sceneGraphInitialized()
1925 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
1927 Q_D(const QQuickCanvas);
1928 if (d->context && d->context->isReady())
1929 return d->context->createTexture(image);
1937 Creates a new QSGTexture object from an existing GL texture \a id.
1939 The caller of the function is responsible for deleting the returned texture.
1941 Use \a options to customize the texture attributes.
1943 \warning This function will return 0 if the scenegraph has not yet been
1946 \sa sceneGraphInitialized()
1948 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
1950 Q_D(const QQuickCanvas);
1951 if (d->context && d->context->isReady()) {
1952 QSGPlainTexture *texture = new QSGPlainTexture();
1953 texture->setTextureId(id);
1954 texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
1955 texture->setHasMipmaps(options & TextureHasMipmaps);
1956 texture->setOwnsTexture(options & TextureOwnsGLTexture);
1957 texture->setTextureSize(size);
1965 Sets the color used to clear the opengl context to \a color.
1967 Setting the clear color has no effect when clearing is disabled.
1969 \sa setClearBeforeRendering()
1972 void QQuickCanvas::setClearColor(const QColor &color)
1975 if (color == d->clearColor)
1978 d->clearColor = color;
1979 emit clearColorChanged(color);
1985 Returns the color used to clear the opengl context.
1988 QColor QQuickCanvas::clearColor() const
1990 return d_func()->clearColor;
1995 #include "moc_qquickcanvas.cpp"