1 /****************************************************************************
3 ** Copyright (C) 2012 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;
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;
675 Returns the item which currently has the mouse grab.
677 QQuickItem *QQuickCanvas::mouseGrabberItem() const
679 Q_D(const QQuickCanvas);
681 return d->mouseGrabberItem;
686 \qmlproperty color QtQuick2.Window::Window::color
688 The background color for the window.
690 Setting this property is more efficient than using a separate Rectangle.
693 bool QQuickCanvasPrivate::clearHover()
695 if (hoverItems.isEmpty())
698 QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
700 bool accepted = false;
701 foreach (QQuickItem* item, hoverItems)
702 accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
708 bool QQuickCanvas::event(QEvent *e)
714 case QEvent::TouchBegin:
715 case QEvent::TouchUpdate:
716 case QEvent::TouchEnd:
718 QTouchEvent *touch = static_cast<QTouchEvent *>(e);
719 d->translateTouchEvent(touch);
720 d->deliverTouchEvent(touch);
721 if (!touch->isAccepted())
727 d->lastMousePosition = QPoint();
729 case QEvent::DragEnter:
730 case QEvent::DragLeave:
731 case QEvent::DragMove:
733 d->deliverDragEvent(&d->dragGrabber, e);
735 case QEvent::WindowDeactivate:
736 rootItem()->windowDeactivateEvent();
742 return QWindow::event(e);
745 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
749 if (d->activeFocusItem)
750 sendEvent(d->activeFocusItem, e);
753 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
757 if (d->activeFocusItem)
758 sendEvent(d->activeFocusItem, e);
761 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
765 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
766 if (itemPrivate->opacity == 0.0)
769 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
770 QPointF p = item->mapFromScene(event->windowPos());
771 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
775 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
776 for (int ii = children.count() - 1; ii >= 0; --ii) {
777 QQuickItem *child = children.at(ii);
778 if (!child->isVisible() || !child->isEnabled())
780 if (deliverInitialMousePressEvent(child, event))
784 if (itemPrivate->acceptedMouseButtons & event->button()) {
785 QPointF p = item->mapFromScene(event->windowPos());
786 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
787 QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
788 event->button(), event->buttons(), event->modifiers());
790 mouseGrabberItem = item;
791 q->sendEvent(item, &me);
792 event->setAccepted(me.isAccepted());
795 mouseGrabberItem->ungrabMouse();
796 mouseGrabberItem = 0;
803 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
807 lastMousePosition = event->windowPos();
809 if (!mouseGrabberItem &&
810 event->type() == QEvent::MouseButtonPress &&
811 (event->button() & event->buttons()) == event->buttons()) {
812 return deliverInitialMousePressEvent(rootItem, event);
815 if (mouseGrabberItem) {
816 QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
817 const QTransform &transform = mgPrivate->canvasToItemTransform();
818 QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
819 event->button(), event->buttons(), event->modifiers());
821 q->sendEvent(mouseGrabberItem, &me);
822 event->setAccepted(me.isAccepted());
830 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
835 qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
838 d->deliverMouseEvent(event);
841 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
846 qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
849 if (!d->mouseGrabberItem) {
850 QWindow::mouseReleaseEvent(event);
854 d->deliverMouseEvent(event);
855 d->mouseGrabberItem = 0;
858 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
863 qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
866 if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
867 if (d->deliverInitialMousePressEvent(d->rootItem, event))
874 d->deliverMouseEvent(event);
877 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
878 const QPointF &scenePos, const QPointF &lastScenePos,
879 Qt::KeyboardModifiers modifiers, bool accepted)
882 const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
884 //create copy of event
885 QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
886 hoverEvent.setAccepted(accepted);
888 q->sendEvent(item, &hoverEvent);
890 return hoverEvent.isAccepted();
893 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
898 qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
901 if (!d->mouseGrabberItem) {
902 if (d->lastMousePosition.isNull())
903 d->lastMousePosition = event->windowPos();
904 QPointF last = d->lastMousePosition;
905 d->lastMousePosition = event->windowPos();
907 bool accepted = event->isAccepted();
908 bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
910 //take care of any exits
911 accepted = d->clearHover();
913 event->setAccepted(accepted);
917 d->deliverMouseEvent(event);
920 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
921 Qt::KeyboardModifiers modifiers, bool &accepted)
923 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
924 if (itemPrivate->opacity == 0.0)
927 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
928 QPointF p = item->mapFromScene(scenePos);
929 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
933 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
934 for (int ii = children.count() - 1; ii >= 0; --ii) {
935 QQuickItem *child = children.at(ii);
936 if (!child->isVisible() || !child->isEnabled())
938 if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
942 if (itemPrivate->hoverEnabled) {
943 QPointF p = item->mapFromScene(scenePos);
944 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
945 if (!hoverItems.isEmpty() && hoverItems[0] == item) {
947 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
949 QList<QQuickItem *> itemsToHover;
950 QQuickItem* parent = item;
951 itemsToHover << item;
952 while ((parent = parent->parentItem()))
953 itemsToHover << parent;
955 // Leaving from previous hovered items until we reach the item or one of its ancestors.
956 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
957 sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
958 hoverItems.removeFirst();
961 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
962 // ### Shouldn't we send moves for the parent items as well?
963 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
965 // Enter items that are not entered yet.
967 if (!hoverItems.isEmpty())
968 startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
970 startIdx = itemsToHover.count() - 1;
972 for (int i = startIdx; i >= 0; i--) {
973 QQuickItem *itemToHover = itemsToHover[i];
974 if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
975 hoverItems.prepend(itemToHover);
976 sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
988 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
991 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
992 if (itemPrivate->opacity == 0.0)
995 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
996 QPointF p = item->mapFromScene(event->posF());
997 if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1001 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1002 for (int ii = children.count() - 1; ii >= 0; --ii) {
1003 QQuickItem *child = children.at(ii);
1004 if (!child->isVisible() || !child->isEnabled())
1006 if (deliverWheelEvent(child, event))
1010 QPointF p = item->mapFromScene(event->posF());
1011 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1012 QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1014 q->sendEvent(item, &wheel);
1015 if (wheel.isAccepted()) {
1024 #ifndef QT_NO_WHEELEVENT
1025 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1029 qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1032 d->deliverWheelEvent(d->rootItem, event);
1034 #endif // QT_NO_WHEELEVENT
1036 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1039 if (event->type() == QEvent::TouchBegin)
1040 qWarning("touchBeginEvent");
1041 else if (event->type() == QEvent::TouchUpdate)
1042 qWarning("touchUpdateEvent");
1043 else if (event->type() == QEvent::TouchEnd)
1044 qWarning("touchEndEvent");
1047 QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1049 if (event->type() == QTouchEvent::TouchBegin) { // all points are new touch points
1050 QSet<int> acceptedNewPoints;
1051 deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1052 if (acceptedNewPoints.count() > 0)
1054 return event->isAccepted();
1057 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1058 QList<QTouchEvent::TouchPoint> newPoints;
1059 QQuickItem *item = 0;
1060 for (int i=0; i<touchPoints.count(); i++) {
1061 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1062 switch (touchPoint.state()) {
1063 case Qt::TouchPointPressed:
1064 newPoints << touchPoint;
1066 case Qt::TouchPointMoved:
1067 case Qt::TouchPointStationary:
1068 case Qt::TouchPointReleased:
1069 if (itemForTouchPointId.contains(touchPoint.id())) {
1070 item = itemForTouchPointId[touchPoint.id()];
1072 updatedPoints[item].append(touchPoint);
1080 if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1081 QSet<int> acceptedNewPoints;
1082 int prevCount = updatedPoints.count();
1083 deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1084 if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1088 if (event->touchPointStates() & Qt::TouchPointReleased) {
1089 for (int i=0; i<touchPoints.count(); i++) {
1090 if (touchPoints[i].state() == Qt::TouchPointReleased)
1091 itemForTouchPointId.remove(touchPoints[i].id());
1095 return event->isAccepted();
1098 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1101 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1103 if (itemPrivate->opacity == 0.0)
1106 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1107 QRectF bounds(0, 0, item->width(), item->height());
1108 for (int i=0; i<newPoints.count(); i++) {
1109 QPointF p = item->mapFromScene(newPoints[i].scenePos());
1110 if (!bounds.contains(p))
1115 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1116 for (int ii = children.count() - 1; ii >= 0; --ii) {
1117 QQuickItem *child = children.at(ii);
1118 if (!child->isEnabled() || !child->isVisible())
1120 if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1124 QList<QTouchEvent::TouchPoint> matchingPoints;
1125 if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1126 QRectF bounds(0, 0, item->width(), item->height());
1127 for (int i=0; i<newPoints.count(); i++) {
1128 if (acceptedNewPoints->contains(newPoints[i].id()))
1130 QPointF p = item->mapFromScene(newPoints[i].scenePos());
1131 if (bounds.contains(p))
1132 matchingPoints << newPoints[i];
1136 if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1137 QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1138 eventPoints.append(matchingPoints);
1139 transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1141 Qt::TouchPointStates eventStates;
1142 for (int i=0; i<eventPoints.count(); i++)
1143 eventStates |= eventPoints[i].state();
1144 // if all points have the same state, set the event type accordingly
1145 QEvent::Type eventType;
1146 switch (eventStates) {
1147 case Qt::TouchPointPressed:
1148 eventType = QEvent::TouchBegin;
1150 case Qt::TouchPointReleased:
1151 eventType = QEvent::TouchEnd;
1154 eventType = QEvent::TouchUpdate;
1158 if (eventStates != Qt::TouchPointStationary) {
1159 QTouchEvent touchEvent(eventType);
1160 touchEvent.setWindow(event->window());
1161 touchEvent.setTarget(item);
1162 touchEvent.setDevice(event->device());
1163 touchEvent.setModifiers(event->modifiers());
1164 touchEvent.setTouchPointStates(eventStates);
1165 touchEvent.setTouchPoints(eventPoints);
1166 touchEvent.setTimestamp(event->timestamp());
1168 touchEvent.accept();
1169 q->sendEvent(item, &touchEvent);
1171 if (touchEvent.isAccepted()) {
1172 for (int i=0; i<matchingPoints.count(); i++) {
1173 itemForTouchPointId[matchingPoints[i].id()] = item;
1174 acceptedNewPoints->insert(matchingPoints[i].id());
1180 updatedPoints->remove(item);
1181 if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1187 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1190 grabber->resetTarget();
1191 QQuickDragGrabber::iterator grabItem = grabber->begin();
1192 if (grabItem != grabber->end()) {
1193 Q_ASSERT(event->type() != QEvent::DragEnter);
1194 if (event->type() == QEvent::Drop) {
1195 QDropEvent *e = static_cast<QDropEvent *>(event);
1196 for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1197 QPointF p = (**grabItem)->mapFromScene(e->pos());
1198 QDropEvent translatedEvent(
1200 e->possibleActions(),
1203 e->keyboardModifiers());
1204 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1205 q->sendEvent(**grabItem, &translatedEvent);
1206 e->setAccepted(translatedEvent.isAccepted());
1207 e->setDropAction(translatedEvent.dropAction());
1208 grabber->setTarget(**grabItem);
1211 if (event->type() != QEvent::DragMove) { // Either an accepted drop or a leave.
1212 QDragLeaveEvent leaveEvent;
1213 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1214 q->sendEvent(**grabItem, &leaveEvent);
1216 } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1217 QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1218 if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1219 moveEvent->setAccepted(true);
1220 for (++grabItem; grabItem != grabber->end();) {
1221 QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1222 if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1223 QDragMoveEvent translatedEvent(
1225 moveEvent->possibleActions(),
1226 moveEvent->mimeData(),
1227 moveEvent->mouseButtons(),
1228 moveEvent->keyboardModifiers());
1229 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1230 q->sendEvent(**grabItem, &translatedEvent);
1233 QDragLeaveEvent leaveEvent;
1234 q->sendEvent(**grabItem, &leaveEvent);
1235 grabItem = grabber->release(grabItem);
1240 QDragLeaveEvent leaveEvent;
1241 q->sendEvent(**grabItem, &leaveEvent);
1245 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1246 QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1247 QDragEnterEvent enterEvent(
1249 e->possibleActions(),
1252 e->keyboardModifiers());
1253 QQuickDropEventEx::copyActions(&enterEvent, *e);
1254 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1258 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1261 bool accepted = false;
1262 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1263 if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
1266 QPointF p = item->mapFromScene(event->pos());
1267 if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1268 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1269 QDragMoveEvent translatedEvent(
1271 event->possibleActions(),
1273 event->mouseButtons(),
1274 event->keyboardModifiers(),
1276 QQuickDropEventEx::copyActions(&translatedEvent, *event);
1277 q->sendEvent(item, &translatedEvent);
1278 if (event->type() == QEvent::DragEnter) {
1279 if (translatedEvent.isAccepted()) {
1280 grabber->grab(item);
1287 } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1291 QDragEnterEvent enterEvent(
1293 event->possibleActions(),
1295 event->mouseButtons(),
1296 event->keyboardModifiers());
1297 QQuickDropEventEx::copyActions(&enterEvent, *event);
1298 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1299 for (int ii = children.count() - 1; ii >= 0; --ii) {
1300 if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1307 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1312 QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1313 if (targetPrivate->filtersChildMouseEvents)
1314 if (target->childMouseEventFilter(item, event))
1317 if (sendFilteredMouseEvent(target->parentItem(), item, event))
1324 Propagates an event to a QQuickItem on the canvas
1326 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1331 qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1337 switch (e->type()) {
1338 case QEvent::KeyPress:
1339 case QEvent::KeyRelease:
1341 QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1342 while (!e->isAccepted() && (item = item->parentItem())) {
1344 QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1347 case QEvent::FocusIn:
1348 case QEvent::FocusOut:
1349 QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1351 case QEvent::MouseButtonPress:
1352 case QEvent::MouseButtonRelease:
1353 case QEvent::MouseButtonDblClick:
1354 case QEvent::MouseMove:
1355 // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
1356 if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1358 QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1362 QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1364 case QEvent::HoverEnter:
1365 case QEvent::HoverLeave:
1366 case QEvent::HoverMove:
1367 QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1369 case QEvent::TouchBegin:
1370 case QEvent::TouchUpdate:
1371 case QEvent::TouchEnd:
1372 // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
1373 if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1375 QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1378 case QEvent::DragEnter:
1379 case QEvent::DragMove:
1380 case QEvent::DragLeave:
1382 QQuickItemPrivate::get(item)->deliverDragEvent(e);
1391 void QQuickCanvasPrivate::cleanupNodes()
1393 for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1394 delete cleanupNodeList.at(ii);
1395 cleanupNodeList.clear();
1398 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1400 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1401 if (p->itemNodeInstance) {
1402 delete p->itemNodeInstance;
1403 p->itemNodeInstance = 0;
1410 for (int ii = 0; ii < p->childItems.count(); ++ii)
1411 cleanupNodesOnShutdown(p->childItems.at(ii));
1414 // This must be called from the render thread, with the main thread frozen
1415 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1418 cleanupNodesOnShutdown(rootItem);
1419 QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
1420 for (; it != parentlessItems.end(); ++it)
1421 cleanupNodesOnShutdown(*it);
1424 void QQuickCanvasPrivate::updateDirtyNodes()
1427 qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1432 QQuickItem *updateList = dirtyItemList;
1434 if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1436 while (updateList) {
1437 QQuickItem *item = updateList;
1438 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1439 itemPriv->removeFromDirtyList();
1442 qWarning() << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1444 updateDirtyNode(item);
1448 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1450 #ifdef QML_RUNTIME_TESTING
1451 bool didFlash = false;
1454 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1455 quint32 dirty = itemPriv->dirtyAttributes;
1456 itemPriv->dirtyAttributes = 0;
1458 if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1459 (dirty & QQuickItemPrivate::Size && itemPriv->origin != QQuickItem::TopLeft &&
1460 (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1464 if (itemPriv->x != 0. || itemPriv->y != 0.)
1465 matrix.translate(itemPriv->x, itemPriv->y);
1467 for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1468 itemPriv->transforms.at(ii)->applyTo(&matrix);
1470 if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1471 QPointF origin = item->transformOriginPoint();
1472 matrix.translate(origin.x(), origin.y());
1473 if (itemPriv->scale != 1.)
1474 matrix.scale(itemPriv->scale, itemPriv->scale);
1475 if (itemPriv->rotation != 0.)
1476 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1477 matrix.translate(-origin.x(), -origin.y());
1480 itemPriv->itemNode()->setMatrix(matrix);
1483 bool clipEffectivelyChanged = dirty & QQuickItemPrivate::Clip &&
1484 ((item->clip() == false) != (itemPriv->clipNode == 0));
1485 bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
1486 ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1488 if (clipEffectivelyChanged) {
1489 QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1490 QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1493 Q_ASSERT(itemPriv->clipNode == 0);
1494 itemPriv->clipNode = new QQuickDefaultClipNode(item->boundingRect());
1495 itemPriv->clipNode->update();
1498 parent->removeChildNode(child);
1499 parent->appendChildNode(itemPriv->clipNode);
1501 itemPriv->clipNode->appendChildNode(child);
1504 Q_ASSERT(itemPriv->clipNode != 0);
1505 parent->removeChildNode(itemPriv->clipNode);
1507 itemPriv->clipNode->removeChildNode(child);
1508 delete itemPriv->clipNode;
1509 itemPriv->clipNode = 0;
1511 parent->appendChildNode(child);
1515 if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1516 itemPriv->childContainerNode()->removeAllChildNodes();
1518 if (effectRefEffectivelyChanged) {
1519 QSGNode *parent = itemPriv->clipNode;
1521 parent = itemPriv->opacityNode;
1523 parent = itemPriv->itemNode();
1524 QSGNode *child = itemPriv->groupNode;
1526 if (itemPriv->effectRefCount) {
1527 Q_ASSERT(itemPriv->rootNode == 0);
1528 itemPriv->rootNode = new QSGRootNode;
1531 parent->removeChildNode(child);
1532 parent->appendChildNode(itemPriv->rootNode);
1534 itemPriv->rootNode->appendChildNode(child);
1536 Q_ASSERT(itemPriv->rootNode != 0);
1537 parent->removeChildNode(itemPriv->rootNode);
1539 itemPriv->rootNode->removeChildNode(child);
1540 delete itemPriv->rootNode;
1541 itemPriv->rootNode = 0;
1543 parent->appendChildNode(child);
1547 if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1548 QSGNode *groupNode = itemPriv->groupNode;
1550 groupNode->removeAllChildNodes();
1552 QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1555 for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1556 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1557 if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1559 if (childPrivate->itemNode()->parent())
1560 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1562 itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1564 itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1566 if (itemPriv->paintNode)
1567 itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1569 for (; ii < orderedChildren.count(); ++ii) {
1570 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1571 if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1573 if (childPrivate->itemNode()->parent())
1574 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1576 itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1580 if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode) {
1581 itemPriv->clipNode->setRect(item->boundingRect());
1582 itemPriv->clipNode->update();
1585 if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
1586 qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1587 ? itemPriv->opacity : qreal(0);
1589 if (opacity != 1 && !itemPriv->opacityNode) {
1590 itemPriv->opacityNode = new QSGOpacityNode;
1592 QSGNode *parent = itemPriv->itemNode();
1593 QSGNode *child = itemPriv->clipNode;
1595 child = itemPriv->rootNode;
1597 child = itemPriv->groupNode;
1600 parent->removeChildNode(child);
1601 parent->appendChildNode(itemPriv->opacityNode);
1603 itemPriv->opacityNode->appendChildNode(child);
1605 if (itemPriv->opacityNode)
1606 itemPriv->opacityNode->setOpacity(opacity);
1609 if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1611 if (itemPriv->flags & QQuickItem::ItemHasContents) {
1612 updatePaintNodeData.transformNode = itemPriv->itemNode();
1613 itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1615 Q_ASSERT(itemPriv->paintNode == 0 ||
1616 itemPriv->paintNode->parent() == 0 ||
1617 itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1619 if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1620 if (itemPriv->beforePaintNode)
1621 itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1623 itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1625 } else if (itemPriv->paintNode) {
1626 delete itemPriv->paintNode;
1627 itemPriv->paintNode = 0;
1631 if ((dirty & QQuickItemPrivate::PerformanceHints) && itemPriv->groupNode) {
1632 itemPriv->groupNode->setFlag(QSGNode::ChildrenDoNotOverlap, itemPriv->childrenDoNotOverlap);
1633 itemPriv->groupNode->setFlag(QSGNode::StaticSubtreeGeometry, itemPriv->staticSubtreeGeometry);
1637 // Check consistency.
1638 const QSGNode *nodeChain[] = {
1639 itemPriv->itemNodeInstance,
1640 itemPriv->opacityNode,
1643 itemPriv->groupNode,
1644 itemPriv->paintNode,
1649 while (ip < 5 && nodeChain[ip] == 0)
1654 while (ic < 5 && nodeChain[ic] == 0)
1656 const QSGNode *parent = nodeChain[ip];
1657 const QSGNode *child = nodeChain[ic];
1659 Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1661 Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1662 Q_ASSERT(child->parent() == parent);
1663 bool containsChild = false;
1664 for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1665 containsChild |= (n == child);
1666 Q_ASSERT(containsChild);
1672 #ifdef QML_RUNTIME_TESTING
1673 if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1674 QSGFlashNode *flash = new QSGFlashNode();
1675 flash->setRect(item->boundingRect());
1676 itemPriv->childContainerNode()->appendChildNode(flash);
1687 void QQuickCanvas::maybeUpdate()
1690 d->windowManager->maybeUpdate(this);
1693 void QQuickCanvas::cleanupSceneGraph()
1700 delete d->renderer->rootNode();
1707 Returns the opengl context used for rendering.
1709 If the scene graph is not ready, this function will return 0.
1711 \sa sceneGraphInitialized(), sceneGraphInvalidated()
1714 QOpenGLContext *QQuickCanvas::openglContext() const
1716 Q_D(const QQuickCanvas);
1717 if (d->context->isReady())
1718 return d->context->glContext();
1724 \fn void QSGContext::sceneGraphInitialized()
1726 This signal is emitted when the scene graph has been initialized.
1728 This signal will be emitted from the scene graph rendering thread.
1734 \fn void QSGContext::sceneGraphInvalidated()
1736 This signal is emitted when the scene graph has been invalidated.
1738 This signal implies that the opengl rendering context used
1739 has been invalidated and all user resources tied to that context
1742 This signal will be emitted from the scene graph rendering thread.
1746 Returns the QSGEngine used for this scene.
1748 The engine will only be available once the scene graph has been
1749 initialized. Register for the sceneGraphEngine() signal to get
1750 notification about this.
1755 QSGEngine *QQuickCanvas::sceneGraphEngine() const
1757 Q_D(const QQuickCanvas);
1758 qWarning("QQuickCanvas::sceneGraphEngine() is deprecated, use members of QQuickCanvas instead");
1759 if (d->context && d->context->isReady())
1767 Sets the render target for this canvas to be \a fbo.
1769 The specified fbo must be created in the context of the canvas
1770 or one that shares with it.
1773 This function can only be called from the thread doing
1777 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1780 if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1781 qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1785 d->renderTarget = fbo;
1791 Returns the render target for this canvas.
1793 The default is to render to the surface of the canvas, in which
1794 case the render target is 0.
1796 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
1798 Q_D(const QQuickCanvas);
1799 return d->renderTarget;
1804 Grabs the contents of the framebuffer and returns it as an image.
1806 This function might not work if the view is not visible.
1808 \warning Calling this function will cause performance problems.
1810 \warning This function can only be called from the GUI thread.
1812 QImage QQuickCanvas::grabFrameBuffer()
1815 return d->windowManager->grab(this);
1819 Returns an incubation controller that splices incubation between frames
1820 for this canvas. QQuickView automatically installs this controller for you,
1821 otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController}
1823 The controller is owned by the canvas and will be destroyed when the canvas
1826 QDeclarativeIncubationController *QQuickCanvas::incubationController() const
1828 Q_D(const QQuickCanvas);
1830 if (!d->incubationController)
1831 d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
1832 return d->incubationController;
1838 \enum QQuickCanvas::CreateTextureOption
1840 The CreateTextureOption enums are used to customize a texture is wrapped.
1842 \value TextureHasAlphaChannel The texture has an alpha channel and should
1843 be drawn using blending.
1845 \value TextureHasMipmaps The texture has mipmaps and can be drawn with
1848 \value TextureOwnsGLTexture The texture object owns the texture id and
1849 will delete the GL texture when the texture object is deleted.
1853 \fn void QQuickCanvas::beforeRendering()
1855 This signal is emitted before the scene starts rendering.
1857 Combined with the modes for clearing the background, this option
1858 can be used to paint using raw GL under QML content.
1860 The GL context used for rendering the scene graph will be bound
1863 Since this signal is emitted from the scene graph rendering thread, the receiver should
1864 be on the scene graph thread or the connection should be Qt::DirectConnection.
1869 \fn void QQuickCanvas::afterRendering()
1871 This signal is emitted after the scene has completed rendering, before swapbuffers is called.
1873 This signal can be used to paint using raw GL on top of QML content,
1874 or to do screen scraping of the current frame buffer.
1876 The GL context used for rendering the scene graph will be bound at this point.
1878 Since this signal is emitted from the scene graph rendering thread, the receiver should
1879 be on the scene graph thread or the connection should be Qt::DirectConnection.
1885 Sets weither the scene graph rendering of QML should clear the color buffer
1886 before it starts rendering to \a enbled.
1888 By disabling clearing of the color buffer, it is possible to do GL painting
1889 under the scene graph.
1891 The color buffer is cleared by default.
1893 \sa beforeRendering()
1896 void QQuickCanvas::setClearBeforeRendering(bool enabled)
1899 d->clearBeforeRendering = enabled;
1905 Returns weither clearing of the color buffer is done before rendering or not.
1908 bool QQuickCanvas::clearBeforeRendering() const
1910 Q_D(const QQuickCanvas);
1911 return d->clearBeforeRendering;
1917 Creates a new QSGTexture from the supplied \a image. If the image has an
1918 alpha channel, the corresponding texture will have an alpha channel.
1920 The caller of the function is responsible for deleting the returned texture.
1921 The actual GL texture will be deleted when the texture object is deleted.
1923 \warning This function will return 0 if the scene graph has not yet been
1926 This function can be called both from the GUI thread and the rendering thread.
1928 \sa sceneGraphInitialized()
1931 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
1933 Q_D(const QQuickCanvas);
1934 if (d->context && d->context->isReady())
1935 return d->context->createTexture(image);
1943 Creates a new QSGTexture object from an existing GL texture \a id.
1945 The caller of the function is responsible for deleting the returned texture.
1947 Use \a options to customize the texture attributes.
1949 \warning This function will return 0 if the scenegraph has not yet been
1952 \sa sceneGraphInitialized()
1954 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
1956 Q_D(const QQuickCanvas);
1957 if (d->context && d->context->isReady()) {
1958 QSGPlainTexture *texture = new QSGPlainTexture();
1959 texture->setTextureId(id);
1960 texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
1961 texture->setHasMipmaps(options & TextureHasMipmaps);
1962 texture->setOwnsTexture(options & TextureOwnsGLTexture);
1963 texture->setTextureSize(size);
1971 Sets the color used to clear the opengl context to \a color.
1973 Setting the clear color has no effect when clearing is disabled.
1975 \sa setClearBeforeRendering()
1978 void QQuickCanvas::setClearColor(const QColor &color)
1981 if (color == d->clearColor)
1984 d->clearColor = color;
1985 emit clearColorChanged(color);
1991 Returns the color used to clear the opengl context.
1994 QColor QQuickCanvas::clearColor() const
1996 return d_func()->clearColor;
2001 #include "moc_qquickcanvas.cpp"