1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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;
119 QAccessibleInterface *QQuickCanvas::accessibleRoot() const
121 return QAccessible::queryAccessibleInterface(const_cast<QQuickCanvas*>(this));
129 Prior to being added to a valid canvas items can set and clear focus with no
130 effect. Only once items are added to a canvas (by way of having a parent set that
131 already belongs to a canvas) do the focus rules apply. Focus goes back to
132 having no effect if an item is removed from a canvas.
134 When an item is moved into a new focus scope (either being added to a canvas
135 for the first time, or having its parent changed), if the focus scope already has
136 a scope focused item that takes precedence over the item being added. Otherwise,
137 the focus of the added tree is used. In the case of of a tree of items being
138 added to a canvas for the first time, which may have a conflicted focus state (two
139 or more items in one scope having focus set), the same rule is applied item by item -
140 thus the first item that has focus will get it (assuming the scope doesn't already
141 have a scope focused item), and the other items will have their focus cleared.
145 // #define FOCUS_DEBUG
146 // #define MOUSE_DEBUG
147 // #define TOUCH_DEBUG
148 // #define DIRTY_DEBUG
150 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
155 QQuickRootItem::QQuickRootItem()
159 void QQuickCanvas::exposeEvent(QExposeEvent *)
162 d->windowManager->paint(this);
165 void QQuickCanvas::resizeEvent(QResizeEvent *)
168 d->windowManager->resize(this, size());
171 void QQuickCanvas::showEvent(QShowEvent *)
173 d_func()->windowManager->show(this);
176 void QQuickCanvas::hideEvent(QHideEvent *)
178 d_func()->windowManager->hide(this);
181 void QQuickCanvas::focusOutEvent(QFocusEvent *)
184 d->rootItem->setFocus(false);
187 void QQuickCanvas::focusInEvent(QFocusEvent *)
190 d->rootItem->setFocus(true);
194 void QQuickCanvasPrivate::polishItems()
196 while (!itemsToPolish.isEmpty()) {
197 QSet<QQuickItem *>::Iterator iter = itemsToPolish.begin();
198 QQuickItem *item = *iter;
199 itemsToPolish.erase(iter);
200 QQuickItemPrivate::get(item)->polishScheduled = false;
201 item->updatePolish();
203 updateFocusItemTransform();
206 void forceUpdate(QQuickItem *item)
208 if (item->flags() & QQuickItem::ItemHasContents)
210 QQuickItemPrivate::get(item)->dirty(QQuickItemPrivate::ChildrenUpdateMask);
212 QList <QQuickItem *> items = item->childItems();
213 for (int i=0; i<items.size(); ++i)
214 forceUpdate(items.at(i));
217 void QQuickCanvasPrivate::syncSceneGraph()
220 forceUpdate(rootItem);
222 QSGRootNode *rootNode = new QSGRootNode;
223 rootNode->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
224 renderer = context->createRenderer();
225 renderer->setRootNode(rootNode);
230 // Copy the current state of clearing from canvas into renderer.
231 renderer->setClearColor(clearColor);
232 QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
233 if (clearBeforeRendering)
234 mode |= QSGRenderer::ClearColorBuffer;
235 renderer->setClearMode(mode);
239 void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
242 renderer->setDeviceRect(QRect(QPoint(0, 0), size));
243 renderer->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
244 renderer->setProjectionMatrixToDeviceRect();
246 emit q->beforeRendering();
247 context->renderNextFrame(renderer, renderTarget);
248 emit q->afterRendering();
251 QQuickCanvasPrivate::QQuickCanvasPrivate()
254 , mouseGrabberItem(0)
259 , clearColor(Qt::white)
260 , clearBeforeRendering(true)
262 , incubationController(0)
266 QQuickCanvasPrivate::~QQuickCanvasPrivate()
270 void QQuickCanvasPrivate::init(QQuickCanvas *c)
276 rootItem = new QQuickRootItem;
277 QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
278 rootItemPrivate->canvas = q;
279 rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
281 // In the absence of a focus in event on some platforms assume the window will
282 // be activated immediately and set focus on the rootItem
283 // ### Remove when QTBUG-22415 is resolved.
284 //It is important that this call happens after the rootItem has a canvas..
285 rootItem->setFocus(true);
287 windowManager = QQuickWindowManager::instance();
288 context = windowManager->sceneGraphContext();
289 q->setSurfaceType(QWindow::OpenGLSurface);
290 q->setFormat(context->defaultSurfaceFormat());
292 QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
293 QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
294 QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection);
296 // ### TODO: remove QSGEngine
297 engine = new QSGEngine();
298 engine->setCanvas(q);
301 QDeclarativeListProperty<QObject> QQuickCanvasPrivate::data()
304 return QQuickItemPrivate::get(rootItem)->data();
307 void QQuickCanvasPrivate::initRootItem()
310 q->connect(q, SIGNAL(widthChanged(int)),
311 rootItem, SLOT(setWidth(int)));
312 q->connect(q, SIGNAL(heightChanged(int)),
313 rootItem, SLOT(setHeight(int)));
314 rootItem->setWidth(q->width());
315 rootItem->setHeight(q->height());
318 void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
320 for (int i=0; i<touchPoints.count(); i++) {
321 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
322 touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
323 touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
324 touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
330 Translates the data in \a touchEvent to this canvas. This method leaves the item local positions in
331 \a touchEvent untouched (these are filled in later).
333 void QQuickCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
335 // Q_Q(QQuickCanvas);
337 // touchEvent->setWidget(q); // ### refactor...
339 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
340 for (int i = 0; i < touchPoints.count(); ++i) {
341 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
343 touchPoint.setScreenRect(touchPoint.sceneRect());
344 touchPoint.setStartScreenPos(touchPoint.startScenePos());
345 touchPoint.setLastScreenPos(touchPoint.lastScenePos());
347 touchPoint.setSceneRect(touchPoint.rect());
348 touchPoint.setStartScenePos(touchPoint.startPos());
349 touchPoint.setLastScenePos(touchPoint.lastPos());
352 lastMousePosition = touchPoint.pos().toPoint();
354 touchEvent->setTouchPoints(touchPoints);
357 void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
362 Q_ASSERT(scope || item == rootItem);
365 qWarning() << "QQuickCanvasPrivate::setFocusInScope():";
366 qWarning() << " scope:" << (QObject *)scope;
368 qWarning() << " scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
369 qWarning() << " item:" << (QObject *)item;
370 qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
373 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
374 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
376 QQuickItem *oldActiveFocusItem = 0;
377 QQuickItem *newActiveFocusItem = 0;
379 QVarLengthArray<QQuickItem *, 20> changed;
381 // Does this change the active focus?
382 if (item == rootItem || scopePrivate->activeFocus) {
383 oldActiveFocusItem = activeFocusItem;
384 newActiveFocusItem = item;
385 while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
386 newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
388 if (oldActiveFocusItem) {
390 qApp->inputPanel()->reset();
394 QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
395 q->sendEvent(oldActiveFocusItem, &event);
397 QQuickItem *afi = oldActiveFocusItem;
398 while (afi != scope) {
399 if (QQuickItemPrivate::get(afi)->activeFocus) {
400 QQuickItemPrivate::get(afi)->activeFocus = false;
403 afi = afi->parentItem();
408 if (item != rootItem) {
409 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
410 // Correct focus chain in scope
411 if (oldSubFocusItem) {
412 QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
413 while (sfi != scope) {
414 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
415 sfi = sfi->parentItem();
419 scopePrivate->subFocusItem = item;
420 QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
421 while (sfi != scope) {
422 QQuickItemPrivate::get(sfi)->subFocusItem = item;
423 sfi = sfi->parentItem();
427 if (oldSubFocusItem) {
428 QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
429 changed << oldSubFocusItem;
433 if (!(options & DontChangeFocusProperty)) {
434 // if (item != rootItem || QGuiApplication::focusWindow() == q) { // QTBUG-22415
435 itemPrivate->focus = true;
440 if (newActiveFocusItem && rootItem->hasFocus()) {
441 activeFocusItem = newActiveFocusItem;
443 QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
444 changed << newActiveFocusItem;
446 QQuickItem *afi = newActiveFocusItem->parentItem();
447 while (afi && afi != scope) {
448 if (afi->isFocusScope()) {
449 QQuickItemPrivate::get(afi)->activeFocus = true;
452 afi = afi->parentItem();
455 updateInputMethodData();
457 QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
458 q->sendEvent(newActiveFocusItem, &event);
460 updateInputMethodData();
463 if (!changed.isEmpty())
464 notifyFocusChangesRecur(changed.data(), changed.count() - 1);
467 void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
473 Q_ASSERT(scope || item == rootItem);
476 qWarning() << "QQuickCanvasPrivate::clearFocusInScope():";
477 qWarning() << " scope:" << (QObject *)scope;
478 qWarning() << " item:" << (QObject *)item;
479 qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
482 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
484 QQuickItem *oldActiveFocusItem = 0;
485 QQuickItem *newActiveFocusItem = 0;
487 QVarLengthArray<QQuickItem *, 20> changed;
489 Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
491 // Does this change the active focus?
492 if (item == rootItem || scopePrivate->activeFocus) {
493 oldActiveFocusItem = activeFocusItem;
494 newActiveFocusItem = scope;
496 Q_ASSERT(oldActiveFocusItem);
499 qApp->inputPanel()->reset();
503 QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
504 q->sendEvent(oldActiveFocusItem, &event);
506 QQuickItem *afi = oldActiveFocusItem;
507 while (afi != scope) {
508 if (QQuickItemPrivate::get(afi)->activeFocus) {
509 QQuickItemPrivate::get(afi)->activeFocus = false;
512 afi = afi->parentItem();
516 if (item != rootItem) {
517 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
518 // Correct focus chain in scope
519 if (oldSubFocusItem) {
520 QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
521 while (sfi != scope) {
522 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
523 sfi = sfi->parentItem();
526 scopePrivate->subFocusItem = 0;
528 if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
529 QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
530 changed << oldSubFocusItem;
532 } else if (!(options & DontChangeFocusProperty)) {
533 QQuickItemPrivate::get(item)->focus = false;
537 if (newActiveFocusItem) {
538 Q_ASSERT(newActiveFocusItem == scope);
539 activeFocusItem = scope;
541 updateInputMethodData();
543 QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
544 q->sendEvent(newActiveFocusItem, &event);
546 updateInputMethodData();
549 if (!changed.isEmpty())
550 notifyFocusChangesRecur(changed.data(), changed.count() - 1);
553 void QQuickCanvasPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
555 QDeclarativeGuard<QQuickItem> item(*items);
558 notifyFocusChangesRecur(items + 1, remaining - 1);
561 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
563 if (itemPrivate->notifiedFocus != itemPrivate->focus) {
564 itemPrivate->notifiedFocus = itemPrivate->focus;
565 emit item->focusChanged(itemPrivate->focus);
568 if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
569 itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
570 itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
571 emit item->activeFocusChanged(itemPrivate->activeFocus);
576 void QQuickCanvasPrivate::updateInputMethodData()
578 QQuickItem *inputItem = 0;
579 if (activeFocusItem && activeFocusItem->flags() & QQuickItem::ItemAcceptsInputMethod)
580 inputItem = activeFocusItem;
581 qApp->inputPanel()->setInputItem(inputItem);
584 void QQuickCanvasPrivate::dirtyItem(QQuickItem *)
590 void QQuickCanvasPrivate::cleanup(QSGNode *n)
594 Q_ASSERT(!cleanupNodeList.contains(n));
595 cleanupNodeList.append(n);
601 \qmlclass Window QQuickCanvas
602 \inqmlmodule QtQuick.Window 2
603 \brief The Window object creates a new top-level window.
605 The Window object creates a new top-level window for a QtQuick scene. It automatically sets up the
606 window for use with QtQuick 2.0 graphical elements.
611 \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene
613 QQuickCanvas provides the graphical scene management needed to interact with and display
614 a scene of QQuickItems.
616 A QQuickCanvas always has a single invisible root item. To add items to this canvas,
617 reparent the items to the root item or to an existing item in the scene.
619 For easily displaying a scene from a QML file, see \l{QQuickView}.
621 QQuickCanvas::QQuickCanvas(QWindow *parent)
622 : QWindow(*(new QQuickCanvasPrivate), parent)
628 QQuickCanvas::QQuickCanvas(QQuickCanvasPrivate &dd, QWindow *parent)
629 : QWindow(dd, parent)
635 QQuickCanvas::~QQuickCanvas()
639 d->windowManager->canvasDestroyed(this);
641 // ### should we change ~QQuickItem to handle this better?
642 // manually cleanup for the root item (item destructor only handles these when an item is parented)
643 QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
644 rootItemPrivate->removeFromDirtyList();
646 delete d->incubationController; d->incubationController = 0;
648 delete d->rootItem; d->rootItem = 0;
652 Returns the invisible root item of the scene.
654 A QQuickCanvas always has a single invisible root item. To add items to this canvas,
655 reparent the items to the root item or to an existing item in the scene.
657 QQuickItem *QQuickCanvas::rootItem() const
659 Q_D(const QQuickCanvas);
665 Returns the item which currently has active focus.
667 QQuickItem *QQuickCanvas::activeFocusItem() const
669 Q_D(const QQuickCanvas);
671 return d->activeFocusItem;
674 QObject *QQuickCanvas::focusObject() const
676 Q_D(const QQuickCanvas);
678 if (d->activeFocusItem)
679 return d->activeFocusItem;
680 return const_cast<QQuickCanvas*>(this);
685 Returns the item which currently has the mouse grab.
687 QQuickItem *QQuickCanvas::mouseGrabberItem() const
689 Q_D(const QQuickCanvas);
691 return d->mouseGrabberItem;
696 \qmlproperty color QtQuick2.Window::Window::color
698 The background color for the window.
700 Setting this property is more efficient than using a separate Rectangle.
703 bool QQuickCanvasPrivate::clearHover()
705 if (hoverItems.isEmpty())
708 QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
710 bool accepted = false;
711 foreach (QQuickItem* item, hoverItems)
712 accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
718 bool QQuickCanvas::event(QEvent *e)
724 case QEvent::TouchBegin:
725 case QEvent::TouchUpdate:
726 case QEvent::TouchEnd:
728 QTouchEvent *touch = static_cast<QTouchEvent *>(e);
729 d->translateTouchEvent(touch);
730 d->deliverTouchEvent(touch);
732 return touch->isAccepted();
736 d->lastMousePosition = QPoint();
738 case QEvent::DragEnter:
739 case QEvent::DragLeave:
740 case QEvent::DragMove:
742 d->deliverDragEvent(&d->dragGrabber, e);
744 case QEvent::WindowDeactivate:
745 rootItem()->windowDeactivateEvent();
751 return QWindow::event(e);
754 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
758 if (d->activeFocusItem)
759 sendEvent(d->activeFocusItem, e);
762 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
766 if (d->activeFocusItem)
767 sendEvent(d->activeFocusItem, e);
770 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
774 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
775 if (itemPrivate->opacity == 0.0)
778 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
779 QPointF p = item->mapFromScene(event->windowPos());
780 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
784 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
785 for (int ii = children.count() - 1; ii >= 0; --ii) {
786 QQuickItem *child = children.at(ii);
787 if (!child->isVisible() || !child->isEnabled())
789 if (deliverInitialMousePressEvent(child, event))
793 if (itemPrivate->acceptedMouseButtons & event->button()) {
794 QPointF p = item->mapFromScene(event->windowPos());
795 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
796 QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
797 event->button(), event->buttons(), event->modifiers());
799 mouseGrabberItem = item;
800 q->sendEvent(item, &me);
801 event->setAccepted(me.isAccepted());
804 mouseGrabberItem->ungrabMouse();
805 mouseGrabberItem = 0;
812 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
816 lastMousePosition = event->windowPos();
818 if (!mouseGrabberItem &&
819 event->type() == QEvent::MouseButtonPress &&
820 (event->button() & event->buttons()) == event->buttons()) {
821 return deliverInitialMousePressEvent(rootItem, event);
824 if (mouseGrabberItem) {
825 QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
826 const QTransform &transform = mgPrivate->canvasToItemTransform();
827 QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
828 event->button(), event->buttons(), event->modifiers());
830 q->sendEvent(mouseGrabberItem, &me);
831 event->setAccepted(me.isAccepted());
839 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
844 qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
847 d->deliverMouseEvent(event);
850 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
855 qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
858 if (!d->mouseGrabberItem) {
859 QWindow::mouseReleaseEvent(event);
863 d->deliverMouseEvent(event);
864 d->mouseGrabberItem = 0;
867 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
872 qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
875 if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
876 if (d->deliverInitialMousePressEvent(d->rootItem, event))
883 d->deliverMouseEvent(event);
886 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
887 const QPointF &scenePos, const QPointF &lastScenePos,
888 Qt::KeyboardModifiers modifiers, bool accepted)
891 const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
893 //create copy of event
894 QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
895 hoverEvent.setAccepted(accepted);
897 q->sendEvent(item, &hoverEvent);
899 return hoverEvent.isAccepted();
902 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
907 qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
910 if (!d->mouseGrabberItem) {
911 if (d->lastMousePosition.isNull())
912 d->lastMousePosition = event->windowPos();
913 QPointF last = d->lastMousePosition;
914 d->lastMousePosition = event->windowPos();
916 bool accepted = event->isAccepted();
917 bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
919 //take care of any exits
920 accepted = d->clearHover();
922 event->setAccepted(accepted);
926 d->deliverMouseEvent(event);
929 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
930 Qt::KeyboardModifiers modifiers, bool &accepted)
932 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
933 if (itemPrivate->opacity == 0.0)
936 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
937 QPointF p = item->mapFromScene(scenePos);
938 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
942 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
943 for (int ii = children.count() - 1; ii >= 0; --ii) {
944 QQuickItem *child = children.at(ii);
945 if (!child->isVisible() || !child->isEnabled())
947 if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
951 if (itemPrivate->hoverEnabled) {
952 QPointF p = item->mapFromScene(scenePos);
953 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
954 if (!hoverItems.isEmpty() && hoverItems[0] == item) {
956 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
958 QList<QQuickItem *> itemsToHover;
959 QQuickItem* parent = item;
960 itemsToHover << item;
961 while ((parent = parent->parentItem()))
962 itemsToHover << parent;
964 // Leaving from previous hovered items until we reach the item or one of its ancestors.
965 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
966 sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
967 hoverItems.removeFirst();
970 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
971 // ### Shouldn't we send moves for the parent items as well?
972 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
974 // Enter items that are not entered yet.
976 if (!hoverItems.isEmpty())
977 startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
979 startIdx = itemsToHover.count() - 1;
981 for (int i = startIdx; i >= 0; i--) {
982 QQuickItem *itemToHover = itemsToHover[i];
983 if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
984 hoverItems.prepend(itemToHover);
985 sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
997 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
1000 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1001 if (itemPrivate->opacity == 0.0)
1004 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1005 QPointF p = item->mapFromScene(event->posF());
1006 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1010 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1011 for (int ii = children.count() - 1; ii >= 0; --ii) {
1012 QQuickItem *child = children.at(ii);
1013 if (!child->isVisible() || !child->isEnabled())
1015 if (deliverWheelEvent(child, event))
1019 QPointF p = item->mapFromScene(event->posF());
1020 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1021 QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1023 q->sendEvent(item, &wheel);
1024 if (wheel.isAccepted()) {
1033 #ifndef QT_NO_WHEELEVENT
1034 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1038 qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1041 d->deliverWheelEvent(d->rootItem, event);
1043 #endif // QT_NO_WHEELEVENT
1045 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1048 if (event->type() == QEvent::TouchBegin)
1049 qWarning("touchBeginEvent");
1050 else if (event->type() == QEvent::TouchUpdate)
1051 qWarning("touchUpdateEvent");
1052 else if (event->type() == QEvent::TouchEnd)
1053 qWarning("touchEndEvent");
1056 QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1058 if (event->type() == QTouchEvent::TouchBegin) { // all points are new touch points
1059 QSet<int> acceptedNewPoints;
1060 deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1061 if (acceptedNewPoints.count() > 0)
1063 return event->isAccepted();
1066 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1067 QList<QTouchEvent::TouchPoint> newPoints;
1068 QQuickItem *item = 0;
1069 for (int i=0; i<touchPoints.count(); i++) {
1070 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1071 switch (touchPoint.state()) {
1072 case Qt::TouchPointPressed:
1073 newPoints << touchPoint;
1075 case Qt::TouchPointMoved:
1076 case Qt::TouchPointStationary:
1077 case Qt::TouchPointReleased:
1078 if (itemForTouchPointId.contains(touchPoint.id())) {
1079 item = itemForTouchPointId[touchPoint.id()];
1081 updatedPoints[item].append(touchPoint);
1089 if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1090 QSet<int> acceptedNewPoints;
1091 int prevCount = updatedPoints.count();
1092 deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1093 if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1097 if (event->touchPointStates() & Qt::TouchPointReleased) {
1098 for (int i=0; i<touchPoints.count(); i++) {
1099 if (touchPoints[i].state() == Qt::TouchPointReleased)
1100 itemForTouchPointId.remove(touchPoints[i].id());
1104 return event->isAccepted();
1107 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1110 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1112 if (itemPrivate->opacity == 0.0)
1115 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1116 QRectF bounds(0, 0, item->width(), item->height());
1117 for (int i=0; i<newPoints.count(); i++) {
1118 QPointF p = item->mapFromScene(newPoints[i].scenePos());
1119 if (!bounds.contains(p))
1124 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1125 for (int ii = children.count() - 1; ii >= 0; --ii) {
1126 QQuickItem *child = children.at(ii);
1127 if (!child->isEnabled() || !child->isVisible())
1129 if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1133 QList<QTouchEvent::TouchPoint> matchingPoints;
1134 if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1135 QRectF bounds(0, 0, item->width(), item->height());
1136 for (int i=0; i<newPoints.count(); i++) {
1137 if (acceptedNewPoints->contains(newPoints[i].id()))
1139 QPointF p = item->mapFromScene(newPoints[i].scenePos());
1140 if (bounds.contains(p))
1141 matchingPoints << newPoints[i];
1145 if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1146 QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1147 eventPoints.append(matchingPoints);
1148 transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1150 Qt::TouchPointStates eventStates;
1151 for (int i=0; i<eventPoints.count(); i++)
1152 eventStates |= eventPoints[i].state();
1153 // if all points have the same state, set the event type accordingly
1154 QEvent::Type eventType;
1155 switch (eventStates) {
1156 case Qt::TouchPointPressed:
1157 eventType = QEvent::TouchBegin;
1159 case Qt::TouchPointReleased:
1160 eventType = QEvent::TouchEnd;
1163 eventType = QEvent::TouchUpdate;
1167 if (eventStates != Qt::TouchPointStationary) {
1168 QTouchEvent touchEvent(eventType);
1169 touchEvent.setWindow(event->window());
1170 touchEvent.setTarget(item);
1171 touchEvent.setDevice(event->device());
1172 touchEvent.setModifiers(event->modifiers());
1173 touchEvent.setTouchPointStates(eventStates);
1174 touchEvent.setTouchPoints(eventPoints);
1175 touchEvent.setTimestamp(event->timestamp());
1177 touchEvent.accept();
1178 q->sendEvent(item, &touchEvent);
1180 if (touchEvent.isAccepted()) {
1181 for (int i=0; i<matchingPoints.count(); i++) {
1182 itemForTouchPointId[matchingPoints[i].id()] = item;
1183 acceptedNewPoints->insert(matchingPoints[i].id());
1189 updatedPoints->remove(item);
1190 if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1196 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1199 grabber->resetTarget();
1200 QQuickDragGrabber::iterator grabItem = grabber->begin();
1201 if (grabItem != grabber->end()) {
1202 Q_ASSERT(event->type() != QEvent::DragEnter);
1203 if (event->type() == QEvent::Drop) {
1204 QDropEvent *e = static_cast<QDropEvent *>(event);
1205 for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1206 QPointF p = (**grabItem)->mapFromScene(e->pos());
1207 QDropEvent translatedEvent(
1209 e->possibleActions(),
1212 e->keyboardModifiers());
1213 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1214 q->sendEvent(**grabItem, &translatedEvent);
1215 e->setAccepted(translatedEvent.isAccepted());
1216 e->setDropAction(translatedEvent.dropAction());
1217 grabber->setTarget(**grabItem);
1220 if (event->type() != QEvent::DragMove) { // Either an accepted drop or a leave.
1221 QDragLeaveEvent leaveEvent;
1222 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1223 q->sendEvent(**grabItem, &leaveEvent);
1225 } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1226 QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1227 if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1228 moveEvent->setAccepted(true);
1229 for (++grabItem; grabItem != grabber->end();) {
1230 QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1231 if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1232 QDragMoveEvent translatedEvent(
1234 moveEvent->possibleActions(),
1235 moveEvent->mimeData(),
1236 moveEvent->mouseButtons(),
1237 moveEvent->keyboardModifiers());
1238 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1239 q->sendEvent(**grabItem, &translatedEvent);
1242 QDragLeaveEvent leaveEvent;
1243 q->sendEvent(**grabItem, &leaveEvent);
1244 grabItem = grabber->release(grabItem);
1249 QDragLeaveEvent leaveEvent;
1250 q->sendEvent(**grabItem, &leaveEvent);
1254 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1255 QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1256 QDragEnterEvent enterEvent(
1258 e->possibleActions(),
1261 e->keyboardModifiers());
1262 QQuickDropEventEx::copyActions(&enterEvent, *e);
1263 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1267 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1270 bool accepted = false;
1271 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1272 if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
1275 QPointF p = item->mapFromScene(event->pos());
1276 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1277 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1278 QDragMoveEvent translatedEvent(
1280 event->possibleActions(),
1282 event->mouseButtons(),
1283 event->keyboardModifiers(),
1285 QQuickDropEventEx::copyActions(&translatedEvent, *event);
1286 q->sendEvent(item, &translatedEvent);
1287 if (event->type() == QEvent::DragEnter) {
1288 if (translatedEvent.isAccepted()) {
1289 grabber->grab(item);
1296 } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1300 QDragEnterEvent enterEvent(
1302 event->possibleActions(),
1304 event->mouseButtons(),
1305 event->keyboardModifiers());
1306 QQuickDropEventEx::copyActions(&enterEvent, *event);
1307 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1308 for (int ii = children.count() - 1; ii >= 0; --ii) {
1309 if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1316 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1321 QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1322 if (targetPrivate->filtersChildMouseEvents)
1323 if (target->childMouseEventFilter(item, event))
1326 if (sendFilteredMouseEvent(target->parentItem(), item, event))
1333 Propagates an event to a QQuickItem on the canvas
1335 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1340 qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1346 switch (e->type()) {
1347 case QEvent::KeyPress:
1348 case QEvent::KeyRelease:
1350 QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1351 while (!e->isAccepted() && (item = item->parentItem())) {
1353 QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1356 case QEvent::FocusIn:
1357 case QEvent::FocusOut:
1358 QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1360 case QEvent::MouseButtonPress:
1361 case QEvent::MouseButtonRelease:
1362 case QEvent::MouseButtonDblClick:
1363 case QEvent::MouseMove:
1364 // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
1365 if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1367 QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1371 QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1373 case QEvent::HoverEnter:
1374 case QEvent::HoverLeave:
1375 case QEvent::HoverMove:
1376 QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1378 case QEvent::TouchBegin:
1379 case QEvent::TouchUpdate:
1380 case QEvent::TouchEnd:
1381 // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
1382 if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1384 QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1387 case QEvent::DragEnter:
1388 case QEvent::DragMove:
1389 case QEvent::DragLeave:
1391 QQuickItemPrivate::get(item)->deliverDragEvent(e);
1400 void QQuickCanvasPrivate::cleanupNodes()
1402 for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1403 delete cleanupNodeList.at(ii);
1404 cleanupNodeList.clear();
1407 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1409 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1410 if (p->itemNodeInstance) {
1411 delete p->itemNodeInstance;
1412 p->itemNodeInstance = 0;
1419 for (int ii = 0; ii < p->childItems.count(); ++ii)
1420 cleanupNodesOnShutdown(p->childItems.at(ii));
1423 // This must be called from the render thread, with the main thread frozen
1424 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1427 cleanupNodesOnShutdown(rootItem);
1428 QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
1429 for (; it != parentlessItems.end(); ++it)
1430 cleanupNodesOnShutdown(*it);
1433 void QQuickCanvasPrivate::updateDirtyNodes()
1436 qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1441 QQuickItem *updateList = dirtyItemList;
1443 if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1445 while (updateList) {
1446 QQuickItem *item = updateList;
1447 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1448 itemPriv->removeFromDirtyList();
1451 qWarning() << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1453 updateDirtyNode(item);
1457 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1459 #ifdef QML_RUNTIME_TESTING
1460 bool didFlash = false;
1463 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1464 quint32 dirty = itemPriv->dirtyAttributes;
1465 itemPriv->dirtyAttributes = 0;
1467 if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1468 (dirty & QQuickItemPrivate::Size && itemPriv->origin != QQuickItem::TopLeft &&
1469 (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1473 if (itemPriv->x != 0. || itemPriv->y != 0.)
1474 matrix.translate(itemPriv->x, itemPriv->y);
1476 for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1477 itemPriv->transforms.at(ii)->applyTo(&matrix);
1479 if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1480 QPointF origin = item->transformOriginPoint();
1481 matrix.translate(origin.x(), origin.y());
1482 if (itemPriv->scale != 1.)
1483 matrix.scale(itemPriv->scale, itemPriv->scale);
1484 if (itemPriv->rotation != 0.)
1485 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1486 matrix.translate(-origin.x(), -origin.y());
1489 itemPriv->itemNode()->setMatrix(matrix);
1492 bool clipEffectivelyChanged = dirty & QQuickItemPrivate::Clip &&
1493 ((item->clip() == false) != (itemPriv->clipNode == 0));
1494 bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
1495 ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1497 if (clipEffectivelyChanged) {
1498 QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1499 QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1502 Q_ASSERT(itemPriv->clipNode == 0);
1503 itemPriv->clipNode = new QQuickDefaultClipNode(item->boundingRect());
1504 itemPriv->clipNode->update();
1507 parent->removeChildNode(child);
1508 parent->appendChildNode(itemPriv->clipNode);
1510 itemPriv->clipNode->appendChildNode(child);
1513 Q_ASSERT(itemPriv->clipNode != 0);
1514 parent->removeChildNode(itemPriv->clipNode);
1516 itemPriv->clipNode->removeChildNode(child);
1517 delete itemPriv->clipNode;
1518 itemPriv->clipNode = 0;
1520 parent->appendChildNode(child);
1524 if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1525 itemPriv->childContainerNode()->removeAllChildNodes();
1527 if (effectRefEffectivelyChanged) {
1528 QSGNode *parent = itemPriv->clipNode;
1530 parent = itemPriv->opacityNode;
1532 parent = itemPriv->itemNode();
1533 QSGNode *child = itemPriv->groupNode;
1535 if (itemPriv->effectRefCount) {
1536 Q_ASSERT(itemPriv->rootNode == 0);
1537 itemPriv->rootNode = new QSGRootNode;
1540 parent->removeChildNode(child);
1541 parent->appendChildNode(itemPriv->rootNode);
1543 itemPriv->rootNode->appendChildNode(child);
1545 Q_ASSERT(itemPriv->rootNode != 0);
1546 parent->removeChildNode(itemPriv->rootNode);
1548 itemPriv->rootNode->removeChildNode(child);
1549 delete itemPriv->rootNode;
1550 itemPriv->rootNode = 0;
1552 parent->appendChildNode(child);
1556 if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1557 QSGNode *groupNode = itemPriv->groupNode;
1559 groupNode->removeAllChildNodes();
1561 QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1564 for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1565 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1566 if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1568 if (childPrivate->itemNode()->parent())
1569 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1571 itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1573 itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1575 if (itemPriv->paintNode)
1576 itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1578 for (; ii < orderedChildren.count(); ++ii) {
1579 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1580 if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1582 if (childPrivate->itemNode()->parent())
1583 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1585 itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1589 if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode) {
1590 itemPriv->clipNode->setRect(item->boundingRect());
1591 itemPriv->clipNode->update();
1594 if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
1595 qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1596 ? itemPriv->opacity : qreal(0);
1598 if (opacity != 1 && !itemPriv->opacityNode) {
1599 itemPriv->opacityNode = new QSGOpacityNode;
1601 QSGNode *parent = itemPriv->itemNode();
1602 QSGNode *child = itemPriv->clipNode;
1604 child = itemPriv->rootNode;
1606 child = itemPriv->groupNode;
1609 parent->removeChildNode(child);
1610 parent->appendChildNode(itemPriv->opacityNode);
1612 itemPriv->opacityNode->appendChildNode(child);
1614 if (itemPriv->opacityNode)
1615 itemPriv->opacityNode->setOpacity(opacity);
1618 if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1620 if (itemPriv->flags & QQuickItem::ItemHasContents) {
1621 updatePaintNodeData.transformNode = itemPriv->itemNode();
1622 itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1624 Q_ASSERT(itemPriv->paintNode == 0 ||
1625 itemPriv->paintNode->parent() == 0 ||
1626 itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1628 if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1629 if (itemPriv->beforePaintNode)
1630 itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1632 itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1634 } else if (itemPriv->paintNode) {
1635 delete itemPriv->paintNode;
1636 itemPriv->paintNode = 0;
1640 if ((dirty & QQuickItemPrivate::PerformanceHints) && itemPriv->groupNode) {
1641 itemPriv->groupNode->setFlag(QSGNode::ChildrenDoNotOverlap, itemPriv->childrenDoNotOverlap);
1642 itemPriv->groupNode->setFlag(QSGNode::StaticSubtreeGeometry, itemPriv->staticSubtreeGeometry);
1646 // Check consistency.
1647 const QSGNode *nodeChain[] = {
1648 itemPriv->itemNodeInstance,
1649 itemPriv->opacityNode,
1652 itemPriv->groupNode,
1653 itemPriv->paintNode,
1658 while (ip < 5 && nodeChain[ip] == 0)
1663 while (ic < 5 && nodeChain[ic] == 0)
1665 const QSGNode *parent = nodeChain[ip];
1666 const QSGNode *child = nodeChain[ic];
1668 Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1670 Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1671 Q_ASSERT(child->parent() == parent);
1672 bool containsChild = false;
1673 for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1674 containsChild |= (n == child);
1675 Q_ASSERT(containsChild);
1681 #ifdef QML_RUNTIME_TESTING
1682 if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1683 QSGFlashNode *flash = new QSGFlashNode();
1684 flash->setRect(item->boundingRect());
1685 itemPriv->childContainerNode()->appendChildNode(flash);
1696 void QQuickCanvas::maybeUpdate()
1699 d->windowManager->maybeUpdate(this);
1702 void QQuickCanvas::cleanupSceneGraph()
1709 delete d->renderer->rootNode();
1716 Returns the opengl context used for rendering.
1718 If the scene graph is not ready, this function will return 0.
1720 \sa sceneGraphInitialized(), sceneGraphInvalidated()
1723 QOpenGLContext *QQuickCanvas::openglContext() const
1725 Q_D(const QQuickCanvas);
1726 if (d->context->isReady())
1727 return d->context->glContext();
1733 \fn void QSGContext::sceneGraphInitialized()
1735 This signal is emitted when the scene graph has been initialized.
1737 This signal will be emitted from the scene graph rendering thread.
1743 \fn void QSGContext::sceneGraphInvalidated()
1745 This signal is emitted when the scene graph has been invalidated.
1747 This signal implies that the opengl rendering context used
1748 has been invalidated and all user resources tied to that context
1751 This signal will be emitted from the scene graph rendering thread.
1755 Returns the QSGEngine used for this scene.
1757 The engine will only be available once the scene graph has been
1758 initialized. Register for the sceneGraphEngine() signal to get
1759 notification about this.
1764 QSGEngine *QQuickCanvas::sceneGraphEngine() const
1766 Q_D(const QQuickCanvas);
1767 qWarning("QQuickCanvas::sceneGraphEngine() is deprecated, use members of QQuickCanvas instead");
1768 if (d->context && d->context->isReady())
1776 Sets the render target for this canvas to be \a fbo.
1778 The specified fbo must be created in the context of the canvas
1779 or one that shares with it.
1782 This function can only be called from the thread doing
1786 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1789 if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1790 qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1794 d->renderTarget = fbo;
1800 Returns the render target for this canvas.
1802 The default is to render to the surface of the canvas, in which
1803 case the render target is 0.
1805 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
1807 Q_D(const QQuickCanvas);
1808 return d->renderTarget;
1813 Grabs the contents of the framebuffer and returns it as an image.
1815 This function might not work if the view is not visible.
1817 \warning Calling this function will cause performance problems.
1819 \warning This function can only be called from the GUI thread.
1821 QImage QQuickCanvas::grabFrameBuffer()
1824 return d->windowManager->grab(this);
1828 Returns an incubation controller that splices incubation between frames
1829 for this canvas. QQuickView automatically installs this controller for you,
1830 otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController}
1832 The controller is owned by the canvas and will be destroyed when the canvas
1835 QDeclarativeIncubationController *QQuickCanvas::incubationController() const
1837 Q_D(const QQuickCanvas);
1839 if (!d->incubationController)
1840 d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
1841 return d->incubationController;
1847 \enum QQuickCanvas::CreateTextureOption
1849 The CreateTextureOption enums are used to customize a texture is wrapped.
1851 \value TextureHasAlphaChannel The texture has an alpha channel and should
1852 be drawn using blending.
1854 \value TextureHasMipmaps The texture has mipmaps and can be drawn with
1857 \value TextureOwnsGLTexture The texture object owns the texture id and
1858 will delete the GL texture when the texture object is deleted.
1862 \fn void QQuickCanvas::beforeRendering()
1864 This signal is emitted before the scene starts rendering.
1866 Combined with the modes for clearing the background, this option
1867 can be used to paint using raw GL under QML content.
1869 The GL context used for rendering the scene graph will be bound
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.
1878 \fn void QQuickCanvas::afterRendering()
1880 This signal is emitted after the scene has completed rendering, before swapbuffers is called.
1882 This signal can be used to paint using raw GL on top of QML content,
1883 or to do screen scraping of the current frame buffer.
1885 The GL context used for rendering the scene graph will be bound at this point.
1887 Since this signal is emitted from the scene graph rendering thread, the receiver should
1888 be on the scene graph thread or the connection should be Qt::DirectConnection.
1894 Sets weither the scene graph rendering of QML should clear the color buffer
1895 before it starts rendering to \a enbled.
1897 By disabling clearing of the color buffer, it is possible to do GL painting
1898 under the scene graph.
1900 The color buffer is cleared by default.
1902 \sa beforeRendering()
1905 void QQuickCanvas::setClearBeforeRendering(bool enabled)
1908 d->clearBeforeRendering = enabled;
1914 Returns weither clearing of the color buffer is done before rendering or not.
1917 bool QQuickCanvas::clearBeforeRendering() const
1919 Q_D(const QQuickCanvas);
1920 return d->clearBeforeRendering;
1926 Creates a new QSGTexture from the supplied \a image. If the image has an
1927 alpha channel, the corresponding texture will have an alpha channel.
1929 The caller of the function is responsible for deleting the returned texture.
1930 The actual GL texture will be deleted when the texture object is deleted.
1932 \warning This function will return 0 if the scene graph has not yet been
1935 This function can be called both from the GUI thread and the rendering thread.
1937 \sa sceneGraphInitialized()
1940 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
1942 Q_D(const QQuickCanvas);
1943 if (d->context && d->context->isReady())
1944 return d->context->createTexture(image);
1952 Creates a new QSGTexture object from an existing GL texture \a id.
1954 The caller of the function is responsible for deleting the returned texture.
1956 Use \a options to customize the texture attributes.
1958 \warning This function will return 0 if the scenegraph has not yet been
1961 \sa sceneGraphInitialized()
1963 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
1965 Q_D(const QQuickCanvas);
1966 if (d->context && d->context->isReady()) {
1967 QSGPlainTexture *texture = new QSGPlainTexture();
1968 texture->setTextureId(id);
1969 texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
1970 texture->setHasMipmaps(options & TextureHasMipmaps);
1971 texture->setOwnsTexture(options & TextureOwnsGLTexture);
1972 texture->setTextureSize(size);
1980 Sets the color used to clear the opengl context to \a color.
1982 Setting the clear color has no effect when clearing is disabled.
1984 \sa setClearBeforeRendering()
1987 void QQuickCanvas::setClearColor(const QColor &color)
1990 if (color == d->clearColor)
1993 d->clearColor = color;
1994 emit clearColorChanged(color);
2000 Returns the color used to clear the opengl context.
2003 QColor QQuickCanvas::clearColor() const
2005 return d_func()->clearColor;
2010 #include "moc_qquickcanvas.cpp"