Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickwindow.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qquickwindow.h"
7
8#include "qquickitem.h"
9#include "qquickitem_p.h"
14
15#include <QtQuick/private/qsgrenderer_p.h>
16#include <QtQuick/private/qsgplaintexture_p.h>
17#include <QtQuick/private/qquickpointerhandler_p.h>
18#include <QtQuick/private/qquickpointerhandler_p_p.h>
19#include <QtQuick/private/qquicktaphandler_p.h>
20#include <QtQuick/private/qsgnode_p.h>
21#include <private/qsgrenderloop_p.h>
22#include <private/qsgrhisupport_p.h>
23#include <private/qquickrendercontrol_p.h>
24#include <private/qquickanimatorcontroller_p.h>
25#include <private/qquickprofiler_p.h>
26#include <private/qquicktextinterface_p.h>
27
28#include <private/qguiapplication_p.h>
29
30#include <private/qabstractanimation_p.h>
31
32#include <QtGui/qpainter.h>
33#include <QtGui/qevent.h>
34#include <QtGui/qmatrix4x4.h>
35#include <QtGui/private/qevent_p.h>
36#include <QtGui/private/qpointingdevice_p.h>
37#include <QtCore/qvarlengtharray.h>
38#include <QtCore/qabstractanimation.h>
39#include <QtCore/QLibraryInfo>
40#include <QtCore/QRunnable>
41#include <QtQml/qqmlincubator.h>
42#include <QtQml/qqmlinfo.h>
43#include <QtQml/private/qqmlmetatype_p.h>
44
45#include <QtQuick/private/qquickpixmap_p.h>
46
47#include <private/qqmldebugserviceinterfaces_p.h>
48#include <private/qqmldebugconnector_p.h>
49#include <private/qsgdefaultrendercontext_p.h>
50#include <private/qsgsoftwarerenderer_p.h>
51#if QT_CONFIG(opengl)
52#include <private/qopengl_p.h>
53#include <QOpenGLContext>
54#endif
55#ifndef QT_NO_DEBUG_STREAM
56#include <private/qdebug_p.h>
57#endif
58#include <QtCore/qpointer.h>
59
60#include <rhi/qrhi.h>
61
62#include <algorithm>
63#include <utility>
64#include <mutex>
65
67
68Q_STATIC_LOGGING_CATEGORY(lcDirty, "qt.quick.dirty")
69Q_LOGGING_CATEGORY(lcQuickWindow, "qt.quick.window")
70
71bool QQuickWindowPrivate::defaultAlphaBuffer = false;
72
73#if defined(QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
74QQuickWindow::TextRenderType QQuickWindowPrivate::textRenderType = QQuickWindow::QT_QUICK_DEFAULT_TEXT_RENDER_TYPE;
75#else
76QQuickWindow::TextRenderType QQuickWindowPrivate::textRenderType = QQuickWindow::QtTextRendering;
77#endif
78
80{
82
83public:
96
97protected:
99 {
101 m_timer = 0;
102 incubate();
103 }
104
106 if (m_timer == 0) {
107 // Wait for a while before processing the next batch. Using a
108 // timer to avoid starvation of system events.
110 }
111 }
112
113public slots:
114 void incubate() {
118 } else {
122 }
123 }
124 }
125
127
128protected:
134
135private:
137 int m_incubation_time;
138 int m_timer;
139};
140
141#if QT_CONFIG(accessibility)
142/*!
143 Returns an accessibility interface for this window, or 0 if such an
144 interface cannot be created.
145*/
146QAccessibleInterface *QQuickWindow::accessibleRoot() const
147{
148 return QAccessible::queryAccessibleInterface(const_cast<QQuickWindow*>(this));
149}
150#endif
151
152
153/*
154Focus behavior
155==============
156
157Prior to being added to a valid window items can set and clear focus with no
158effect. Only once items are added to a window (by way of having a parent set that
159already belongs to a window) do the focus rules apply. Focus goes back to
160having no effect if an item is removed from a window.
161
162When an item is moved into a new focus scope (either being added to a window
163for the first time, or having its parent changed), if the focus scope already has
164a scope focused item that takes precedence over the item being added. Otherwise,
165the focus of the added tree is used. In the case of a tree of items being
166added to a window for the first time, which may have a conflicted focus state (two
167or more items in one scope having focus set), the same rule is applied item by item -
168thus the first item that has focus will get it (assuming the scope doesn't already
169have a scope focused item), and the other items will have their focus cleared.
170*/
171
172QQuickRootItem::QQuickRootItem()
173{
174 // child items with ItemObservesViewport can treat the window's content item
175 // as the ultimate viewport: avoid populating SG nodes that fall outside
176 setFlag(ItemIsViewport);
177}
178
179/*! \reimp */
180void QQuickWindow::exposeEvent(QExposeEvent *)
181{
182 Q_D(QQuickWindow);
183 if (d->windowManager)
184 d->windowManager->exposureChanged(this);
185}
186
187/*! \reimp */
188void QQuickWindow::resizeEvent(QResizeEvent *ev)
189{
190 Q_D(QQuickWindow);
191 if (d->contentItem)
192 d->contentItem->setSize(ev->size());
193 if (d->windowManager)
194 d->windowManager->resize(this);
195}
196
197/*! \reimp */
198void QQuickWindow::showEvent(QShowEvent *)
199{
200 Q_D(QQuickWindow);
201 if (d->windowManager)
202 d->windowManager->show(this);
203}
204
205/*! \reimp */
206void QQuickWindow::hideEvent(QHideEvent *)
207{
208 Q_D(QQuickWindow);
209 if (auto da = d->deliveryAgentPrivate())
210 da->handleWindowHidden(this);
211 if (d->windowManager)
212 d->windowManager->hide(this);
213}
214
215/*! \reimp */
216void QQuickWindow::closeEvent(QCloseEvent *e)
217{
218 QQuickCloseEvent qev;
219 qev.setAccepted(e->isAccepted());
220 emit closing(&qev);
221 e->setAccepted(qev.isAccepted());
222}
223
224/*! \reimp */
225void QQuickWindow::focusOutEvent(QFocusEvent *ev)
226{
227 Q_D(QQuickWindow);
228 if (d->contentItem)
229 d->contentItem->setFocus(false, ev->reason());
230}
231
232/*! \reimp */
233void QQuickWindow::focusInEvent(QFocusEvent *ev)
234{
235 Q_D(QQuickWindow);
236 if (d->inDestructor)
237 return;
238 if (d->contentItem)
239 d->contentItem->setFocus(true, ev->reason());
240 if (auto da = d->deliveryAgentPrivate())
241 da->updateFocusItemTransform();
242}
243
244#if QT_CONFIG(im)
245static bool transformDirtyOnItemOrAncestor(const QQuickItem *item)
246{
247 while (item) {
248 if (QQuickItemPrivate::get(item)->dirtyAttributes & (
249 QQuickItemPrivate::TransformOrigin |
250 QQuickItemPrivate::Transform |
251 QQuickItemPrivate::BasicTransform |
252 QQuickItemPrivate::Position |
253 QQuickItemPrivate::Size |
254 QQuickItemPrivate::ParentChanged |
255 QQuickItemPrivate::Clip)) {
256 return true;
257 }
258 item = item->parentItem();
259 }
260 return false;
261}
262#endif
263
264/*!
265 * \internal
266
267 A "polish loop" can occur inside QQuickWindowPrivate::polishItems(). It is when an item calls
268 polish() on an(other?) item from updatePolish(). If this anomaly happens repeatedly and without
269 interruption (of a well-behaved updatePolish() that doesn't call polish()), it is a strong
270 indication that we are heading towards an infinite polish loop. A polish loop is not a bug in
271 Qt Quick - it is a bug caused by ill-behaved items put in the scene.
272
273 We can detect this sequence of polish loops easily, since the
274 QQuickWindowPrivate::itemsToPolish is basically a stack: polish() will push to it, and
275 polishItems() will pop from it.
276 Therefore if updatePolish() calls polish(), the immediate next item polishItems() processes is
277 the item that was polished by the previous call to updatePolish().
278 We therefore just need to count the number of polish loops we detected in _sequence_.
279*/
281{
282 PolishLoopDetector(const QList<QQuickItem*> &itemsToPolish)
284 {
285 }
286
287 /*
288 * returns true when it detected a likely infinite loop
289 * (suggests it should abort the polish loop)
290 **/
291 bool check(QQuickItem *item, int itemsRemainingBeforeUpdatePolish)
292 {
293 if (itemsToPolish.size() > itemsRemainingBeforeUpdatePolish) {
294 // Detected potential polish loop.
296 if (numPolishLoopsInSequence == 10000) {
297 // We have looped 10,000 times without actually reducing the list of items to
298 // polish, give up for now.
299 // This is not a fix, just a remedy so that the application can be somewhat
300 // responsive.
302 return true;
303 }
305 // Start to warn about polish loop after 1000 consecutive polish loops
306 // Show the 5 next items involved in the polish loop.
307 // (most likely they will be the same 5 items...)
308 QQuickItem *guiltyItem = itemsToPolish.last();
309 qmlWarning(item) << "possible QQuickItem::polish() loop";
310
311 auto typeAndObjectName = [](QQuickItem *item) {
312 QString typeName = QQmlMetaType::prettyTypeName(item);
313 QString objName = item->objectName();
314 if (!objName.isNull())
315 return QLatin1String("%1(%2)").arg(typeName, objName);
316 return typeName;
317 };
318
319 qmlWarning(guiltyItem) << typeAndObjectName(guiltyItem)
320 << " called polish() inside updatePolish() of " << typeAndObjectName(item);
321 }
322 } else {
324 }
325 return false;
326 }
327 const QList<QQuickItem*> &itemsToPolish; // Just a ref to the one in polishItems()
329};
330
331void QQuickWindowPrivate::polishItems()
332{
333 // An item can trigger polish on another item, or itself for that matter,
334 // during its updatePolish() call. Because of this, we cannot simply
335 // iterate through the set, we must continue pulling items out until it
336 // is empty.
337 // In the case where polish is called from updatePolish() either directly
338 // or indirectly, we use a PolishLoopDetector to determine if a warning should
339 // be printed to the user.
340
341 PolishLoopDetector polishLoopDetector(itemsToPolish);
342 while (!itemsToPolish.isEmpty()) {
343 QQuickItem *item = itemsToPolish.takeLast();
344 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
345 itemPrivate->polishScheduled = false;
346 const int itemsRemaining = itemsToPolish.size();
347 itemPrivate->updatePolish();
348 item->updatePolish();
349 if (polishLoopDetector.check(item, itemsRemaining) == true)
350 break;
351 }
352
353#if QT_CONFIG(im)
354 if (QQuickItem *focusItem = q_func()->activeFocusItem()) {
355 // If the current focus item, or any of its anchestors, has changed location
356 // inside the window, we need inform IM about it. This to ensure that overlays
357 // such as selection handles will be updated.
358 const bool isActiveFocusItem = (focusItem == QGuiApplication::focusObject());
359 const bool hasImEnabled = focusItem->inputMethodQuery(Qt::ImEnabled).toBool();
360 if (isActiveFocusItem && hasImEnabled && transformDirtyOnItemOrAncestor(focusItem))
361 deliveryAgentPrivate()->updateFocusItemTransform();
362 }
363#endif
364
365 if (needsChildWindowStackingOrderUpdate) {
366 updateChildWindowStackingOrder();
367 needsChildWindowStackingOrderUpdate = false;
368 }
369}
370
371/*!
372 * Schedules the window to render another frame.
373 *
374 * Calling QQuickWindow::update() differs from QQuickItem::update() in that
375 * it always triggers a repaint, regardless of changes in the underlying
376 * scene graph or not.
377 */
378void QQuickWindow::update()
379{
380 Q_D(QQuickWindow);
381 if (d->windowManager)
382 d->windowManager->update(this);
383 else if (d->renderControl)
384 QQuickRenderControlPrivate::get(d->renderControl)->update();
385}
386
387static void updatePixelRatioHelper(QQuickItem *item, float pixelRatio)
388{
389 if (item->flags() & QQuickItem::ItemHasContents) {
390 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
391 itemPrivate->itemChange(QQuickItem::ItemDevicePixelRatioHasChanged, pixelRatio);
392 }
393
394 QList <QQuickItem *> items = item->childItems();
395 for (int i = 0; i < items.size(); ++i)
396 updatePixelRatioHelper(items.at(i), pixelRatio);
397}
398
399void QQuickWindow::physicalDpiChanged()
400{
401 Q_D(QQuickWindow);
402 const qreal newPixelRatio = effectiveDevicePixelRatio();
403 if (qFuzzyCompare(newPixelRatio, d->lastReportedItemDevicePixelRatio))
404 return;
405 d->lastReportedItemDevicePixelRatio = newPixelRatio;
406 if (d->contentItem)
407 updatePixelRatioHelper(d->contentItem, newPixelRatio);
408 d->forcePolish();
409 emit devicePixelRatioChanged();
410}
411
412void QQuickWindow::handleFontDatabaseChanged()
413{
414 Q_D(QQuickWindow);
415 d->pendingFontUpdate = true;
416}
417
418void forcePolishHelper(QQuickItem *item)
419{
420 if (item->flags() & QQuickItem::ItemHasContents) {
421 item->polish();
422 }
423
424 QList <QQuickItem *> items = item->childItems();
425 for (int i=0; i<items.size(); ++i)
426 forcePolishHelper(items.at(i));
427}
428
429void QQuickWindow::handleScreenChanged(QScreen *screen)
430{
431 Q_D(QQuickWindow);
432 Q_UNUSED(screen);
433 d->forcePolish();
434}
435
436/*!
437 Schedules polish events on all items in the scene.
438*/
439void QQuickWindowPrivate::forcePolish()
440{
441 Q_Q(QQuickWindow);
442 if (!q->screen())
443 return;
444 forcePolishHelper(contentItem);
445}
446
447void forceUpdate(QQuickItem *item)
448{
449 if (item->flags() & QQuickItem::ItemHasContents)
450 item->update();
451 QQuickItemPrivate::get(item)->dirty(QQuickItemPrivate::ChildrenUpdateMask);
452
453 QList <QQuickItem *> items = item->childItems();
454 for (int i=0; i<items.size(); ++i)
455 forceUpdate(items.at(i));
456}
457
458void QQuickWindowRenderTarget::reset(QRhi *rhi, ResetFlags flags)
459{
460 if (rhi) {
461 if (rt.owns)
462 delete rt.renderTarget;
463
464 delete res.texture;
465 delete res.renderBuffer;
466 delete res.rpDesc;
467 }
468
469 rt = {};
470 res = {};
471
472 if (!flags.testFlag(ResetFlag::KeepImplicitBuffers))
473 implicitBuffers.reset(rhi);
474
475 if (sw.owns)
476 delete sw.paintDevice;
477
478 sw = {};
479}
480
482{
483 if (rhi) {
484 delete depthStencil;
485 delete depthStencilTexture;
486 delete multisampleTexture;
487 }
488 *this = {};
489}
490
491void QQuickWindowPrivate::invalidateFontData(QQuickItem *item)
492{
493 QQuickTextInterface *textItem = qobject_cast<QQuickTextInterface *>(item);
494 if (textItem != nullptr)
495 textItem->invalidate();
496
497 const QList<QQuickItem *> children = item->childItems();
498 for (QQuickItem *child : children)
499 invalidateFontData(child);
500}
501
502void QQuickWindowPrivate::ensureCustomRenderTarget()
503{
504 // resolve() can be expensive when importing an existing native texture, so
505 // it is important to only do it when the QQuickRenderTarget was really changed.
506 if (!redirect.renderTargetDirty)
507 return;
508
509 redirect.renderTargetDirty = false;
510
511 redirect.rt.reset(rhi, QQuickWindowRenderTarget::ResetFlag::KeepImplicitBuffers);
512
513 if (!QQuickRenderTargetPrivate::get(&customRenderTarget)->resolve(rhi, &redirect.rt)) {
514 qWarning("Failed to set up render target redirection for QQuickWindow");
515 redirect.rt.reset(rhi);
516 }
517}
518
519void QQuickWindowPrivate::setCustomCommandBuffer(QRhiCommandBuffer *cb)
520{
521 // ownership not transferred
522 redirect.commandBuffer = cb;
523}
524
525void QQuickWindowPrivate::syncSceneGraph()
526{
527 Q_Q(QQuickWindow);
528
529 const bool wasRtDirty = redirect.renderTargetDirty;
530 ensureCustomRenderTarget();
531
532 QRhiCommandBuffer *cb = nullptr;
533 if (rhi) {
534 if (redirect.commandBuffer)
535 cb = redirect.commandBuffer;
536 else
537 cb = swapchain->currentFrameCommandBuffer();
538 }
539 context->prepareSync(q->effectiveDevicePixelRatio(), cb, graphicsConfig);
540
541 animationController->beforeNodeSync();
542
543 emit q->beforeSynchronizing();
544 runAndClearJobs(&beforeSynchronizingJobs);
545
546 if (pendingFontUpdate) {
547 QFont::cleanup();
548 invalidateFontData(contentItem);
549 context->invalidateGlyphCaches();
550 }
551
552 if (Q_UNLIKELY(!renderer)) {
553 forceUpdate(contentItem);
554
555 QSGRootNode *rootNode = new QSGRootNode;
556 rootNode->appendChildNode(QQuickItemPrivate::get(contentItem)->itemNode());
557 const bool useDepth = graphicsConfig.isDepthBufferEnabledFor2D();
558 const QSGRendererInterface::RenderMode renderMode = useDepth ? QSGRendererInterface::RenderMode2D
559 : QSGRendererInterface::RenderMode2DNoDepthBuffer;
560 renderer = context->createRenderer(renderMode);
561 renderer->setRootNode(rootNode);
562 } else if (Q_UNLIKELY(wasRtDirty)
563 && q->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
564 auto softwareRenderer = static_cast<QSGSoftwareRenderer *>(renderer);
565 softwareRenderer->markDirty();
566 }
567
568 updateDirtyNodes();
569
570 animationController->afterNodeSync();
571
572 renderer->setClearColor(clearColor);
573
574 renderer->setVisualizationMode(visualizationMode);
575
576 if (pendingFontUpdate) {
577 context->flushGlyphCaches();
578 pendingFontUpdate = false;
579 }
580
581 emit q->afterSynchronizing();
582 runAndClearJobs(&afterSynchronizingJobs);
583}
584
585void QQuickWindowPrivate::emitBeforeRenderPassRecording(void *ud)
586{
587 QQuickWindow *w = reinterpret_cast<QQuickWindow *>(ud);
588 emit w->beforeRenderPassRecording();
589}
590
591void QQuickWindowPrivate::emitAfterRenderPassRecording(void *ud)
592{
593 QQuickWindow *w = reinterpret_cast<QQuickWindow *>(ud);
594 emit w->afterRenderPassRecording();
595}
596
597int QQuickWindowPrivate::multiViewCount()
598{
599 if (rhi) {
600 ensureCustomRenderTarget();
601 if (redirect.rt.rt.renderTarget)
602 return redirect.rt.rt.multiViewCount;
603 }
604
605 // Note that on QRhi level 0 and 1 are often used interchangeably, as both mean
606 // no-multiview. Here in Qt Quick let's always use 1 as the default
607 // (no-multiview), so that higher layers (effects, materials) do not need to
608 // handle both 0 and 1, only 1.
609 return 1;
610}
611
612QRhiRenderTarget *QQuickWindowPrivate::activeCustomRhiRenderTarget()
613{
614 if (rhi) {
615 ensureCustomRenderTarget();
616 return redirect.rt.rt.renderTarget;
617 }
618 return nullptr;
619}
620
621void QQuickWindowPrivate::renderSceneGraph()
622{
623 Q_Q(QQuickWindow);
624 if (!renderer)
625 return;
626
627 ensureCustomRenderTarget();
628
629 QSGRenderTarget sgRenderTarget;
630 if (rhi) {
631 QRhiRenderTarget *rt;
632 QRhiRenderPassDescriptor *rp;
633 QRhiCommandBuffer *cb;
634 if (redirect.rt.rt.renderTarget) {
635 rt = redirect.rt.rt.renderTarget;
636 rp = rt->renderPassDescriptor();
637 if (!rp) {
638 qWarning("Custom render target is set but no renderpass descriptor has been provided.");
639 return;
640 }
641 cb = redirect.commandBuffer;
642 if (!cb) {
643 qWarning("Custom render target is set but no command buffer has been provided.");
644 return;
645 }
646 } else {
647 if (!swapchain) {
648 qWarning("QQuickWindow: No render target (neither swapchain nor custom target was provided)");
649 return;
650 }
651 rt = swapchain->currentFrameRenderTarget();
652 rp = rpDescForSwapchain;
653 cb = swapchain->currentFrameCommandBuffer();
654 }
655 sgRenderTarget = QSGRenderTarget(rt, rp, cb);
656 sgRenderTarget.multiViewCount = multiViewCount();
657 } else {
658 sgRenderTarget = QSGRenderTarget(redirect.rt.sw.paintDevice);
659 }
660
661 context->beginNextFrame(renderer,
662 sgRenderTarget,
663 emitBeforeRenderPassRecording,
664 emitAfterRenderPassRecording,
665 q);
666
667 animationController->advance();
668 emit q->beforeRendering();
669 runAndClearJobs(&beforeRenderingJobs);
670
671 const qreal devicePixelRatio = q->effectiveDevicePixelRatio();
672 QSize pixelSize;
673 if (redirect.rt.rt.renderTarget)
674 pixelSize = redirect.rt.rt.renderTarget->pixelSize();
675 else if (redirect.rt.sw.paintDevice)
676 pixelSize = QSize(redirect.rt.sw.paintDevice->width(), redirect.rt.sw.paintDevice->height());
677 else if (rhi)
678 pixelSize = swapchain->currentPixelSize();
679 else // software or other backend
680 pixelSize = q->size() * devicePixelRatio;
681
682 renderer->setDevicePixelRatio(devicePixelRatio);
683 renderer->setDeviceRect(QRect(QPoint(0, 0), pixelSize));
684 renderer->setViewportRect(QRect(QPoint(0, 0), pixelSize));
685
686 QSGAbstractRenderer::MatrixTransformFlags matrixFlags;
687 bool flipY = rhi ? !rhi->isYUpInNDC() : false;
688 if (!customRenderTarget.isNull() && customRenderTarget.mirrorVertically())
689 flipY = !flipY;
690 if (flipY)
691 matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
692
693 const QRectF rect(QPointF(0, 0), pixelSize / devicePixelRatio);
694 renderer->setProjectionMatrixToRect(rect, matrixFlags, rhi && !rhi->isYUpInNDC());
695
696 context->renderNextFrame(renderer);
697
698 emit q->afterRendering();
699 runAndClearJobs(&afterRenderingJobs);
700
701 context->endNextFrame(renderer);
702
703 if (renderer && renderer->hasVisualizationModeWithContinuousUpdate()) {
704 // For the overdraw visualizer. This update is not urgent so avoid a
705 // direct update() call, this is only here to keep the overdraw
706 // visualization box rotating even when the scene is static.
707 QCoreApplication::postEvent(q, new QEvent(QEvent::Type(FullUpdateRequest)));
708 }
709}
710
711QQuickWindowPrivate::QQuickWindowPrivate()
712 : contentItem(nullptr)
713 , dirtyItemList(nullptr)
714 , lastReportedItemDevicePixelRatio(0)
715 , context(nullptr)
716 , renderer(nullptr)
717 , windowManager(nullptr)
718 , renderControl(nullptr)
719 , clearColor(Qt::white)
720 , persistentGraphics(true)
721 , persistentSceneGraph(true)
722 , inDestructor(false)
723 , incubationController(nullptr)
724 , hasActiveSwapchain(false)
725 , hasRenderableSwapchain(false)
726 , swapchainJustBecameRenderable(false)
727 , updatesEnabled(true)
728{
729}
730
731QQuickWindowPrivate::~QQuickWindowPrivate()
732{
733#ifdef QT_BUILD_INTERNAL
734 qCDebug(lcQuickWindow, "lifetime total, in all windows: constructed %d QQuickItems, %d ExtraData (%d%%)",
735 QQuickItemPrivate::item_counter, QQuickItemPrivate::itemExtra_counter,
736 QQuickItemPrivate::itemExtra_counter * 100 / QQuickItemPrivate::item_counter);
737 qCDebug(lcQuickWindow, "event-handling items fully within parent bounds: %d (%d%%)",
738 QQuickItemPrivate::eventHandlingChildrenWithinBounds_counter,
739 QQuickItemPrivate::eventHandlingChildrenWithinBounds_counter * 100 / QQuickItemPrivate::item_counter);
740 qCDebug(lcQuickWindow, "transform accessor calls: itemToParent %lld itemToWindow %lld windowToItem %lld; skipped due to effectiveClipping: %lld",
741 QQuickItemPrivate::itemToParentTransform_counter,
742 QQuickItemPrivate::itemToWindowTransform_counter,
743 QQuickItemPrivate::windowToItemTransform_counter,
744 QQuickItemPrivate::effectiveClippingSkips_counter);
745#endif
746 inDestructor = true;
747 redirect.rt.reset(rhi);
748 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
749 service->removeWindow(q_func());
750 deliveryAgent = nullptr;
751}
752
753void QQuickWindowPrivate::setPalette(QQuickPalette* palette)
754{
755 if (windowPaletteRef == palette)
756 return;
757
758 if (windowPaletteRef)
759 disconnect(windowPaletteRef, &QQuickPalette::changed, this, &QQuickWindowPrivate::updateWindowPalette);
760 windowPaletteRef = palette;
761 updateWindowPalette();
762 if (windowPaletteRef)
763 connect(windowPaletteRef, &QQuickPalette::changed, this, &QQuickWindowPrivate::updateWindowPalette);
764}
765
766void QQuickWindowPrivate::updateWindowPalette()
767{
768 QQuickPaletteProviderPrivateBase::setPalette(windowPaletteRef);
769}
770
771void QQuickWindowPrivate::updateChildrenPalettes(const QPalette &parentPalette)
772{
773 Q_Q(QQuickWindow);
774 if (auto root = q->contentItem()) {
775 const auto children = root->childItems();
776 for (auto *child : children) {
777 QQuickItemPrivate::get(child)->inheritPalette(parentPalette);
778 }
779 }
780}
781
782void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
783{
784 q_ptr = c;
785
786
787 Q_Q(QQuickWindow);
788
789 contentItem = new QQuickRootItem;
790 contentItem->setObjectName(q->objectName());
791 QQml_setParent_noEvent(contentItem, c);
792 QQmlEngine::setObjectOwnership(contentItem, QQmlEngine::CppOwnership);
793 QQuickItemPrivate *contentItemPrivate = QQuickItemPrivate::get(contentItem);
794 contentItemPrivate->window = q;
795 contentItemPrivate->windowRefCount = 1;
796 contentItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
797 contentItem->setSize(q->size());
798 deliveryAgent = new QQuickDeliveryAgent(contentItem);
799
800 visualizationMode = qgetenv("QSG_VISUALIZE");
801 renderControl = control;
802 if (renderControl)
803 QQuickRenderControlPrivate::get(renderControl)->window = q;
804
805 if (!renderControl)
806 windowManager = QSGRenderLoop::instance();
807
808 Q_ASSERT(windowManager || renderControl);
809
810 QObject::connect(static_cast<QGuiApplication *>(QGuiApplication::instance()),
811 &QGuiApplication::fontDatabaseChanged,
812 q,
813 &QQuickWindow::handleFontDatabaseChanged);
814
815 if (q->screen()) {
816 lastReportedItemDevicePixelRatio = q->effectiveDevicePixelRatio();
817 }
818
819 QSGContext *sg;
820 if (renderControl) {
821 QQuickRenderControlPrivate *renderControlPriv = QQuickRenderControlPrivate::get(renderControl);
822 sg = renderControlPriv->sg;
823 context = renderControlPriv->rc;
824 } else {
825 windowManager->addWindow(q);
826 sg = windowManager->sceneGraphContext();
827 context = windowManager->createRenderContext(sg);
828 }
829
830 q->setSurfaceType(windowManager ? windowManager->windowSurfaceType() : QSurface::OpenGLSurface);
831 q->setFormat(sg->defaultSurfaceFormat());
832 // When using Vulkan, associating a scenegraph-managed QVulkanInstance with
833 // the window (but only when not using renderControl) is deferred to
834 // QSGRhiSupport::createRhi(). This allows applications to set up their own
835 // QVulkanInstance and set that on the window, if they wish to.
836
837 animationController.reset(new QQuickAnimatorController(q));
838
839 connections = {
840 QObject::connect(context, &QSGRenderContext::initialized, q, &QQuickWindow::sceneGraphInitialized, Qt::DirectConnection),
841 QObject::connect(context, &QSGRenderContext::invalidated, q, &QQuickWindow::sceneGraphInvalidated, Qt::DirectConnection),
842 QObject::connect(context, &QSGRenderContext::invalidated, q, &QQuickWindow::cleanupSceneGraph, Qt::DirectConnection),
843
844 QObject::connect(q, &QQuickWindow::focusObjectChanged, q, &QQuickWindow::activeFocusItemChanged),
845 QObject::connect(q, &QQuickWindow::screenChanged, q, &QQuickWindow::handleScreenChanged),
846 QObject::connect(qApp, &QGuiApplication::applicationStateChanged, q, &QQuickWindow::handleApplicationStateChanged),
847 QObject::connect(q, &QQuickWindow::frameSwapped, q, &QQuickWindow::runJobsAfterSwap, Qt::DirectConnection),
848 };
849
850 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
851 service->addWindow(q);
852}
853
854void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state)
855{
856 Q_D(QQuickWindow);
857 if (state != Qt::ApplicationActive && d->contentItem) {
858 auto da = d->deliveryAgentPrivate();
859 Q_ASSERT(da);
860 da->handleWindowDeactivate(this);
861 }
862}
863
864/*!
865 \property QQuickWindow::data
866 \internal
867*/
868
869QQmlListProperty<QObject> QQuickWindowPrivate::data()
870{
871 QQmlListProperty<QObject> ret;
872
873 ret.object = q_func();
874 ret.append = QQuickWindowPrivate::data_append;
875 ret.count = QQuickWindowPrivate::data_count;
876 ret.at = QQuickWindowPrivate::data_at;
877 ret.clear = QQuickWindowPrivate::data_clear;
878 // replace is not supported by QQuickItem. Don't synthesize it.
879 ret.removeLast = QQuickWindowPrivate::data_removeLast;
880
881 return ret;
882}
883
884void QQuickWindowPrivate::dirtyItem(QQuickItem *item, bool maySkipUpdate)
885{
886 Q_Q(QQuickWindow);
887
888 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
889 if (itemPriv->dirtyAttributes & QQuickItemPrivate::ChildrenStackingChanged)
890 needsChildWindowStackingOrderUpdate = true;
891
892 if (!maySkipUpdate
893 || (itemPriv->effectiveVisible || item->isTextureProvider()
894 || (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount > 0)))
895 q->maybeUpdate();
896}
897
898/*!
899 \deprecated Use QPointerEvent::exclusiveGrabber().
900 Returns the item which currently has the mouse grab.
901*/
902QQuickItem *QQuickWindow::mouseGrabberItem() const
903{
904 Q_D(const QQuickWindow);
905 auto da = const_cast<QQuickWindowPrivate *>(d)->deliveryAgentPrivate();
906 Q_ASSERT(da);
907 // The normal use case is to call this function while an event is being delivered;
908 // but if the caller knows about the event, it should call QPointerEvent::exclusiveGrabber() instead.
909 if (auto epd = da->mousePointData())
910 return qmlobject_cast<QQuickItem *>(epd->exclusiveGrabber);
911
912 if (Q_LIKELY(d->deliveryAgentPrivate()->eventsInDelivery.isEmpty()))
913 // mousePointData() checked that already: it's one reason epd can be null
914 qCDebug(lcMouse, "mouse grabber ambiguous: no event is currently being delivered");
915 // If no event is being delivered, we can return "the mouse" grabber,
916 // but in general there could be more than one mouse, could be only a touchscreen etc.
917 // That's why this function is obsolete.
918 return qmlobject_cast<QQuickItem *>(QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice())->
919 firstPointExclusiveGrabber());
920}
921
922void QQuickWindowPrivate::cleanup(QSGNode *n)
923{
924 Q_Q(QQuickWindow);
925
926 Q_ASSERT(!cleanupNodeList.contains(n));
927 cleanupNodeList.append(n);
928 q->maybeUpdate();
929}
930
931/*!
932 \qmltype Window
933 \nativetype QQuickWindow
934 \inqmlmodule QtQuick
935 \ingroup qtquick-visual
936 \brief Creates a new top-level window.
937
938 The Window object creates a new top-level window for a Qt Quick scene. It automatically sets up the
939 window for use with \c {QtQuick} graphical types.
940
941 A Window can be declared inside an Item or inside another Window, in which
942 case the inner Window will automatically become "transient for" the outer
943 Window, with the outer Window as its \l transientParent. Most platforms will
944 show the Window centered upon the outer window in this case, and there may be
945 other platform-dependent behaviors, depending also on the \l flags. If the nested
946 window is intended to be a dialog in your application, you should also set \l flags
947 to \c Qt.Dialog, because some window managers will not provide the centering behavior
948 without that flag.
949
950 You can also declare multiple windows inside a top-level \l QtObject, in which
951 case the windows will have no transient relationship.
952
953 Alternatively you can set or bind \l x and \l y to position the Window
954 explicitly on the screen.
955
956 When the user attempts to close a window, the \l closing signal will be
957 emitted. You can force the window to stay open (for example to prompt the
958 user to save changes) by writing an \c onClosing handler that sets
959 \c {close.accepted = false} unless it's safe to close the window (for example,
960 because there are no more unsaved changes).
961
962 \code
963 onClosing: (close) => {
964 if (document.changed) {
965 close.accepted = false
966 confirmExitPopup.open()
967 }
968 }
969
970 // The confirmExitPopup allows user to save or discard the document,
971 // or to cancel the closing.
972 \endcode
973
974 \section1 Styling
975
976 As with all visual types in Qt Quick, Window supports
977 \l {palette}{palettes}. However, as with types like \l Text, Window does
978 not use palettes by default. For example, to change the background color
979 of the window when the operating system's theme changes, the \l color must
980 be set:
981
982 \snippet qml/windowPalette.qml declaration-and-color
983 \codeline
984 \snippet qml/windowPalette.qml text-item
985 \snippet qml/windowPalette.qml closing-brace
986
987 Use \l {ApplicationWindow} (and \l {Label}) from \l {Qt Quick Controls}
988 instead of Window to get automatic styling.
989*/
990
991/*!
992 \class QQuickWindow
993 \since 5.0
994
995 \inmodule QtQuick
996
997 \brief The QQuickWindow class provides the window for displaying a graphical QML scene.
998
999 QQuickWindow provides the graphical scene management needed to interact with and display
1000 a scene of QQuickItems.
1001
1002 A QQuickWindow always has a single invisible root item. To add items to this window,
1003 reparent the items to the root item or to an existing item in the scene.
1004
1005 For easily displaying a scene from a QML file, see \l{QQuickView}.
1006
1007 \section1 Rendering
1008
1009 QQuickWindow uses a scene graph to represent what needs to be rendered.
1010 This scene graph is disconnected from the QML scene and potentially lives in
1011 another thread, depending on the platform implementation. Since the
1012 rendering scene graph lives independently from the QML scene, it can also be
1013 completely released without affecting the state of the QML scene.
1014
1015 The sceneGraphInitialized() signal is emitted on the rendering thread before
1016 the QML scene is rendered to the screen for the first time. If the rendering
1017 scene graph has been released, the signal will be emitted again before the
1018 next frame is rendered. A visible, on-screen QQuickWindow is driven
1019 internally by a \c{render loop}, of which there are multiple implementations
1020 provided in the scene graph. For details on the scene graph rendering
1021 process, see \l{Qt Quick Scene Graph}.
1022
1023 By default, a QQuickWindow renders using an accelerated 3D graphics API,
1024 such as OpenGL or Vulkan. See \l{Scene Graph Adaptations} for a detailed
1025 overview of scene graph backends and the supported graphics APIs.
1026
1027 \warning It is crucial that graphics operations and interaction with the
1028 scene graph happens exclusively on the rendering thread, primarily during
1029 the updatePaintNode() phase.
1030
1031 \warning As many of the signals related to rendering are emitted from the
1032 rendering thread, connections should be made using Qt::DirectConnection.
1033
1034 \section2 Integration with Accelerated 3D Graphics APIs
1035
1036 It is possible to integrate OpenGL, Vulkan, Metal, or Direct3D 11 calls
1037 directly into the QQuickWindow, as long as the QQuickWindow and the
1038 underlying scene graph is rendering using the same API. To access native
1039 graphics objects, such as device or context object handles, use
1040 QSGRendererInterface. An instance of QSGRendererInterface is queriable from
1041 QQuickWindow by calling rendererInterface(). The enablers for this
1042 integration are the beforeRendering(), beforeRenderPassRecording(),
1043 afterRenderPassRecording(), and related signals. These allow rendering
1044 underlays or overlays. Alternatively, QNativeInterface::QSGOpenGLTexture,
1045 QNativeInterface::QSGVulkanTexture, and other similar classes allow
1046 wrapping an existing native texture or image object in a QSGTexture that
1047 can then be used with the scene graph.
1048
1049 \section2 Rendering without Acceleration
1050
1051 A limited, pure software based rendering path is available as well. With the
1052 \c software backend, a number of Qt Quick features are not available, QML
1053 items relying on these will not be rendered at all. At the same time, this
1054 allows QQuickWindow to be functional even on systems where there is no 3D
1055 graphics API available at all. See \l{Qt Quick Software Adaptation} for more
1056 details.
1057
1058 \section2 Redirected Rendering
1059
1060 A QQuickWindow is not necessarily backed by a native window on screen. The
1061 rendering can be redirected to target a custom render target, such as a
1062 given native texture. This is achieved in combination with the
1063 QQuickRenderControl class, and functions such as setRenderTarget(),
1064 setGraphicsDevice(), and setGraphicsConfiguration().
1065
1066 In this case, the QQuickWindow represents the scene, and provides the
1067 intrastructure for rendering a frame. It will not be backed by a render
1068 loop and a native window. Instead, in this case the application drives
1069 rendering, effectively substituting for the render loops. This allows
1070 generating image sequences, rendering into textures for use in external 3D
1071 engines, or rendering Qt Quick content within a VR environment.
1072
1073 \section2 Resource Management
1074
1075 QML will try to cache images and scene graph nodes to improve performance,
1076 but in some low-memory scenarios it might be required to aggressively
1077 release these resources. The releaseResources() function can be used to
1078 force the clean up of certain resources, especially resource that are cached
1079 and can be recreated later when needed again.
1080
1081 Additionally, calling releaseResources() may result in releasing the entire
1082 scene graph and the associated graphics resources. The
1083 sceneGraphInvalidated() signal will be emitted when this happens. This
1084 behavior is controlled by the setPersistentGraphics() and
1085 setPersistentSceneGraph() functions.
1086
1087 \note All classes with QSG prefix should be used solely on the scene graph's
1088 rendering thread. See \l {Scene Graph and Rendering} for more information.
1089
1090 \section2 Exposure and Visibility
1091
1092 When a QQuickWindow instance is deliberately hidden with hide() or
1093 setVisible(false), it will stop rendering and its scene graph and graphics
1094 context might be released as well. This depends on the settings configured
1095 by setPersistentGraphics() and setPersistentSceneGraph(). The behavior in
1096 this respect is identical to explicitly calling the releaseResources()
1097 function. A window can become not exposed, in other words non-renderable, by
1098 other means as well. This depends on the platform and windowing system. For
1099 example, on Windows minimizing a window makes it stop rendering. On \macos
1100 fully obscuring a window by other windows on top triggers the same. On
1101 Linux/X11, the behavior is dependent on the window manager.
1102
1103 \section2 OpenGL Context and Surface Formats
1104
1105 While it is possible to specify a QSurfaceFormat for every QQuickWindow by
1106 calling the member function setFormat(), windows may also be created from
1107 QML by using the Window and ApplicationWindow elements. In this case there
1108 is no C++ code involved in the creation of the window instance, yet
1109 applications may still wish to set certain surface format values, for
1110 example to request a given OpenGL version or profile. Such applications can
1111 call the static function QSurfaceFormat::setDefaultFormat() at startup. The
1112 specified format will be used for all Quick windows created afterwards.
1113
1114 \section2 Vulkan Instance
1115
1116 When using Vulkan, a QQuickWindow is automatically associated with a
1117 QVulkanInstance that is created and managed internally by the scene graph.
1118 This way most applications do not need to worry about having a \c
1119 VkInstance available since it all happens automatically. In advanced cases
1120 an application may wish to create its own QVulkanInstance, in order to
1121 configure it in a specific way. That is possible as well. Calling
1122 \l{QWindow::setVulkanInstance()}{setVulkanInstance()} on the QQuickWindow
1123 right after construction, before making it visible, leads to using the
1124 application-supplied QVulkanInstance (and the underlying \c VkInstance).
1125 When redirecting via QQuickRenderControl, there is no QVulkanInstance
1126 provided automatically, but rather the application is expected to provide
1127 its own and associate it with the QQuickWindow.
1128
1129 \section2 Graphics Contexts and Devices
1130
1131 When the scene graph is initialized, which typically happens when the
1132 window becomes exposed or, in case of redirected rendering, initialization
1133 is performed \l{QQuickRenderControl::initialize()}{via
1134 QQuickRenderControl}, the context or device objects necessary for rendering
1135 are created automatically. This includes OpenGL contexts, Direct3D devices
1136 and device contexts, Vulkan and Metal devices. These are also queriable by
1137 application code afterwards via
1138 \l{QSGRendererInterface::getResource()}{QSGRendererInterface}. When using
1139 the \c basic render loop, which performs all rendering on the GUI thread,
1140 the same context or device is used with all visible QQuickWindows. The \c
1141 threaded render loop uses a dedicated context or device object for each
1142 rendering thread, and so for each QQuickWindow. With some graphics APIs,
1143 there is a degree of customizability provided via
1144 setGraphicsConfiguration(). This makes it possible, for example, to specify
1145 the list of Vulkan extensions to enable on the \c VkDevice. Alternatively,
1146 it is also possible to provide a set of existing context or device objects
1147 for use by the QQuickWindow, instead of letting it construct its own. This
1148 is achieved through setGraphicsDevice().
1149
1150 \sa QQuickView, QQuickRenderControl, QQuickRenderTarget,
1151 QQuickGraphicsDevice, QQuickGraphicsConfiguration, QSGRendererInterface
1152*/
1153
1154/*!
1155 \qmlmethod void Window::startSystemMove()
1156 \since 6.8
1157
1158 \brief Starts a system-specific move operation.
1159
1160 Starts an interactive move operation on the window using platform support.
1161 The window follows the mouse cursor until the mouse button is released.
1162
1163 Use this method instead of \c setPosition, because it allows the window manager
1164 to handle snapping, tiling, and related animations. On Wayland, \c setPosition
1165 is not supported, so this is the only way the application can influence the
1166 window’s position.
1167*/
1168
1169/*!
1170 \qmlmethod void Window::startSystemResize(Qt::Edges edges)
1171 \since 6.8
1172
1173 \brief Starts a system-specific resize operation.
1174
1175 Starts an interactive resize operation on the window using platform support.
1176 The specified edge follows the mouse cursor while dragging.
1177
1178 Use this method instead of \c setGeometry, because it allows the window manager
1179 to handle snapping and resize animations when resizing to screen edges.
1180
1181 \a edges must be a single edge or a combination of two adjacent edges (a corner).
1182 Other values are not allowed.
1183*/
1184
1185/*!
1186 Constructs a window for displaying a QML scene with parent window \a parent.
1187*/
1188QQuickWindow::QQuickWindow(QWindow *parent)
1189 : QQuickWindow(*new QQuickWindowPrivate, parent)
1190{
1191}
1192
1193
1194
1195/*!
1196 \internal
1197*/
1198QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent)
1199 : QWindow(dd, parent)
1200{
1201 Q_D(QQuickWindow);
1202 d->init(this);
1203}
1204
1205/*!
1206 Constructs a window for displaying a QML scene, whose rendering will
1207 be controlled by the \a control object.
1208 Please refer to QQuickRenderControl's documentation for more information.
1209
1210 \since 5.4
1211*/
1212QQuickWindow::QQuickWindow(QQuickRenderControl *control)
1213 : QWindow(*(new QQuickWindowPrivate), nullptr)
1214{
1215 Q_D(QQuickWindow);
1216 d->init(this, control);
1217}
1218
1219/*!
1220 \internal
1221*/
1222QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control)
1223 : QWindow(dd, nullptr)
1224{
1225 Q_D(QQuickWindow);
1226 d->init(this, control);
1227}
1228
1229/*!
1230 Destroys the window.
1231*/
1232QQuickWindow::~QQuickWindow()
1233{
1234 Q_D(QQuickWindow);
1235 d->inDestructor = true;
1236 if (d->renderControl) {
1237 QQuickRenderControlPrivate::get(d->renderControl)->windowDestroyed();
1238 } else if (d->windowManager) {
1239 d->windowManager->removeWindow(this);
1240 d->windowManager->windowDestroyed(this);
1241 }
1242
1243 disconnect(this, &QQuickWindow::focusObjectChanged, this, &QQuickWindow::activeFocusItemChanged);
1244 disconnect(this, &QQuickWindow::screenChanged, this, &QQuickWindow::handleScreenChanged);
1245 disconnect(qApp, &QGuiApplication::applicationStateChanged, this, &QQuickWindow::handleApplicationStateChanged);
1246 disconnect(this, &QQuickWindow::frameSwapped, this, &QQuickWindow::runJobsAfterSwap);
1247
1248 delete d->incubationController; d->incubationController = nullptr;
1249 QQuickRootItem *root = d->contentItem;
1250 d->contentItem = nullptr;
1251 root->setParent(nullptr); // avoid QChildEvent delivery during deletion
1252 delete root;
1253 d->deliveryAgent = nullptr; // avoid forwarding events there during destruction
1254
1255
1256 {
1257 const std::lock_guard locker(d->renderJobMutex);
1258 qDeleteAll(std::exchange(d->beforeSynchronizingJobs, {}));
1259 qDeleteAll(std::exchange(d->afterSynchronizingJobs, {}));
1260 qDeleteAll(std::exchange(d->beforeRenderingJobs, {}));
1261 qDeleteAll(std::exchange(d->afterRenderingJobs, {}));;
1262 qDeleteAll(std::exchange(d->afterSwapJobs, {}));
1263 }
1264
1265 // It is important that the pixmap cache is cleaned up during shutdown.
1266 // Besides playing nice, this also solves a practical problem that
1267 // QQuickTextureFactory implementations in other libraries need
1268 // have their destructors loaded while they the library is still
1269 // loaded into memory.
1270 QQuickPixmap::purgeCache();
1271
1272 for (QMetaObject::Connection &connection : d->connections)
1273 disconnect(connection);
1274}
1275
1276#if QT_CONFIG(quick_shadereffect)
1277void qtquick_shadereffect_purge_gui_thread_shader_cache();
1278#endif
1279
1280/*!
1281 This function tries to release redundant resources currently held by the QML scene.
1282
1283 Calling this function requests the scene graph to release cached graphics
1284 resources, such as graphics pipeline objects, shader programs, or image
1285 data.
1286
1287 Additionally, depending on the render loop in use, this function may also
1288 result in the scene graph and all window-related rendering resources to be
1289 released. If this happens, the sceneGraphInvalidated() signal will be
1290 emitted, allowing users to clean up their own graphics resources. The
1291 setPersistentGraphics() and setPersistentSceneGraph() functions can be used
1292 to prevent this from happening, if handling the cleanup is not feasible in
1293 the application, at the cost of higher memory usage.
1294
1295 \note The releasing of cached graphics resources, such as graphics
1296 pipelines or shader programs is not dependent on the persistency hints. The
1297 releasing of those will happen regardless of the values of the persistent
1298 graphics and scenegraph hints.
1299
1300 \note This function is not related to the QQuickItem::releaseResources()
1301 virtual function.
1302
1303 \sa sceneGraphInvalidated(), setPersistentGraphics(), setPersistentSceneGraph()
1304 */
1305
1306void QQuickWindow::releaseResources()
1307{
1308 Q_D(QQuickWindow);
1309 if (d->windowManager)
1310 d->windowManager->releaseResources(this);
1311 QQuickPixmap::purgeCache();
1312#if QT_CONFIG(quick_shadereffect)
1313 qtquick_shadereffect_purge_gui_thread_shader_cache();
1314#endif
1315}
1316
1317
1318
1319/*!
1320 Sets whether the graphics resources (graphics device or context,
1321 swapchain, buffers, textures) should be preserved, and cannot be
1322 released until the last window is deleted, to \a persistent. The
1323 default value is true.
1324
1325 When calling releaseResources(), or when the window gets hidden (more
1326 specifically, not renderable), some render loops have the possibility
1327 to release all, not just the cached, graphics resources. This can free
1328 up memory temporarily, but it also means the rendering engine will have
1329 to do a full, potentially costly reinitialization of the resources when
1330 the window needs to render again.
1331
1332 \note The rules for when a window is not renderable are platform and
1333 window manager specific.
1334
1335 \note All graphics resources are released when the last QQuickWindow is
1336 deleted, regardless of this setting.
1337
1338 \note This is a hint, and is not guaranteed that it is taken into account.
1339
1340 \note This hint does not apply to cached resources, that are relatively
1341 cheap to drop and then recreate later. Therefore, calling releaseResources()
1342 will typically lead to releasing those regardless of the value of this hint.
1343
1344 \sa setPersistentSceneGraph(), sceneGraphInitialized(), sceneGraphInvalidated(), releaseResources()
1345 */
1346
1347void QQuickWindow::setPersistentGraphics(bool persistent)
1348{
1349 Q_D(QQuickWindow);
1350 d->persistentGraphics = persistent;
1351}
1352
1353
1354
1355/*!
1356 Returns whether essential graphics resources can be released during the
1357 lifetime of the QQuickWindow.
1358
1359 \note This is a hint, and is not guaranteed that it is taken into account.
1360
1361 \sa setPersistentGraphics()
1362 */
1363
1364bool QQuickWindow::isPersistentGraphics() const
1365{
1366 Q_D(const QQuickWindow);
1367 return d->persistentGraphics;
1368}
1369
1370
1371
1372/*!
1373 Sets whether the scene graph nodes and resources are \a persistent.
1374 Persistent means the nodes and resources cannot be released.
1375 The default value is \c true.
1376
1377 When calling releaseResources(), when the window gets hidden (more
1378 specifically, not renderable), some render loops have the possibility
1379 to release the scene graph nodes and related graphics resources. This
1380 frees up memory temporarily, but will also mean the scene graph has to
1381 be rebuilt when the window renders next time.
1382
1383 \note The rules for when a window is not renderable are platform and
1384 window manager specific.
1385
1386 \note The scene graph nodes and resources are always released when the
1387 last QQuickWindow is deleted, regardless of this setting.
1388
1389 \note This is a hint, and is not guaranteed that it is taken into account.
1390
1391 \sa setPersistentGraphics(), sceneGraphInvalidated(), sceneGraphInitialized(), releaseResources()
1392 */
1393
1394void QQuickWindow::setPersistentSceneGraph(bool persistent)
1395{
1396 Q_D(QQuickWindow);
1397 d->persistentSceneGraph = persistent;
1398}
1399
1400
1401
1402/*!
1403 Returns whether the scene graph nodes and resources can be
1404 released during the lifetime of this QQuickWindow.
1405
1406 \note This is a hint. When and how this happens is implementation
1407 specific.
1408 */
1409
1410bool QQuickWindow::isPersistentSceneGraph() const
1411{
1412 Q_D(const QQuickWindow);
1413 return d->persistentSceneGraph;
1414}
1415
1416/*!
1417 \qmlattachedproperty Item Window::contentItem
1418 \since 5.4
1419
1420 This attached property holds the invisible root item of the scene or
1421 \c null if the item is not in a window. The Window attached property
1422 can be attached to any Item.
1423*/
1424
1425/*!
1426 \property QQuickWindow::contentItem
1427 \brief The invisible root item of the scene.
1428
1429 A QQuickWindow always has a single invisible root item containing all of its content.
1430 To add items to this window, reparent the items to the contentItem or to an existing
1431 item in the scene.
1432*/
1433QQuickItem *QQuickWindow::contentItem() const
1434{
1435 Q_D(const QQuickWindow);
1436
1437 return d->contentItem;
1438}
1439
1440/*!
1441 \property QQuickWindow::activeFocusItem
1442
1443 \brief The item which currently has active focus or \c null if there is
1444 no item with active focus.
1445
1446 \sa QQuickItem::forceActiveFocus(), {Keyboard Focus in Qt Quick}
1447*/
1448QQuickItem *QQuickWindow::activeFocusItem() const
1449{
1450 Q_D(const QQuickWindow);
1451 auto da = d->deliveryAgentPrivate();
1452 Q_ASSERT(da);
1453 return da->activeFocusItem;
1454}
1455
1456/*!
1457 \internal
1458 \reimp
1459*/
1460QObject *QQuickWindow::focusObject() const
1461{
1462 Q_D(const QQuickWindow);
1463 auto da = d->deliveryAgentPrivate();
1464 Q_ASSERT(da);
1465 if (!d->inDestructor && da->activeFocusItem)
1466 return da->activeFocusItem;
1467 return const_cast<QQuickWindow*>(this);
1468}
1469
1470/*! \reimp */
1471bool QQuickWindow::event(QEvent *event)
1472{
1473 Q_D(QQuickWindow);
1474
1475 // bypass QWindow::event dispatching of input events: deliveryAgent takes care of it
1476 QQuickDeliveryAgent *da = d->deliveryAgent;
1477 if (event->isPointerEvent()) {
1478 /*
1479 We can't bypass the virtual functions like mousePressEvent() tabletEvent() etc.,
1480 for the sake of code that subclasses QQuickWindow and overrides them, even though
1481 we no longer need them as entry points for Qt Quick event delivery.
1482 So dispatch to them now, ahead of normal delivery, and stop them from calling
1483 back into this function if they were called from here (avoid recursion).
1484 It could also be that user code expects them to work as entry points, too;
1485 in that case, windowEventDispatch _won't_ be set, so the event comes here and
1486 we'll dispatch it further below.
1487 */
1488 if (d->windowEventDispatch)
1489 return false;
1490 {
1491 const bool wasAccepted = event->isAccepted();
1492 QScopedValueRollback windowEventDispatchGuard(d->windowEventDispatch, true);
1493 qCDebug(lcPtr) << "dispatching to window functions in case of override" << event;
1494 QWindow::event(event);
1495 if (event->isAccepted() && !wasAccepted)
1496 return true;
1497 }
1498 /*
1499 QQuickWindow does not override touchEvent(). If the application has a subclass
1500 of QQuickWindow which allows the event to remain accepted, it means they want
1501 to stop propagation here, so return early (below). But otherwise we will call
1502 QWindow::touchEvent(), which will ignore(); in that case, we need to continue
1503 with the usual delivery below, so we need to undo the ignore().
1504 */
1505 auto pe = static_cast<QPointerEvent *>(event);
1506 if (QQuickDeliveryAgentPrivate::isTouchEvent(pe))
1507 event->accept();
1508 // end of dispatch to user-overridden virtual window functions
1509
1510 /*
1511 When delivering update and release events to existing grabbers,
1512 use the subscene delivery agent, if any. A possible scenario:
1513 1) Two touchpoints pressed on the main window: QQuickWindowPrivate::deliveryAgent delivers to QQuick3DViewport,
1514 which does picking and finds two subscenes ("root" Items mapped onto two different 3D objects) to deliver it to.
1515 2) The QTouchEvent is split up so that each subscene sees points relevant to it.
1516 3) During delivery to either subscene, an item in the subscene grabs.
1517 4) The user moves finger(s) generating a move event: the correct grabber item needs to get the update
1518 via the same subscene delivery agent from which it got the press, so that the coord transform will be done properly.
1519 5) Likewise with the touchpoint releases.
1520 With single-point events (mouse, or only one finger) it's simplified: there can only be one subscene of interest;
1521 for (pt : pe->points()) would only iterate once, so we might as well skip that logic.
1522 */
1523 if (pe->pointCount()) {
1524 const bool synthMouse = QQuickDeliveryAgentPrivate::isSynthMouse(pe);
1525 if (QQuickDeliveryAgentPrivate::subsceneAgentsExist) {
1526 bool ret = false;
1527 // Split up the multi-point event according to the relevant QQuickDeliveryAgent that should deliver to each existing grabber
1528 // but send ungrabbed points to d->deliveryAgent()
1529 QFlatMap<QQuickDeliveryAgent*, QList<QEventPoint>> deliveryAgentsNeedingPoints;
1530 QEventPoint::States eventStates;
1531
1532 auto insert = [&](QQuickDeliveryAgent *ptda, const QEventPoint &pt) {
1533 if (pt.state() == QEventPoint::Pressed && !synthMouse)
1534 pe->clearPassiveGrabbers(pt);
1535 auto &ptList = deliveryAgentsNeedingPoints[ptda];
1536 auto idEquals = [](auto id) { return [id] (const auto &e) { return e.id() == id; }; };
1537 if (std::none_of(ptList.cbegin(), ptList.cend(), idEquals(pt.id())))
1538 ptList.append(pt);
1539 };
1540
1541 for (const auto &pt : pe->points()) {
1542 eventStates |= pt.state();
1543 auto epd = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(pe->pointingDevice()))->queryPointById(pt.id());
1544 Q_ASSERT(epd);
1545 bool foundAgent = false;
1546 if (!epd->exclusiveGrabber.isNull() && !epd->exclusiveGrabberContext.isNull()) {
1547 if (auto ptda = qobject_cast<QQuickDeliveryAgent *>(epd->exclusiveGrabberContext.data())) {
1548 insert(ptda, pt);
1549 qCDebug(lcPtr) << pe->type() << "point" << pt.id() << pt.state()
1550 << "@" << pt.scenePosition() << "will be re-delivered via known grabbing agent" << ptda << "to" << epd->exclusiveGrabber.data();
1551 foundAgent = true;
1552 }
1553 }
1554 for (const auto &pgda : std::as_const(epd->passiveGrabbersContext)) {
1555 if (auto ptda = qobject_cast<QQuickDeliveryAgent *>(pgda.data())) {
1556 insert(ptda, pt);
1557 qCDebug(lcPtr) << pe->type() << "point" << pt.id() << pt.state()
1558 << "@" << pt.scenePosition() << "will be re-delivered via known passive-grabbing agent" << ptda;
1559 foundAgent = true;
1560 }
1561 }
1562 // fallback: if we didn't find remembered/known grabber agent(s), expect the root DA to handle it
1563 if (!foundAgent)
1564 insert(da, pt);
1565 }
1566 for (auto daAndPoints : deliveryAgentsNeedingPoints) {
1567 if (pe->pointCount() > 1) {
1568 Q_ASSERT(QQuickDeliveryAgentPrivate::isTouchEvent(pe));
1569 // if all points have the same state, set the event type accordingly
1570 QEvent::Type eventType = pe->type();
1571 switch (eventStates) {
1572 case QEventPoint::State::Pressed:
1573 eventType = QEvent::TouchBegin;
1574 break;
1575 case QEventPoint::State::Released:
1576 eventType = QEvent::TouchEnd;
1577 break;
1578 default:
1579 eventType = QEvent::TouchUpdate;
1580 break;
1581 }
1582 // Make a new touch event for the subscene, the same way QQuickItemPrivate::localizedTouchEvent() does it
1583 QMutableTouchEvent te(eventType, pe->pointingDevice(), pe->modifiers(), daAndPoints.second);
1584 te.setTimestamp(pe->timestamp());
1585 te.accept();
1586 qCDebug(lcTouch) << daAndPoints.first << "shall now receive" << &te;
1587 ret = daAndPoints.first->event(&te) || ret;
1588 } else {
1589 qCDebug(lcPtr) << daAndPoints.first << "shall now receive" << pe;
1590 ret = daAndPoints.first->event(pe) || ret;
1591 }
1592 }
1593
1594 if (ret) {
1595 d->deliveryAgentPrivate()->clearGrabbers(pe);
1596 return true;
1597 }
1598 } else if (!synthMouse) {
1599 // clear passive grabbers unless it's a system synth-mouse event
1600 // QTBUG-104890: Windows sends synth mouse events (which should be ignored) after touch events
1601 for (const auto &pt : pe->points()) {
1602 if (pt.state() == QEventPoint::Pressed)
1603 pe->clearPassiveGrabbers(pt);
1604 }
1605 }
1606 }
1607
1608 // If it has no points, it's probably a TouchCancel, and DeliveryAgent needs to handle it.
1609 // If we didn't handle it in the block above, handle it now.
1610 // TODO should we deliver to all DAs at once then, since we don't know which one should get it?
1611 // or fix QTBUG-90851 so that the event always has points?
1612 qCDebug(lcHoverTrace) << this << "some sort of event" << event;
1613 bool ret = (da && da->event(event));
1614
1615 // The default QWindow mousePressEvent/mouseMoveEvent/mouseReleaseEvent handlers
1616 // dispatched to above always ignore() the event, and Quick's own handlers don't
1617 // reliably accept() the whole event either (e.g. QQuickDragHandler only does so
1618 // incidentally). So isAccepted() may not reflect whether a point actually got
1619 // grabbed. Fix that up before clearGrabbers() discards the grab state, so external
1620 // code that still checks QEvent::isAccepted() (e.g. QWindowPrivate::forwardToPopup)
1621 // gets a meaningful answer.
1622 // Tablet events are excluded: QGuiApplicationPrivate::processTabletEvent() gives
1623 // isAccepted() an unrelated meaning for them (whether to synthesize a compatibility
1624 // QMouseEvent for items/handlers that only understand mouse events), and accepting
1625 // here purely because a point got grabbed would suppress that synthesis (see the
1626 // dedicated tablet handling below, which accepts tablet events on its own terms).
1627 if (pe->isPointerEvent() && !QQuickDeliveryAgentPrivate::isTabletEvent(pe) && d->isPopup()
1628 && std::any_of(std::cbegin(pe->points()), std::cend(pe->points()), [pe](auto &p){ return pe->exclusiveGrabber(p);}))
1629 pe->accept();
1630
1631 d->deliveryAgentPrivate()->clearGrabbers(pe);
1632
1633 if (pe->type() == QEvent::MouseButtonPress || pe->type() == QEvent::MouseButtonRelease) {
1634 // Ensure that we synthesize a context menu event as QWindow::event does, if necessary.
1635 // We only send the context menu event if the pointer event wasn't accepted (ret == false).
1636 d->maybeSynthesizeContextMenuEvent(static_cast<QMouseEvent *>(pe));
1637 }
1638
1639#if QT_CONFIG(tabletevent)
1640 // QGuiApplication::processTabletEvent() uses forwardToPopup() to send
1641 // tablet events to popup windows so they can handle them or block
1642 // further delivery. Prevent fall-through to any window behind a popup
1643 // by accepting any tablet event that landed outside the popup's bounds.
1644 // QTabletEvent.accepted is false by default (unlike mouse events), so
1645 // we need to stop delivery by accepting explicitly.
1646 if (type() == Qt::Popup && QQuickDeliveryAgentPrivate::isTabletEvent(pe) &&
1647 !QRect(QPoint(), size()).contains(pe->points().first().scenePosition().toPoint())) {
1648 pe->accept();
1649 return true;
1650 }
1651#endif
1652
1653 if (ret)
1654 return true;
1655 } else if (event->isInputEvent()) {
1656 if (da && da->event(event))
1657 return true;
1658 }
1659
1660 switch (event->type()) {
1661 // a few more types that are not QInputEvents, but QQuickDeliveryAgent needs to handle them anyway
1662 case QEvent::FocusAboutToChange:
1663 case QEvent::Enter:
1664 case QEvent::Leave:
1665 case QEvent::InputMethod:
1666 case QEvent::InputMethodQuery:
1667#if QT_CONFIG(quick_draganddrop)
1668 case QEvent::DragEnter:
1669 case QEvent::DragLeave:
1670 case QEvent::DragMove:
1671 case QEvent::Drop:
1672#endif
1673 if (d->inDestructor)
1674 return false;
1675 if (da && da->event(event))
1676 return true;
1677 break;
1678 case QEvent::LanguageChange:
1679 case QEvent::LocaleChange:
1680 if (d->contentItem)
1681 QCoreApplication::sendEvent(d->contentItem, event);
1682 break;
1683 case QEvent::UpdateRequest:
1684 if (d->windowManager)
1685 d->windowManager->handleUpdateRequest(this);
1686 break;
1687 case QEvent::PlatformSurface:
1688 if ((static_cast<QPlatformSurfaceEvent *>(event))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
1689 // Ensure that the rendering thread is notified before
1690 // the QPlatformWindow is destroyed.
1691 if (d->windowManager)
1692 d->windowManager->hide(this);
1693 }
1694 break;
1695 case QEvent::WindowDeactivate:
1696 if (auto da = d->deliveryAgentPrivate())
1697 da->handleWindowDeactivate(this);
1698 Q_FALLTHROUGH();
1699 case QEvent::WindowActivate:
1700 if (d->contentItem)
1701 QCoreApplication::sendEvent(d->contentItem, event);
1702 break;
1703 case QEvent::ApplicationPaletteChange:
1704 d->inheritPalette(QGuiApplication::palette());
1705 if (d->contentItem)
1706 QCoreApplication::sendEvent(d->contentItem, event);
1707 break;
1708 case QEvent::DevicePixelRatioChange:
1709 physicalDpiChanged();
1710 break;
1711 case QEvent::SafeAreaMarginsChange:
1712 QQuickSafeArea::updateSafeAreasRecursively(d->contentItem);
1713 break;
1714 case QEvent::ChildWindowAdded: {
1715 auto *childEvent = static_cast<QChildWindowEvent*>(event);
1716 auto *childWindow = childEvent->child();
1717 qCDebug(lcQuickWindow) << "Child window" << childWindow << "added to" << this;
1718 if (childWindow->handle()) {
1719 // The reparenting has already resulted in the native window
1720 // being added to its parent, on top of all other windows. We need
1721 // to do a synchronous re-stacking of the windows here, to avoid
1722 // leaving the window in the wrong position while waiting for the
1723 // asynchronous callback to QQuickWindow::polishItems().
1724 d->updateChildWindowStackingOrder();
1725 } else {
1726 qCDebug(lcQuickWindow) << "No platform window yet."
1727 << "Deferring child window stacking until surface creation";
1728 }
1729 break;
1730 }
1731 default:
1732 break;
1733 }
1734
1735 if (event->type() == QEvent::Type(QQuickWindowPrivate::FullUpdateRequest))
1736 update();
1737 else if (event->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure))
1738 d->windowManager->handleContextCreationFailure(this);
1739
1740 if (event->isPointerEvent())
1741 return true;
1742 else
1743 return QWindow::event(event);
1744}
1745
1746void QQuickWindowPrivate::maybeSynthesizeContextMenuEvent(QMouseEvent *event)
1747{
1748 // See comment in QQuickWindow::event; we need to follow that pattern here,
1749 // otherwise the context menu event will be sent before the press (since
1750 // QQuickWindow::mousePressEvent returns early if windowEventDispatch is true).
1751 // If we don't do this, the incorrect order will cause the menu to
1752 // immediately close when the press is delivered.
1753 // Also, don't send QContextMenuEvent if a menu has already been opened while
1754 // handling a QMouseEvent in which the right button was pressed or released.
1755 if (windowEventDispatch || !rmbContextMenuEventEnabled)
1756 return;
1757
1758#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1759 /*
1760 If this is a press event and the EventPoint already has a grab, it may be
1761 that a TapHandler.onTapped() or MouseArea.onClicked() function
1762 intends to show a context menu. Menus were often added that way; so if
1763 we can detect that it's likely, then don't synthesize a QContextMenuEvent,
1764 in case it could be redundant, even though we can't tell in advance
1765 whether the TapHandler or MouseArea will open a menu or do something else.
1766 However, we are only checking for MouseArea and TapHandler; it's also
1767 possible (but hopefully much less likely) that a user adds a custom
1768 QQuickItem subclass to handle mouse events to open a context menu.
1769 If a bug gets written about that, we can ask them to try out the
1770 ContextMenu attached property instead, or handle the QContextMenuEvent
1771 in their subclass. Anyway, let's expect applications to be adjusted for
1772 Qt 7 or before, so that we can get rid of this second-guessing hack.
1773 */
1774 const auto &firstPoint = event->points().first();
1775 auto hasRightButtonTapHandler = [](const auto &passiveGrabbers) {
1776 return std::find_if(passiveGrabbers.constBegin(), passiveGrabbers.constEnd(),
1777 [](const auto grabber) {
1778 auto *tapHandler = qmlobject_cast<QQuickTapHandler *>(grabber);
1779 return tapHandler && tapHandler->acceptedButtons().testFlag(Qt::RightButton); })
1780 != passiveGrabbers.constEnd();
1781 };
1782 if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::RightButton &&
1783 (qmlobject_cast<QQuickMouseArea *>(event->exclusiveGrabber(firstPoint))
1784 || hasRightButtonTapHandler(event->passiveGrabbers(firstPoint)))) {
1785 qCDebug(lcPtr) << "skipping QContextMenuEvent synthesis due to grabber(s)" << event;
1786 return;
1787 }
1788#endif
1789
1790 QWindowPrivate::maybeSynthesizeContextMenuEvent(event);
1791}
1792
1793void QQuickWindowPrivate::updateChildWindowStackingOrder(QQuickItem *item)
1794{
1795 Q_Q(QQuickWindow);
1796
1797 if (!item) {
1798 qCDebug(lcQuickWindow) << "Updating child window stacking order for" << q;
1799 item = contentItem;
1800 }
1801 auto *itemPrivate = QQuickItemPrivate::get(item);
1802 const auto paintOrderChildItems = itemPrivate->paintOrderChildItems();
1803 for (auto *child : paintOrderChildItems) {
1804 if (auto *windowContainer = qobject_cast<QQuickWindowContainer*>(child)) {
1805 auto *window = windowContainer->containedWindow();
1806 if (!window) {
1807 qCDebug(lcQuickWindow) << windowContainer << "has no contained window yet";
1808 continue;
1809 }
1810 if (window->parent() != q) {
1811 qCDebug(lcQuickWindow) << window << "is not yet child of this window";
1812 continue;
1813 }
1814 qCDebug(lcQuickWindow) << "Raising" << window << "owned by" << windowContainer;
1815 window->raise();
1816 }
1817
1818 updateChildWindowStackingOrder(child);
1819 }
1820}
1821
1822/*! \reimp */
1823void QQuickWindow::keyPressEvent(QKeyEvent *e)
1824{
1825 Q_D(QQuickWindow);
1826 if (d->windowEventDispatch)
1827 return;
1828 auto da = d->deliveryAgentPrivate();
1829 Q_ASSERT(da);
1830 da->deliverKeyEvent(e);
1831}
1832
1833/*! \reimp */
1834void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
1835{
1836 Q_D(QQuickWindow);
1837 if (d->windowEventDispatch)
1838 return;
1839 auto da = d->deliveryAgentPrivate();
1840 Q_ASSERT(da);
1841 da->deliverKeyEvent(e);
1842}
1843
1844#if QT_CONFIG(wheelevent)
1845/*! \reimp */
1846void QQuickWindow::wheelEvent(QWheelEvent *event)
1847{
1848 Q_D(QQuickWindow);
1849 if (d->windowEventDispatch)
1850 return;
1851 auto da = d->deliveryAgentPrivate();
1852 Q_ASSERT(da);
1853 da->deliverSinglePointEventUntilAccepted(event);
1854}
1855#endif // wheelevent
1856
1857#if QT_CONFIG(tabletevent)
1858/*! \reimp */
1859void QQuickWindow::tabletEvent(QTabletEvent *event)
1860{
1861 Q_D(QQuickWindow);
1862 if (d->windowEventDispatch)
1863 return;
1864 auto da = d->deliveryAgentPrivate();
1865 Q_ASSERT(da);
1866 da->deliverPointerEvent(event);
1867}
1868#endif // tabletevent
1869
1870/*! \reimp */
1871void QQuickWindow::mousePressEvent(QMouseEvent *event)
1872{
1873 Q_D(QQuickWindow);
1874 if (d->windowEventDispatch)
1875 return;
1876 auto da = d->deliveryAgentPrivate();
1877 Q_ASSERT(da);
1878 da->handleMouseEvent(event);
1879}
1880/*! \reimp */
1881void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
1882{
1883 Q_D(QQuickWindow);
1884 if (d->windowEventDispatch)
1885 return;
1886 auto da = d->deliveryAgentPrivate();
1887 Q_ASSERT(da);
1888 da->handleMouseEvent(event);
1889}
1890/*! \reimp */
1891void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
1892{
1893 Q_D(QQuickWindow);
1894 if (d->windowEventDispatch)
1895 return;
1896 auto da = d->deliveryAgentPrivate();
1897 Q_ASSERT(da);
1898 da->handleMouseEvent(event);
1899}
1900/*! \reimp */
1901void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
1902{
1903 Q_D(QQuickWindow);
1904 if (d->windowEventDispatch)
1905 return;
1906 auto da = d->deliveryAgentPrivate();
1907 Q_ASSERT(da);
1908 da->handleMouseEvent(event);
1909}
1910
1911#if QT_CONFIG(cursor)
1912void QQuickWindowPrivate::updateCursor(const QPointF &scenePos, QQuickItem *rootItem)
1913{
1914 Q_Q(QQuickWindow);
1915 if (!rootItem)
1916 rootItem = contentItem;
1917 auto cursorItemAndHandler = findCursorItemAndHandler(rootItem, scenePos, scenePos);
1918 if (cursorItem != cursorItemAndHandler.first || cursorHandler != cursorItemAndHandler.second ||
1919 (cursorItemAndHandler.second && QQuickPointerHandlerPrivate::get(cursorItemAndHandler.second)->cursorDirty)) {
1920 QWindow *renderWindow = QQuickRenderControl::renderWindowFor(q);
1921 QWindow *window = renderWindow ? renderWindow : q;
1922 cursorItem = cursorItemAndHandler.first;
1923 cursorHandler = cursorItemAndHandler.second;
1924 if (cursorHandler)
1925 QQuickPointerHandlerPrivate::get(cursorItemAndHandler.second)->cursorDirty = false;
1926 if (cursorItem) {
1927 const auto cursor = QQuickItemPrivate::get(cursorItem)->effectiveCursor(cursorHandler);
1928 qCDebug(lcHoverCursor) << "setting cursor" << cursor << "from" << cursorHandler << "or" << cursorItem;
1929 window->setCursor(cursor);
1930 } else {
1931 qCDebug(lcHoverCursor) << "unsetting cursor";
1932 window->unsetCursor();
1933 }
1934 }
1935}
1936
1937std::pair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAndHandler(QQuickItem *item,
1938 const QPointF &localPos, const QPointF &scenePos) const
1939{
1940 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1941 if (itemPrivate->effectivelyClipsEventHandlingChildren() &&
1942 !itemPrivate->eventHandlingBounds().contains(localPos)) {
1943#ifdef QT_BUILD_INTERNAL
1944 ++QQuickItemPrivate::effectiveClippingSkips_counter;
1945#endif
1946 return {nullptr, nullptr};
1947 }
1948
1949 if (itemPrivate->subtreeCursorEnabled) {
1950 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1951 for (int ii = children.size() - 1; ii >= 0; --ii) {
1952 QQuickItem *child = children.at(ii);
1953 if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
1954 continue;
1955
1956 const QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
1957 QTransform childToParent;
1958 childPrivate->itemToParentTransform(&childToParent);
1959 const QPointF childLocalPos = childToParent.inverted().map(localPos);
1960 auto ret = findCursorItemAndHandler(child, childLocalPos, scenePos);
1961 if (ret.first)
1962 return ret;
1963 }
1964 if (itemPrivate->hasCursorHandler) {
1965 if (auto handler = itemPrivate->effectiveCursorHandler()) {
1966 if (handler->parentContains(localPos, scenePos))
1967 return {item, handler};
1968 }
1969 }
1970 if (itemPrivate->hasCursor) {
1971 if (item->contains(localPos))
1972 return {item, nullptr};
1973 }
1974 }
1975
1976 return {nullptr, nullptr};
1977}
1978#endif
1979
1980void QQuickWindowPrivate::clearFocusObject()
1981{
1982 if (auto da = deliveryAgentPrivate())
1983 da->clearFocusObject();
1984}
1985
1986void QQuickWindowPrivate::setFocusToTarget(FocusTarget target, Qt::FocusReason reason)
1987{
1988 if (!contentItem)
1989 return;
1990
1991 QQuickItem *newFocusItem = nullptr;
1992 switch (target) {
1993 case FocusTarget::First:
1994 case FocusTarget::Last: {
1995 const bool forward = (target == FocusTarget::First);
1996 newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, forward);
1997 if (newFocusItem) {
1998 const auto *itemPriv = QQuickItemPrivate::get(newFocusItem);
1999 if (itemPriv->subFocusItem && itemPriv->flags & QQuickItem::ItemIsFocusScope)
2000 deliveryAgentPrivate()->clearFocusInScope(newFocusItem, itemPriv->subFocusItem, reason);
2001 }
2002 break;
2003 }
2004 case FocusTarget::Next:
2005 case FocusTarget::Prev: {
2006 const auto da = deliveryAgentPrivate();
2007 Q_ASSERT(da);
2008 QQuickItem *focusItem = da->focusTargetItem() ? da->focusTargetItem() : contentItem;
2009 bool forward = (target == FocusTarget::Next);
2010 newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(focusItem, forward);
2011 break;
2012 }
2013 default:
2014 break;
2015 }
2016
2017 if (newFocusItem)
2018 newFocusItem->forceActiveFocus(reason);
2019}
2020
2021/*!
2022 \qmlproperty list<QtObject> Window::data
2023 \qmldefault
2024
2025 The data property allows you to freely mix visual children, resources
2026 and other Windows in a Window.
2027
2028 If you assign another Window to the data list, the nested window will
2029 become "transient for" the outer Window.
2030
2031 If you assign an \l Item to the data list, it becomes a child of the
2032 Window's \l contentItem, so that it appears inside the window. The item's
2033 parent will be the window's contentItem, which is the root of the Item
2034 ownership tree within that Window.
2035
2036 If you assign any other object type, it is added as a resource.
2037
2038 It should not generally be necessary to refer to the \c data property,
2039 as it is the default property for Window and thus all child items are
2040 automatically assigned to this property.
2041
2042 \sa QWindow::transientParent()
2043 */
2044
2045void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObject *o)
2046{
2047 if (!o)
2048 return;
2049 QQuickWindow *that = static_cast<QQuickWindow *>(property->object);
2050 QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(that->contentItem())->data();
2051 itemProperty.append(&itemProperty, o);
2052}
2053
2054qsizetype QQuickWindowPrivate::data_count(QQmlListProperty<QObject> *property)
2055{
2056 QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
2057 if (!win || !win->contentItem() || !QQuickItemPrivate::get(win->contentItem())->data().count)
2058 return 0;
2059 QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
2060 return itemProperty.count(&itemProperty);
2061}
2062
2063QObject *QQuickWindowPrivate::data_at(QQmlListProperty<QObject> *property, qsizetype i)
2064{
2065 QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
2066 QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
2067 return itemProperty.at(&itemProperty, i);
2068}
2069
2070void QQuickWindowPrivate::data_clear(QQmlListProperty<QObject> *property)
2071{
2072 QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
2073 QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
2074 itemProperty.clear(&itemProperty);
2075}
2076
2077void QQuickWindowPrivate::data_removeLast(QQmlListProperty<QObject> *property)
2078{
2079 QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
2080 QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
2081 itemProperty.removeLast(&itemProperty);
2082}
2083
2084bool QQuickWindowPrivate::isRenderable() const
2085{
2086 Q_Q(const QQuickWindow);
2087 return ((q->isExposed() && q->isVisible())) && q->geometry().isValid();
2088}
2089
2090void QQuickWindowPrivate::rhiCreationFailureMessage(const QString &backendName,
2091 QString *translatedMessage,
2092 QString *untranslatedMessage)
2093{
2094 const char msg[] = QT_TRANSLATE_NOOP("QQuickWindow",
2095 "Failed to initialize graphics backend for %1.");
2096 *translatedMessage = QQuickWindow::tr(msg).arg(backendName);
2097 *untranslatedMessage = QString::fromLatin1(msg).arg(backendName);
2098}
2099
2100void QQuickWindowPrivate::cleanupNodes()
2101{
2102 qDeleteAll(cleanupNodeList);
2103 cleanupNodeList.clear();
2104}
2105
2106void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
2107{
2108 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
2109 if (p->itemNodeInstance) {
2110 delete p->itemNodeInstance;
2111 p->itemNodeInstance = nullptr;
2112
2113 if (p->extra.isAllocated()) {
2114 p->extra->opacityNode = nullptr;
2115 p->extra->clipNode = nullptr;
2116 p->extra->rootNode = nullptr;
2117 }
2118
2119 p->paintNode = nullptr;
2120
2121 p->dirty(QQuickItemPrivate::Window);
2122 }
2123
2124 // Qt 7: Make invalidateSceneGraph a virtual member of QQuickItem
2125 if (p->flags & QQuickItem::ItemHasContents) {
2126 const QMetaObject *mo = item->metaObject();
2127 int index = mo->indexOfSlot("invalidateSceneGraph()");
2128 if (index >= 0) {
2129 const QMetaMethod &method = mo->method(index);
2130 // Skip functions named invalidateSceneGraph() in QML items.
2131 if (strstr(method.enclosingMetaObject()->className(), "_QML_") == nullptr)
2132 method.invoke(item, Qt::DirectConnection);
2133 }
2134 }
2135
2136 for (int ii = 0; ii < p->childItems.size(); ++ii)
2137 cleanupNodesOnShutdown(p->childItems.at(ii));
2138}
2139
2140// This must be called from the render thread, with the main thread frozen
2141void QQuickWindowPrivate::cleanupNodesOnShutdown()
2142{
2143 Q_Q(QQuickWindow);
2144 cleanupNodes();
2145 cleanupNodesOnShutdown(contentItem);
2146 for (QSet<QQuickItem *>::const_iterator it = parentlessItems.cbegin(), cend = parentlessItems.cend(); it != cend; ++it)
2147 cleanupNodesOnShutdown(*it);
2148 animationController->windowNodesDestroyed();
2149 q->cleanupSceneGraph();
2150}
2151
2152void QQuickWindowPrivate::updateDirtyNodes()
2153{
2154 qCDebug(lcDirty) << "QQuickWindowPrivate::updateDirtyNodes():";
2155
2156 cleanupNodes();
2157
2158 QQuickItem *updateList = dirtyItemList;
2159 dirtyItemList = nullptr;
2160 if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
2161
2162 while (updateList) {
2163 QQuickItem *item = updateList;
2164 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
2165 itemPriv->removeFromDirtyList();
2166
2167 qCDebug(lcDirty) << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
2168 updateDirtyNode(item);
2169 }
2170}
2171
2172static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d)
2173{
2174 const QList<QQuickItem *> childItems = d->paintOrderChildItems();
2175 QQuickItem *before = nullptr;
2176 for (int i=0; i<childItems.size(); ++i) {
2177 QQuickItemPrivate *dd = QQuickItemPrivate::get(childItems.at(i));
2178 // Perform the same check as the in fetchNextNode below.
2179 if (dd->z() < 0 && (dd->explicitVisible || (dd->extra.isAllocated() && dd->extra->effectRefCount)))
2180 before = childItems.at(i);
2181 else
2182 break;
2183 }
2184 return Q_UNLIKELY(before) ? QQuickItemPrivate::get(before)->itemNode() : nullptr;
2185}
2186
2187static QSGNode *fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &returnedPaintNode)
2188{
2189 QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
2190
2191 for (; ii < orderedChildren.size() && orderedChildren.at(ii)->z() < 0; ++ii) {
2192 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
2193 if (!childPrivate->explicitVisible &&
2194 (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
2195 continue;
2196
2197 ii++;
2198 return childPrivate->itemNode();
2199 }
2200
2201 if (itemPriv->paintNode && !returnedPaintNode) {
2202 returnedPaintNode = true;
2203 return itemPriv->paintNode;
2204 }
2205
2206 for (; ii < orderedChildren.size(); ++ii) {
2207 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
2208 if (!childPrivate->explicitVisible &&
2209 (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
2210 continue;
2211
2212 ii++;
2213 return childPrivate->itemNode();
2214 }
2215
2216 return nullptr;
2217}
2218
2219void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
2220{
2221 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
2222 quint32 dirty = itemPriv->dirtyAttributes;
2223 itemPriv->dirtyAttributes = 0;
2224
2225 if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
2226 (dirty & QQuickItemPrivate::Size && itemPriv->origin() != QQuickItem::TopLeft &&
2227 (itemPriv->scale() != 1. || itemPriv->rotation() != 0.))) {
2228
2229 QMatrix4x4 matrix;
2230
2231 if (itemPriv->x != 0. || itemPriv->y != 0.)
2232 matrix.translate(itemPriv->x, itemPriv->y);
2233
2234 for (int ii = itemPriv->transforms.size() - 1; ii >= 0; --ii)
2235 itemPriv->transforms.at(ii)->applyTo(&matrix);
2236
2237 if (itemPriv->scale() != 1. || itemPriv->rotation() != 0.) {
2238 QPointF origin = item->transformOriginPoint();
2239 matrix.translate(origin.x(), origin.y());
2240 if (itemPriv->scale() != 1.)
2241 matrix.scale(itemPriv->scale(), itemPriv->scale());
2242 if (itemPriv->rotation() != 0.)
2243 matrix.rotate(itemPriv->rotation(), 0, 0, 1);
2244 matrix.translate(-origin.x(), -origin.y());
2245 }
2246
2247 itemPriv->itemNode()->setMatrix(matrix);
2248 }
2249
2250 const bool clipEffectivelyChanged = dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Window);
2251 if (clipEffectivelyChanged) {
2252 QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *)itemPriv->opacityNode()
2253 : (QSGNode *)itemPriv->itemNode();
2254 QSGNode *child = itemPriv->rootNode();
2255
2256 if (bool initializeClipNode = item->clip() && itemPriv->clipNode() == nullptr;
2257 initializeClipNode) {
2258 QQuickDefaultClipNode *clip = new QQuickDefaultClipNode(item->clipRect());
2259 itemPriv->extra.value().clipNode = clip;
2260 clip->update();
2261
2262 if (!child) {
2263 parent->reparentChildNodesTo(clip);
2264 parent->appendChildNode(clip);
2265 } else {
2266 parent->removeChildNode(child);
2267 clip->appendChildNode(child);
2268 parent->appendChildNode(clip);
2269 }
2270
2271 } else if (bool updateClipNode = item->clip() && itemPriv->clipNode() != nullptr;
2272 updateClipNode) {
2273 QQuickDefaultClipNode *clip = itemPriv->clipNode();
2274 clip->setClipRect(item->clipRect());
2275 clip->update();
2276 } else if (bool removeClipNode = !item->clip() && itemPriv->clipNode() != nullptr;
2277 removeClipNode) {
2278 QQuickDefaultClipNode *clip = itemPriv->clipNode();
2279 parent->removeChildNode(clip);
2280 if (child) {
2281 clip->removeChildNode(child);
2282 parent->appendChildNode(child);
2283 } else {
2284 clip->reparentChildNodesTo(parent);
2285 }
2286
2287 delete itemPriv->clipNode();
2288 itemPriv->extra->clipNode = nullptr;
2289 }
2290 }
2291
2292 const int effectRefCount = itemPriv->extra.isAllocated() ? itemPriv->extra->effectRefCount : 0;
2293 const bool effectRefEffectivelyChanged =
2294 (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Window))
2295 && ((effectRefCount == 0) != (itemPriv->rootNode() == nullptr));
2296 if (effectRefEffectivelyChanged) {
2297 if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
2298 itemPriv->childContainerNode()->removeAllChildNodes();
2299
2300 QSGNode *parent = itemPriv->clipNode();
2301 if (!parent)
2302 parent = itemPriv->opacityNode();
2303 if (!parent)
2304 parent = itemPriv->itemNode();
2305
2306 if (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount) {
2307 Q_ASSERT(itemPriv->rootNode() == nullptr);
2308 QSGRootNode *root = new QSGRootNode();
2309 itemPriv->extra->rootNode = root;
2310 parent->reparentChildNodesTo(root);
2311 parent->appendChildNode(root);
2312 } else {
2313 Q_ASSERT(itemPriv->rootNode() != nullptr);
2314 QSGRootNode *root = itemPriv->rootNode();
2315 parent->removeChildNode(root);
2316 root->reparentChildNodesTo(parent);
2317 delete itemPriv->rootNode();
2318 itemPriv->extra->rootNode = nullptr;
2319 }
2320 }
2321
2322 if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
2323 int ii = 0;
2324 bool fetchedPaintNode = false;
2325 QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
2326 int desiredNodesSize = orderedChildren.size() + (itemPriv->paintNode ? 1 : 0);
2327
2328 // now start making current state match the promised land of
2329 // desiredNodes. in the case of our current state matching desiredNodes
2330 // (though why would we get ChildrenUpdateMask with no changes?) then we
2331 // should make no changes at all.
2332
2333 // how many nodes did we process, when examining changes
2334 int desiredNodesProcessed = 0;
2335
2336 // currentNode is how far, in our present tree, we have processed. we
2337 // make use of this later on to trim the current child list if the
2338 // desired list is shorter.
2339 QSGNode *groupNode = itemPriv->childContainerNode();
2340 QSGNode *currentNode = groupNode->firstChild();
2341 QSGNode *desiredNode = nullptr;
2342
2343 while (currentNode && (desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) {
2344 if (currentNode != desiredNode) {
2345 // uh oh... reality and our utopic paradise are diverging!
2346 // we need to reconcile this...
2347 if (currentNode->nextSibling() == desiredNode) {
2348 // nice and simple: a node was removed, and the next in line is correct.
2349 groupNode->removeChildNode(currentNode);
2350 } else {
2351 // a node needs to be added..
2352 // remove it from any pre-existing parent, and push it before currentNode,
2353 // so it's in the correct place...
2354 if (desiredNode->parent()) {
2355 desiredNode->parent()->removeChildNode(desiredNode);
2356 }
2357 groupNode->insertChildNodeBefore(desiredNode, currentNode);
2358 }
2359
2360 // continue iteration at the correct point, now desiredNode is in place...
2361 currentNode = desiredNode;
2362 }
2363
2364 currentNode = currentNode->nextSibling();
2365 desiredNodesProcessed++;
2366 }
2367
2368 // if we didn't process as many nodes as in the new list, then we have
2369 // more nodes at the end of desiredNodes to append to our list.
2370 // this will be the case when adding new nodes, for instance.
2371 if (desiredNodesProcessed < desiredNodesSize) {
2372 while ((desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) {
2373 if (desiredNode->parent())
2374 desiredNode->parent()->removeChildNode(desiredNode);
2375 groupNode->appendChildNode(desiredNode);
2376 }
2377 } else if (currentNode) {
2378 // on the other hand, if we processed less than our current node
2379 // tree, then nodes have been _removed_ from the scene, and we need
2380 // to take care of that here.
2381 while (currentNode) {
2382 QSGNode *node = currentNode->nextSibling();
2383 groupNode->removeChildNode(currentNode);
2384 currentNode = node;
2385 }
2386 }
2387 }
2388
2389 if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) {
2390 itemPriv->clipNode()->setRect(item->clipRect());
2391 itemPriv->clipNode()->update();
2392 }
2393
2394 if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible
2395 | QQuickItemPrivate::HideReference | QQuickItemPrivate::Window))
2396 {
2397 qreal opacity = itemPriv->explicitVisible && (!itemPriv->extra.isAllocated() || itemPriv->extra->hideRefCount == 0)
2398 ? itemPriv->opacity() : qreal(0);
2399
2400 if (opacity != 1 && !itemPriv->opacityNode()) {
2401 QSGOpacityNode *node = new QSGOpacityNode;
2402 itemPriv->extra.value().opacityNode = node;
2403
2404 QSGNode *parent = itemPriv->itemNode();
2405 QSGNode *child = itemPriv->clipNode();
2406 if (!child)
2407 child = itemPriv->rootNode();
2408
2409 if (child) {
2410 parent->removeChildNode(child);
2411 node->appendChildNode(child);
2412 parent->appendChildNode(node);
2413 } else {
2414 parent->reparentChildNodesTo(node);
2415 parent->appendChildNode(node);
2416 }
2417 }
2418 if (itemPriv->opacityNode())
2419 itemPriv->opacityNode()->setOpacity(opacity);
2420 }
2421
2422 if (dirty & QQuickItemPrivate::ContentUpdateMask) {
2423
2424 if (itemPriv->flags & QQuickItem::ItemHasContents) {
2425 updatePaintNodeData.transformNode = itemPriv->itemNode();
2426 itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
2427
2428 Q_ASSERT(itemPriv->paintNode == nullptr ||
2429 itemPriv->paintNode->parent() == nullptr ||
2430 itemPriv->paintNode->parent() == itemPriv->childContainerNode());
2431
2432 if (itemPriv->paintNode) {
2433 if (itemPriv->paintNode->parent() == nullptr) {
2434 QSGNode *before = qquickitem_before_paintNode(itemPriv);
2435 if (before && before->parent()) {
2436 Q_ASSERT(before->parent() == itemPriv->childContainerNode());
2437 itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, before);
2438 } else {
2439 itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
2440 }
2441 }
2442
2443 // Ensure paint node subtree has same mutability group as item, but only if
2444 // the mutability group has been explicitly set (avoiding this extra pass for
2445 // the majority of items which never touch this property)
2446 if (itemPriv->extra.isAllocated() && itemPriv->extra->mutabilityGroupSet) {
2447 QSGNodePrivate::setMutabilityGroupOfSubtree(itemPriv->paintNode,
2448 itemPriv->extra->mutabilityGroup);
2449 }
2450 }
2451
2452 } else if (itemPriv->paintNode) {
2453 delete itemPriv->paintNode;
2454 itemPriv->paintNode = nullptr;
2455 }
2456 }
2457
2458#ifndef QT_NO_DEBUG
2459 // Check consistency.
2460
2461 QList<QSGNode *> nodes;
2462 nodes << itemPriv->itemNodeInstance
2463 << itemPriv->opacityNode()
2464 << itemPriv->clipNode()
2465 << itemPriv->rootNode()
2466 << itemPriv->paintNode;
2467 nodes.removeAll(nullptr);
2468
2469 Q_ASSERT(nodes.constFirst() == itemPriv->itemNodeInstance);
2470 for (int i=1; i<nodes.size(); ++i) {
2471 QSGNode *n = nodes.at(i);
2472 // Failing this means we messed up reparenting
2473 Q_ASSERT(n->parent() == nodes.at(i-1));
2474 // Only the paintNode and the one who is childContainer may have more than one child.
2475 Q_ASSERT(n == itemPriv->paintNode || n == itemPriv->childContainerNode() || n->childCount() == 1);
2476 }
2477#endif
2478
2479}
2480
2481bool QQuickWindowPrivate::emitError(QQuickWindow::SceneGraphError error, const QString &msg)
2482{
2483 Q_Q(QQuickWindow);
2484 static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWindow::sceneGraphError);
2485 if (q->isSignalConnected(errorSignal)) {
2486 emit q->sceneGraphError(error, msg);
2487 return true;
2488 }
2489 return false;
2490}
2491
2492void QQuickWindow::maybeUpdate()
2493{
2494 Q_D(QQuickWindow);
2495 if (d->renderControl)
2496 QQuickRenderControlPrivate::get(d->renderControl)->maybeUpdate();
2497 else if (d->windowManager)
2498 d->windowManager->maybeUpdate(this);
2499}
2500
2501void QQuickWindow::cleanupSceneGraph()
2502{
2503 Q_D(QQuickWindow);
2504 if (!d->renderer)
2505 return;
2506
2507 delete d->renderer->rootNode();
2508 delete d->renderer;
2509 d->renderer = nullptr;
2510
2511 d->runAndClearJobs(&d->beforeSynchronizingJobs);
2512 d->runAndClearJobs(&d->afterSynchronizingJobs);
2513 d->runAndClearJobs(&d->beforeRenderingJobs);
2514 d->runAndClearJobs(&d->afterRenderingJobs);
2515 d->runAndClearJobs(&d->afterSwapJobs);
2516}
2517
2518QOpenGLContext *QQuickWindowPrivate::openglContext()
2519{
2520#if QT_CONFIG(opengl)
2521 if (context && context->isValid()) {
2522 QSGRendererInterface *rif = context->sceneGraphContext()->rendererInterface(context);
2523 if (rif) {
2524 Q_Q(QQuickWindow);
2525 return reinterpret_cast<QOpenGLContext *>(rif->getResource(q, QSGRendererInterface::OpenGLContextResource));
2526 }
2527 }
2528#endif
2529 return nullptr;
2530}
2531
2532/*!
2533 Returns true if the scene graph has been initialized; otherwise returns false.
2534 */
2535bool QQuickWindow::isSceneGraphInitialized() const
2536{
2537 Q_D(const QQuickWindow);
2538 return d->context != nullptr && d->context->isValid();
2539}
2540
2541/*!
2542 \fn void QQuickWindow::frameSwapped()
2543
2544 This signal is emitted when a frame has been queued for presenting. With
2545 vertical synchronization enabled the signal is emitted at most once per
2546 vsync interval in a continuously animating scene.
2547
2548 This signal will be emitted from the scene graph rendering thread.
2549*/
2550
2551/*!
2552 \qmlsignal QtQuick::Window::frameSwapped()
2553
2554 This signal is emitted when a frame has been queued for presenting. With
2555 vertical synchronization enabled the signal is emitted at most once per
2556 vsync interval in a continuously animating scene.
2557 */
2558
2559/*!
2560 \fn void QQuickWindow::sceneGraphInitialized()
2561
2562 This signal is emitted when the scene graph has been initialized.
2563
2564 This signal will be emitted from the scene graph rendering thread.
2565 */
2566
2567/*!
2568 \qmlsignal QtQuick::Window::sceneGraphInitialized()
2569 \internal
2570 */
2571
2572/*!
2573 \fn void QQuickWindow::sceneGraphInvalidated()
2574
2575 This signal is emitted when the scene graph has been invalidated.
2576
2577 This signal implies that the graphics rendering context used
2578 has been invalidated and all user resources tied to that context
2579 should be released.
2580
2581 When rendering with OpenGL, the QOpenGLContext of this window will
2582 be bound when this function is called. The only exception is if
2583 the native OpenGL has been destroyed outside Qt's control, for
2584 instance through EGL_CONTEXT_LOST.
2585
2586 This signal will be emitted from the scene graph rendering thread.
2587 */
2588
2589/*!
2590 \qmlsignal QtQuick::Window::sceneGraphInvalidated()
2591 \internal
2592 */
2593
2594/*!
2595 \fn void QQuickWindow::sceneGraphError(SceneGraphError error, const QString &message)
2596
2597 This signal is emitted when an \a error occurred during scene graph initialization.
2598
2599 Applications should connect to this signal if they wish to handle errors,
2600 like graphics context creation failures, in a custom way. When no slot is
2601 connected to the signal, the behavior will be different: Quick will print
2602 the \a message, or show a message box, and terminate the application.
2603
2604 This signal will be emitted from the GUI thread.
2605
2606 \since 5.3
2607 */
2608
2609/*!
2610 \qmlsignal QtQuick::Window::sceneGraphError(SceneGraphError error, QString message)
2611
2612 This signal is emitted when an \a error occurred during scene graph initialization.
2613
2614 You can implement onSceneGraphError(error, message) to handle errors,
2615 such as graphics context creation failures, in a custom way.
2616 If no handler is connected to this signal, Quick will print the \a message,
2617 or show a message box, and terminate the application.
2618
2619 \since 5.3
2620 */
2621
2622/*!
2623 \class QQuickCloseEvent
2624 \internal
2625 \since 5.1
2626
2627 \inmodule QtQuick
2628
2629 \brief Notification that a \l QQuickWindow is about to be closed
2630*/
2631/*!
2632 \qmltype CloseEvent
2633 \nativetype QQuickCloseEvent
2634 \inqmlmodule QtQuick
2635 \ingroup qtquick-visual
2636 \brief Notification that a \l Window is about to be closed.
2637 \since 5.1
2638
2639 Notification that a window is about to be closed by the windowing system
2640 (e.g. the user clicked the title bar close button). The CloseEvent contains
2641 an accepted property which can be set to false to abort closing the window.
2642*/
2643
2644/*!
2645 \qmlproperty bool CloseEvent::accepted
2646
2647 This property indicates whether the application will allow the user to
2648 close the window. It is true by default.
2649*/
2650
2651/*!
2652 \internal
2653 \fn void QQuickWindow::closing(QQuickCloseEvent *close)
2654 \since 5.1
2655
2656 This signal is emitted when the window receives the event \a close from
2657 the windowing system.
2658
2659 On \macos, Qt will create a menu item \c Quit if there is no menu item
2660 whose text is "quit" or "exit". This menu item calls the \c QCoreApplication::quit
2661 signal, not the \c QQuickWindow::closing() signal.
2662
2663 \sa {QMenuBar as a Global Menu Bar}
2664*/
2665
2666/*!
2667 \qmlsignal QtQuick::Window::closing(CloseEvent close)
2668 \since 5.1
2669
2670 This signal is emitted when the user tries to close the window.
2671
2672 This signal includes a \a close parameter. The \c {close.accepted}
2673 property is true by default so that the window is allowed to close; but you
2674 can implement an \c onClosing handler and set \c {close.accepted = false} if
2675 you need to do something else before the window can be closed.
2676 */
2677
2678/*!
2679 Sets the render target for this window to be \a target.
2680
2681 A QQuickRenderTarget serves as an opaque handle for a renderable native
2682 object, most commonly a 2D texture, and associated metadata, such as the
2683 size in pixels.
2684
2685 A default constructed QQuickRenderTarget means no redirection. A valid
2686 \a target, created via one of the static QQuickRenderTarget factory functions,
2687 on the other hand, enables redirection of the rendering of the Qt Quick
2688 scene: it will no longer target the color buffers for the surface
2689 associated with the window, but rather the textures or other graphics
2690 objects specified in \a target.
2691
2692 For example, assuming the scenegraph is using Vulkan to render, one can
2693 redirect its output into a \c VkImage. For graphics APIs like Vulkan, the
2694 image layout must be provided as well. QQuickRenderTarget instances are
2695 implicitly shared and are copyable and can be passed by value. They do not
2696 own the associated native objects (such as, the VkImage in the example),
2697 however.
2698
2699 \badcode
2700 QQuickRenderTarget rt = QQuickRenderTarget::fromVulkanImage(vulkanImage, VK_IMAGE_LAYOUT_PREINITIALIZED, pixelSize);
2701 quickWindow->setRenderTarget(rt);
2702 \endcode
2703
2704 This function is very often used in combination with QQuickRenderControl
2705 and an invisible QQuickWindow, in order to render Qt Quick content into a
2706 texture, without creating an on-screen native window for this QQuickWindow.
2707
2708 When the desired target, or associated data, such as the size, changes,
2709 call this function with a new QQuickRenderTarget. Constructing
2710 QQuickRenderTarget instances and calling this function is cheap, but be
2711 aware that setting a new \a target with a different native object or other
2712 data may lead to potentially expensive initialization steps when the
2713 scenegraph is about to render the next frame. Therefore change the target
2714 only when necessary.
2715
2716 \note The window does not take ownership of any native objects referenced
2717 in \a target.
2718
2719 \note It is the caller's responsibility to ensure the native objects
2720 referred to in \a target are valid for the scenegraph renderer too. For
2721 instance, with Vulkan, Metal, and Direct3D this implies that the texture or
2722 image is created on the same graphics device that is used by the scenegraph
2723 internally. Therefore, when texture objects created on an already existing
2724 device or context are involved, this function is often used in combination
2725 with setGraphicsDevice().
2726
2727 \note With graphics APIs where relevant, the application must pay attention
2728 to image layout transitions performed by the scenegraph. For example, once
2729 a VkImage is associated with the scenegraph by calling this function, its
2730 layout will transition to \c VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL when
2731 rendering a frame.
2732
2733 \warning This function can only be called from the thread doing the
2734 rendering.
2735
2736 \since 6.0
2737
2738 \sa QQuickRenderControl, setGraphicsDevice(), setGraphicsApi()
2739 */
2740void QQuickWindow::setRenderTarget(const QQuickRenderTarget &target)
2741{
2742 Q_D(QQuickWindow);
2743 if (target != d->customRenderTarget) {
2744 d->customRenderTarget = target;
2745 d->redirect.renderTargetDirty = true;
2746 }
2747}
2748
2749/*!
2750 \return the QQuickRenderTarget passed to setRenderTarget(), or a default
2751 constructed one otherwise
2752
2753 \since 6.0
2754
2755 \sa setRenderTarget()
2756 */
2757QQuickRenderTarget QQuickWindow::renderTarget() const
2758{
2759 Q_D(const QQuickWindow);
2760 return d->customRenderTarget;
2761}
2762
2763#ifdef Q_OS_WEBOS
2764class GrabWindowForProtectedContent : public QRunnable
2765{
2766public:
2767 GrabWindowForProtectedContent(QQuickWindow *window, QImage *image, QWaitCondition *condition)
2768 : m_window(window)
2769 , m_image(image)
2770 , m_condition(condition)
2771 {
2772 }
2773
2774 bool checkGrabbable()
2775 {
2776 if (!m_window)
2777 return false;
2778 if (!m_image)
2779 return false;
2780 if (!QQuickWindowPrivate::get(m_window))
2781 return false;
2782
2783 return true;
2784 }
2785
2786 void run() override
2787 {
2788 if (!checkGrabbable())
2789 return;
2790
2791 *m_image = QSGRhiSupport::instance()->grabOffscreenForProtectedContent(m_window);
2792 if (m_condition)
2793 m_condition->wakeOne();
2794 return;
2795 }
2796
2797private:
2798 QQuickWindow *m_window;
2799 QImage *m_image;
2800 QWaitCondition *m_condition;
2801
2802};
2803#endif
2804
2805/*!
2806 Grabs the contents of the window and returns it as an image.
2807
2808 It is possible to call the grabWindow() function when the window is not
2809 visible. This requires that the window is \l{QWindow::create()} {created}
2810 and has a valid size and that no other QQuickWindow instances are rendering
2811 in the same process.
2812
2813 \note When using this window in combination with QQuickRenderControl, the
2814 result of this function is an empty image, unless the \c software backend
2815 is in use. This is because when redirecting the output to an
2816 application-managed graphics resource (such as, a texture) by using
2817 QQuickRenderControl and setRenderTarget(), the application is better suited
2818 for managing and executing an eventual read back operation, since it is in
2819 full control of the resource to begin with.
2820
2821 \warning Calling this function will cause performance problems.
2822
2823 \warning This function can only be called from the GUI thread.
2824 */
2825QImage QQuickWindow::grabWindow()
2826{
2827 Q_D(QQuickWindow);
2828
2829 if (!d->isRenderable() && !d->renderControl) {
2830 // backends like software can grab regardless of the window state
2831 if (d->windowManager && (d->windowManager->flags() & QSGRenderLoop::SupportsGrabWithoutExpose))
2832 return d->windowManager->grab(this);
2833
2834 if (!isSceneGraphInitialized()) {
2835 // We do not have rendering up and running. Forget the render loop,
2836 // do a frame completely offscreen and synchronously into a
2837 // texture. This can be *very* slow due to all the device/context
2838 // and resource initialization but the documentation warns for it,
2839 // and is still important for some use cases.
2840 Q_ASSERT(!d->rhi);
2841 return QSGRhiSupport::instance()->grabOffscreen(this);
2842 }
2843 }
2844
2845#ifdef Q_OS_WEBOS
2846 if (requestedFormat().testOption(QSurfaceFormat::ProtectedContent)) {
2847 QImage image;
2848 QMutex mutex;
2849 QWaitCondition condition;
2850 mutex.lock();
2851 GrabWindowForProtectedContent *job = new GrabWindowForProtectedContent(this, &image, &condition);
2852 if (!job) {
2853 qWarning("QQuickWindow::grabWindow: Failed to create a job for capturing protected content");
2854 mutex.unlock();
2855 return QImage();
2856 }
2857 scheduleRenderJob(job, QQuickWindow::NoStage);
2858 condition.wait(&mutex);
2859 mutex.unlock();
2860 return image;
2861 }
2862#endif
2863 // The common case: we have an exposed window with an initialized
2864 // scenegraph, meaning we can request grabbing via the render loop, or we
2865 // are not targeting the window, in which case the request is to be
2866 // forwarded to the rendercontrol.
2867 if (d->renderControl)
2868 return QQuickRenderControlPrivate::get(d->renderControl)->grab();
2869 else if (d->windowManager)
2870 return d->windowManager->grab(this);
2871
2872 return QImage();
2873}
2874
2875/*!
2876 Returns an incubation controller that splices incubation between frames
2877 for this window. QQuickView automatically installs this controller for you,
2878 otherwise you will need to install it yourself using \l{QQmlEngine::setIncubationController()}.
2879
2880 The controller is owned by the window and will be destroyed when the window
2881 is deleted.
2882*/
2883QQmlIncubationController *QQuickWindow::incubationController() const
2884{
2885 Q_D(const QQuickWindow);
2886
2887 if (!d->windowManager)
2888 return nullptr; // TODO: make sure that this is safe
2889
2890 if (!d->incubationController)
2891 d->incubationController = new QQuickWindowIncubationController(d->windowManager);
2892 return d->incubationController;
2893}
2894
2895
2896
2897/*!
2898 \enum QQuickWindow::CreateTextureOption
2899
2900 The CreateTextureOption enums are used to customize a texture is wrapped.
2901
2902 \value TextureHasAlphaChannel The texture has an alpha channel and should
2903 be drawn using blending.
2904
2905 \value TextureHasMipmaps The texture has mipmaps and can be drawn with
2906 mipmapping enabled.
2907
2908 \value TextureOwnsGLTexture As of Qt 6.0, this flag is not used in practice
2909 and is ignored. Native graphics resource ownership is not transferable to
2910 the wrapping QSGTexture, because Qt Quick may not have the necessary details
2911 on how such an object and the associated memory should be freed.
2912
2913 \value TextureCanUseAtlas The image can be uploaded into a texture atlas.
2914
2915 \value TextureIsOpaque The texture will return false for
2916 QSGTexture::hasAlphaChannel() and will not be blended. This flag was added
2917 in Qt 5.6.
2918
2919 */
2920
2921/*!
2922 \enum QQuickWindow::SceneGraphError
2923
2924 This enum describes the error in a sceneGraphError() signal.
2925
2926 \value ContextNotAvailable graphics context creation failed. This typically means that
2927 no suitable OpenGL implementation was found, for example because no graphics drivers
2928 are installed and so no OpenGL 2 support is present. On mobile and embedded boards
2929 that use OpenGL ES such an error is likely to indicate issues in the windowing system
2930 integration and possibly an incorrect configuration of Qt.
2931
2932 \since 5.3
2933 */
2934
2935/*!
2936 \enum QQuickWindow::TextRenderType
2937 \since 5.10
2938
2939 This enum describes the default render type of text-like elements in Qt
2940 Quick (\l Text, \l TextInput, etc.).
2941
2942 Select NativeTextRendering if you prefer text to look native on the target
2943 platform and do not require advanced features such as transformation of the
2944 text. Using such features in combination with the NativeTextRendering
2945 render type will lend poor and sometimes pixelated results.
2946
2947 Both \c QtTextRendering and \c CurveTextRendering are hardware-accelerated techniques.
2948 \c QtTextRendering is the faster of the two, but uses more memory and will exhibit rendering
2949 artifacts at large sizes. \c CurveTextRendering should be considered as an alternative in cases
2950 where \c QtTextRendering does not give good visual results or where reducing graphics memory
2951 consumption is a priority.
2952
2953 \value QtTextRendering Use Qt's own rasterization algorithm.
2954 \value NativeTextRendering Use the operating system's native rasterizer for text.
2955 \value CurveTextRendering Text is rendered using a curve rasterizer running directly on
2956 the graphics hardware. (Introduced in Qt 6.7.0.)
2957*/
2958
2959/*!
2960 \fn void QQuickWindow::beforeSynchronizing()
2961
2962 This signal is emitted before the scene graph is synchronized with the QML state.
2963
2964 Even though the signal is emitted from the scene graph rendering thread,
2965 the GUI thread is guaranteed to be blocked, like it is in
2966 QQuickItem::updatePaintNode(). Therefore, it is safe to access GUI thread
2967 thread data in a slot or lambda that is connected with
2968 Qt::DirectConnection.
2969
2970 This signal can be used to do any preparation required before calls to
2971 QQuickItem::updatePaintNode().
2972
2973 When using OpenGL, the QOpenGLContext used for rendering by the scene graph
2974 will be bound at this point.
2975
2976 \warning This signal is emitted from the scene graph rendering thread. If your
2977 slot function needs to finish before execution continues, you must make sure that
2978 the connection is direct (see Qt::ConnectionType).
2979
2980 \warning When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific
2981 states and leaving these enabled or set to non-default values when returning
2982 from the connected slot can interfere with the scene graph's rendering.
2983*/
2984
2985/*!
2986 \qmlsignal QtQuick::Window::beforeSynchronizing()
2987 \internal
2988*/
2989
2990/*!
2991 \fn void QQuickWindow::afterSynchronizing()
2992
2993 This signal is emitted after the scene graph is synchronized with the QML state.
2994
2995 This signal can be used to do preparation required after calls to
2996 QQuickItem::updatePaintNode(), while the GUI thread is still locked.
2997
2998 When using OpenGL, the QOpenGLContext used for rendering by the scene graph
2999 will be bound at this point.
3000
3001 \warning This signal is emitted from the scene graph rendering thread. If your
3002 slot function needs to finish before execution continues, you must make sure that
3003 the connection is direct (see Qt::ConnectionType).
3004
3005 \warning When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific
3006 states and leaving these enabled or set to non-default values when returning
3007 from the connected slot can interfere with the scene graph's rendering.
3008
3009 \since 5.3
3010 */
3011
3012/*!
3013 \qmlsignal QtQuick::Window::afterSynchronizing()
3014 \internal
3015 \since 5.3
3016 */
3017
3018/*!
3019 \fn void QQuickWindow::beforeRendering()
3020
3021 This signal is emitted after the preparations for the frame have been done,
3022 meaning there is a command buffer in recording mode, where applicable. If
3023 desired, the slot function connected to this signal can query native
3024 resources like the command before via QSGRendererInterface. Note however
3025 that the recording of the main render pass is not yet started at this point
3026 and it is not possible to add commands within that pass. Starting a pass
3027 means clearing the color, depth, and stencil buffers so it is not possible
3028 to achieve an underlay type of rendering by just connecting to this
3029 signal. Rather, connect to beforeRenderPassRecording(). However, connecting
3030 to this signal is still important if the recording of copy type of commands
3031 is desired since those cannot be enqueued within a render pass.
3032
3033 \warning This signal is emitted from the scene graph rendering thread. If your
3034 slot function needs to finish before execution continues, you must make sure that
3035 the connection is direct (see Qt::ConnectionType).
3036
3037 \note When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific
3038 states and leaving these enabled or set to non-default values when
3039 returning from the connected slot can interfere with the scene graph's
3040 rendering. The QOpenGLContext used for rendering by the scene graph will be
3041 bound when the signal is emitted.
3042
3043 \sa rendererInterface(), {Scene Graph - RHI Under QML}, {Scene Graph -
3044 OpenGL Under QML}, {Scene Graph - Metal Under QML}, {Scene Graph - Vulkan
3045 Under QML}, {Scene Graph - Direct3D 11 Under QML}
3046*/
3047
3048/*!
3049 \qmlsignal QtQuick::Window::beforeRendering()
3050 \internal
3051*/
3052
3053/*!
3054 \fn void QQuickWindow::afterRendering()
3055
3056 The signal is emitted after scene graph has added its commands to the
3057 command buffer, which is not yet submitted to the graphics queue. If
3058 desired, the slot function connected to this signal can query native
3059 resources, like the command buffer, before via QSGRendererInterface. Note
3060 however that the render pass (or passes) are already recorded at this point
3061 and it is not possible to add more commands within the scenegraph's
3062 pass. Instead, use afterRenderPassRecording() for that. This signal has
3063 therefore limited use in Qt 6, unlike in Qt 5. Rather, it is the combination
3064 of beforeRendering() and beforeRenderPassRecording(), or beforeRendering()
3065 and afterRenderPassRecording(), that is typically used to achieve under- or
3066 overlaying of the custom rendering.
3067
3068 \warning This signal is emitted from the scene graph rendering thread. If your
3069 slot function needs to finish before execution continues, you must make sure that
3070 the connection is direct (see Qt::ConnectionType).
3071
3072 \note When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific
3073 states and leaving these enabled or set to non-default values when
3074 returning from the connected slot can interfere with the scene graph's
3075 rendering. The QOpenGLContext used for rendering by the scene graph will be
3076 bound when the signal is emitted.
3077
3078 \sa rendererInterface(), {Scene Graph - RHI Under QML}, {Scene Graph -
3079 OpenGL Under QML}, {Scene Graph - Metal Under QML}, {Scene Graph - Vulkan
3080 Under QML}, {Scene Graph - Direct3D 11 Under QML}
3081 */
3082
3083/*!
3084 \qmlsignal QtQuick::Window::afterRendering()
3085 \internal
3086 */
3087
3088/*!
3089 \fn void QQuickWindow::beforeRenderPassRecording()
3090
3091 This signal is emitted before the scenegraph starts recording commands for
3092 the main render pass. (Layers have their own passes and are fully recorded
3093 by the time this signal is emitted.) The render pass is already active on
3094 the command buffer when the signal is emitted.
3095
3096 This signal is emitted later than beforeRendering() and it guarantees that
3097 not just the frame, but also the recording of the scenegraph's main render
3098 pass is active. This allows inserting commands without having to generate an
3099 entire, separate render pass (which would typically clear the attached
3100 images). The native graphics objects can be queried via
3101 QSGRendererInterface.
3102
3103 \note Resource updates (uploads, copies) typically cannot be enqueued from
3104 within a render pass. Therefore, more complex user rendering will need to
3105 connect to both beforeRendering() and this signal.
3106
3107 \warning This signal is emitted from the scene graph rendering thread. If your
3108 slot function needs to finish before execution continues, you must make sure that
3109 the connection is direct (see Qt::ConnectionType).
3110
3111 \sa rendererInterface()
3112
3113 \since 5.14
3114
3115 \sa {Scene Graph - RHI Under QML}
3116*/
3117
3118/*!
3119 \qmlsignal QtQuick::Window::beforeRenderPassRecording()
3120 \internal
3121 \since 5.14
3122*/
3123
3124/*!
3125 \fn void QQuickWindow::afterRenderPassRecording()
3126
3127 This signal is emitted after the scenegraph has recorded the commands for
3128 its main render pass, but the pass is not yet finalized on the command
3129 buffer.
3130
3131 This signal is emitted earlier than afterRendering(), and it guarantees that
3132 not just the frame but also the recording of the scenegraph's main render
3133 pass is still active. This allows inserting commands without having to
3134 generate an entire, separate render pass (which would typically clear the
3135 attached images). The native graphics objects can be queried via
3136 QSGRendererInterface.
3137
3138 \note Resource updates (uploads, copies) typically cannot be enqueued from
3139 within a render pass. Therefore, more complex user rendering will need to
3140 connect to both beforeRendering() and this signal.
3141
3142 \warning This signal is emitted from the scene graph rendering thread. If your
3143 slot function needs to finish before execution continues, you must make sure that
3144 the connection is direct (see Qt::ConnectionType).
3145
3146 \sa rendererInterface()
3147
3148 \since 5.14
3149
3150 \sa {Scene Graph - RHI Under QML}
3151*/
3152
3153/*!
3154 \fn void QQuickWindow::beforeFrameBegin()
3155
3156 This signal is emitted before the scene graph starts preparing the frame.
3157 This precedes signals like beforeSynchronizing() or beforeRendering(). It is
3158 the earliest signal that is emitted by the scene graph rendering thread
3159 when starting to prepare a new frame.
3160
3161 This signal is relevant for lower level graphics frameworks that need to
3162 execute certain operations, such as resource cleanup, at a stage where Qt
3163 Quick has not initiated the recording of a new frame via the underlying
3164 rendering hardware interface APIs.
3165
3166 \warning This signal is emitted from the scene graph rendering thread. If your
3167 slot function needs to finish before execution continues, you must make sure that
3168 the connection is direct (see Qt::ConnectionType).
3169
3170 \since 6.0
3171
3172 \sa afterFrameEnd(), rendererInterface()
3173*/
3174
3175/*!
3176 \qmlsignal QtQuick::Window::beforeFrameBegin()
3177 \internal
3178*/
3179
3180/*!
3181 \fn void QQuickWindow::afterFrameEnd()
3182
3183 This signal is emitted when the scene graph has submitted a frame. This is
3184 emitted after all other related signals, such as afterRendering(). It is
3185 the last signal that is emitted by the scene graph rendering thread when
3186 rendering a frame.
3187
3188 \note Unlike frameSwapped(), this signal is guaranteed to be emitted also
3189 when the Qt Quick output is redirected via QQuickRenderControl.
3190
3191 \warning This signal is emitted from the scene graph rendering thread. If your
3192 slot function needs to finish before execution continues, you must make sure that
3193 the connection is direct (see Qt::ConnectionType).
3194
3195 \since 6.0
3196
3197 \sa beforeFrameBegin(), rendererInterface()
3198*/
3199
3200/*!
3201 \qmlsignal QtQuick::Window::afterFrameEnd()
3202 \internal
3203*/
3204
3205/*!
3206 \qmlsignal QtQuick::Window::afterRenderPassRecording()
3207 \internal
3208 \since 5.14
3209*/
3210
3211/*!
3212 \fn void QQuickWindow::afterAnimating()
3213
3214 This signal is emitted on the GUI thread before requesting the render thread to
3215 perform the synchronization of the scene graph.
3216
3217 Unlike the other similar signals, this one is emitted on the GUI thread
3218 instead of the render thread. It can be used to synchronize external
3219 animation systems with the QML content. At the same time this means that
3220 this signal is not suitable for triggering graphics operations.
3221
3222 \since 5.3
3223 */
3224
3225/*!
3226 \qmlsignal QtQuick::Window::afterAnimating()
3227
3228 This signal is emitted on the GUI thread before requesting the render thread to
3229 perform the synchronization of the scene graph.
3230
3231 You can implement onAfterAnimating to do additional processing after each animation step.
3232
3233 \since 5.3
3234 */
3235
3236/*!
3237 \fn void QQuickWindow::sceneGraphAboutToStop()
3238
3239 This signal is emitted on the render thread when the scene graph is
3240 about to stop rendering. This happens usually because the window
3241 has been hidden.
3242
3243 Applications may use this signal to release resources, but should be
3244 prepared to reinstantiated them again fast. The scene graph and the
3245 graphics context are not released at this time.
3246
3247 \warning This signal is emitted from the scene graph rendering thread. If your
3248 slot function needs to finish before execution continues, you must make sure that
3249 the connection is direct (see Qt::ConnectionType).
3250
3251 \warning Make very sure that a signal handler for sceneGraphAboutToStop() leaves the
3252 graphics context in the same state as it was when the signal handler was entered.
3253 Failing to do so can result in the scene not rendering properly.
3254
3255 \sa sceneGraphInvalidated()
3256 \since 5.3
3257 */
3258
3259/*!
3260 \qmlsignal QtQuick::Window::sceneGraphAboutToStop()
3261 \internal
3262 \since 5.3
3263 */
3264
3265/*!
3266 \overload
3267 */
3268
3269QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
3270{
3271 return createTextureFromImage(image, {});
3272}
3273
3274
3275/*!
3276 Creates a new QSGTexture from the supplied \a image. If the image has an
3277 alpha channel, the corresponding texture will have an alpha channel.
3278
3279 The caller of the function is responsible for deleting the returned texture.
3280 The underlying native texture object is then destroyed together with the
3281 QSGTexture.
3282
3283 When \a options contains TextureCanUseAtlas, the engine may put the image
3284 into a texture atlas. Textures in an atlas need to rely on
3285 QSGTexture::normalizedTextureSubRect() for their geometry and will not
3286 support QSGTexture::Repeat. Other values from CreateTextureOption are
3287 ignored.
3288
3289 When \a options contains TextureIsOpaque, the engine will create an RGB
3290 texture which returns false for QSGTexture::hasAlphaChannel(). Opaque
3291 textures will in most cases be faster to render. When this flag is not set,
3292 the texture will have an alpha channel based on the image's format.
3293
3294 When \a options contains TextureHasMipmaps, the engine will create a texture
3295 which can use mipmap filtering. Mipmapped textures can not be in an atlas.
3296
3297 Setting TextureHasAlphaChannel in \a options serves no purpose for this
3298 function since assuming an alpha channel and blending is the default. To opt
3299 out, set TextureIsOpaque.
3300
3301 When the scene graph uses OpenGL, the returned texture will be using \c
3302 GL_TEXTURE_2D as texture target and \c GL_RGBA as internal format. With
3303 other graphics APIs, the texture format is typically \c RGBA8. Reimplement
3304 QSGTexture to create textures with different parameters.
3305
3306 \warning This function will return 0 if the scene graph has not yet been
3307 initialized.
3308
3309 \warning The returned texture is not memory managed by the scene graph and
3310 must be explicitly deleted by the caller on the rendering thread. This is
3311 achieved by deleting the texture from a QSGNode destructor or by using
3312 deleteLater() in the case where the texture already has affinity to the
3313 rendering thread.
3314
3315 This function can be called from both the main and the render thread.
3316
3317 \sa sceneGraphInitialized(), QSGTexture
3318 */
3319
3320QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const
3321{
3322 Q_D(const QQuickWindow);
3323 if (!isSceneGraphInitialized()) // check both for d->context and d->context->isValid()
3324 return nullptr;
3325 uint flags = 0;
3326 if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas;
3327 if (options & TextureHasMipmaps) flags |= QSGRenderContext::CreateTexture_Mipmap;
3328 if (!(options & TextureIsOpaque)) flags |= QSGRenderContext::CreateTexture_Alpha;
3329 return d->context->createTexture(image, flags);
3330}
3331
3332/*!
3333 Creates a new QSGTexture from the supplied \a texture.
3334
3335 Use \a options to customize the texture attributes. Only the
3336 TextureHasAlphaChannel flag is taken into account by this function. When
3337 set, the resulting QSGTexture is always treated by the scene graph renderer
3338 as needing blending. For textures that are fully opaque, not setting the
3339 flag can save the cost of performing alpha blending during rendering. The
3340 flag has no direct correspondence to the \l{QRhiTexture::format()}{format}
3341 of the QRhiTexture, i.e. not setting the flag while having a texture format
3342 such as the commonly used \l QRhiTexture::RGBA8 is perfectly normal.
3343
3344 Mipmapping is not controlled by \a options since \a texture is already
3345 created and has the presence or lack of mipmaps baked in.
3346
3347 The returned QSGTexture owns the QRhiTexture, meaning \a texture is
3348 destroyed together with the returned QSGTexture.
3349
3350 If \a texture owns its underlying native graphics resources (OpenGL texture
3351 object, Vulkan image, etc.), that depends on how the QRhiTexture was created
3352 (\l{QRhiTexture::create()} or \l{QRhiTexture::createFrom()}), and that is
3353 not controlled or changed by this function.
3354
3355 \note This is only functional when the scene graph has already initialized
3356 and is using the default, \l{QRhi}-based \l{Scene Graph
3357 Adaptations}{adaptation}. The return value is \nullptr otherwise.
3358
3359 \note This function can only be called on the scene graph render thread.
3360
3361 \since 6.6
3362
3363 \sa createTextureFromImage(), sceneGraphInitialized(), QSGTexture
3364 */
3365QSGTexture *QQuickWindow::createTextureFromRhiTexture(QRhiTexture *texture, CreateTextureOptions options) const
3366{
3367 Q_D(const QQuickWindow);
3368 if (!d->rhi)
3369 return nullptr;
3370
3371 QSGPlainTexture *t = new QSGPlainTexture;
3372 t->setOwnsTexture(true);
3373 t->setTexture(texture);
3374 t->setHasAlphaChannel(options & QQuickWindow::TextureHasAlphaChannel);
3375 t->setTextureSize(texture->pixelSize());
3376 return t;
3377}
3378
3379// Legacy, private alternative to createTextureFromRhiTexture() that internally
3380// creates a QRhiTexture wrapping the existing native graphics resource.
3381// New code should prefer using the public API.
3382QSGTexture *QQuickWindowPrivate::createTextureFromNativeTexture(quint64 nativeObjectHandle,
3383 int nativeLayoutOrState,
3384 uint nativeFormat,
3385 const QSize &size,
3386 QQuickWindow::CreateTextureOptions options,
3387 TextureFromNativeTextureFlags flags) const
3388{
3389 if (!rhi)
3390 return nullptr;
3391
3392 QSGPlainTexture *texture = new QSGPlainTexture;
3393 texture->setTextureFromNativeTexture(rhi, nativeObjectHandle, nativeLayoutOrState, nativeFormat,
3394 size, options, flags);
3395 texture->setHasAlphaChannel(options & QQuickWindow::TextureHasAlphaChannel);
3396 // note that the QRhiTexture does not (and cannot) own the native object
3397 texture->setOwnsTexture(true); // texture meaning the QRhiTexture here, not the native object
3398 texture->setTextureSize(size);
3399 return texture;
3400}
3401
3402/*!
3403 \qmlproperty color Window::color
3404
3405 The background color for the window.
3406
3407 Setting this property is more efficient than using a separate Rectangle.
3408
3409 \note If you set the color to \c "transparent" or to a color with alpha translucency,
3410 you should also set suitable \l flags such as \c {flags: Qt.FramelessWindowHint}.
3411 Otherwise, window translucency may not be enabled consistently on all platforms.
3412*/
3413
3414/*!
3415 \property QQuickWindow::color
3416 \brief The color used to clear the color buffer at the beginning of each frame.
3417
3418 By default, the clear color is white.
3419
3420 \sa setDefaultAlphaBuffer()
3421 */
3422
3423void QQuickWindow::setColor(const QColor &color)
3424{
3425 Q_D(QQuickWindow);
3426 if (color == d->clearColor)
3427 return;
3428
3429 if (color.alpha() != d->clearColor.alpha()) {
3430 QSurfaceFormat fmt = requestedFormat();
3431 if (color.alpha() < 255)
3432 fmt.setAlphaBufferSize(8);
3433 else
3434 fmt.setAlphaBufferSize(-1);
3435 setFormat(fmt);
3436 }
3437 d->clearColor = color;
3438 emit colorChanged(color);
3439 update();
3440}
3441
3442QColor QQuickWindow::color() const
3443{
3444 return d_func()->clearColor;
3445}
3446
3447/*!
3448 \brief Returns whether to use alpha transparency on newly created windows.
3449
3450 \since 5.1
3451 \sa setDefaultAlphaBuffer()
3452 */
3453bool QQuickWindow::hasDefaultAlphaBuffer()
3454{
3455 return QQuickWindowPrivate::defaultAlphaBuffer;
3456}
3457
3458/*!
3459 \brief \a useAlpha specifies whether to use alpha transparency on newly created windows.
3460 \since 5.1
3461
3462 In any application which expects to create translucent windows, it's necessary to set
3463 this to true before creating the first QQuickWindow. The default value is false.
3464
3465 \sa hasDefaultAlphaBuffer()
3466 */
3467void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
3468{
3469 QQuickWindowPrivate::defaultAlphaBuffer = useAlpha;
3470}
3471
3472/*!
3473 \struct QQuickWindow::GraphicsStateInfo
3474 \inmodule QtQuick
3475 \since 5.14
3476
3477 \brief Describes some of the RHI's graphics state at the point of a
3478 \l{QQuickWindow::beginExternalCommands()}{beginExternalCommands()} call.
3479 */
3480
3481/*!
3482 \variable QQuickWindow::GraphicsStateInfo::currentFrameSlot
3483 \since 5.14
3484 \brief the current frame slot index while recording a frame.
3485
3486 When the scenegraph renders with lower level 3D APIs such as Vulkan or
3487 Metal, it is the Qt's responsibility to ensure blocking whenever starting a
3488 new frame and finding the CPU is already a certain number of frames ahead
3489 of the GPU (because the command buffer submitted in frame no. \c{current} -
3490 \c{FramesInFlight} has not yet completed). With other graphics APIs, such
3491 as OpenGL or Direct 3D 11 this level of control is not exposed to the API
3492 client but rather handled by the implementation of the graphics API.
3493
3494 By extension, this also means that the appropriate double (or triple)
3495 buffering of resources, such as buffers, is up to the graphics API client
3496 to manage. Most commonly, a uniform buffer where the data changes between
3497 frames cannot simply change its contents when submitting a frame, given
3498 that the frame may still be active ("in flight") when starting to record
3499 the next frame. To avoid stalling the pipeline, one way is to have multiple
3500 buffers (and memory allocations) under the hood, thus realizing at least a
3501 double buffered scheme for such resources.
3502
3503 Applications that integrate rendering done directly with a graphics API
3504 such as Vulkan may want to perform a similar double or triple buffering of
3505 their own graphics resources, in a way that is compatible with the Qt
3506 rendering engine's frame submission process. That then involves knowing the
3507 values for the maximum number of in-flight frames (which is typically 2 or
3508 3) and the current frame slot index, which is a number running 0, 1, ..,
3509 FramesInFlight-1, and then wrapping around. The former is exposed in the
3510 \l{QQuickWindow::GraphicsStateInfo::framesInFlight}{framesInFlight}
3511 variable. The latter, current index, is this value.
3512
3513 For an example of using these values in practice, refer to the {Scene Graph
3514 - Vulkan Under QML} and {Scene Graph - Vulkan Texture Import} examples.
3515 */
3516
3517/*!
3518 \variable QQuickWindow::GraphicsStateInfo::framesInFlight
3519 \since 5.14
3520 \brief the maximum number of frames kept in flight.
3521
3522 See \l{QQuickWindow::GraphicsStateInfo::currentFrameSlot}{currentFrameSlot}
3523 for a detailed description.
3524 */
3525
3526/*!
3527 \return a reference to a GraphicsStateInfo struct describing some of the
3528 RHI's internal state, in particular, the double or tripple buffering status
3529 of the backend (such as, the Vulkan or Metal integrations). This is
3530 relevant when the underlying graphics APIs is Vulkan or Metal, and the
3531 external rendering code wishes to perform double or tripple buffering of
3532 its own often-changing resources, such as, uniform buffers, in order to
3533 avoid stalling the pipeline.
3534 */
3535const QQuickWindow::GraphicsStateInfo &QQuickWindow::graphicsStateInfo()
3536{
3537 Q_D(QQuickWindow);
3538 if (d->rhi) {
3539 d->rhiStateInfo.currentFrameSlot = d->rhi->currentFrameSlot();
3540 d->rhiStateInfo.framesInFlight = d->rhi->resourceLimit(QRhi::FramesInFlight);
3541 }
3542 return d->rhiStateInfo;
3543}
3544
3545/*!
3546 When mixing raw graphics (OpenGL, Vulkan, Metal, etc.) commands with scene
3547 graph rendering, it is necessary to call this function before recording
3548 commands to the command buffer used by the scene graph to render its main
3549 render pass. This is to avoid clobbering state.
3550
3551 In practice this function is often called from a slot connected to the
3552 beforeRenderPassRecording() or afterRenderPassRecording() signals.
3553
3554 The function does not need to be called when recording commands to the
3555 application's own command buffer (such as, a VkCommandBuffer or
3556 MTLCommandBuffer + MTLRenderCommandEncoder created and managed by the
3557 application, not retrieved from the scene graph). With graphics APIs where
3558 no native command buffer concept is exposed (OpenGL, Direct 3D 11),
3559 beginExternalCommands() and endExternalCommands() together provide a
3560 replacement for the Qt 5 resetOpenGLState() function.
3561
3562 Calling this function and endExternalCommands() is not necessary within the
3563 \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode
3564 because the scene graph performs the necessary steps implicitly for render
3565 nodes.
3566
3567 Native graphics objects (such as, graphics device, command buffer or
3568 encoder) are accessible via QSGRendererInterface::getResource().
3569
3570 \warning Watch out for the fact that
3571 QSGRendererInterface::CommandListResource may return a different object
3572 between beginExternalCommands() - endExternalCommands(). This can happen
3573 when the underlying implementation provides a dedicated secondary command
3574 buffer for recording external graphics commands within a render pass.
3575 Therefore, always query CommandListResource after calling this function. Do
3576 not attempt to reuse an object from an earlier query.
3577
3578 \note When the scenegraph is using OpenGL, pay attention to the fact that
3579 the OpenGL state in the context can have arbitrary settings, and this
3580 function does not perform any resetting of the state back to defaults.
3581
3582 \sa endExternalCommands(), QQuickOpenGLUtils::resetOpenGLState()
3583
3584 \since 5.14
3585 */
3586void QQuickWindow::beginExternalCommands()
3587{
3588 Q_D(QQuickWindow);
3589 if (d->rhi && d->context && d->context->isValid()) {
3590 QSGDefaultRenderContext *rc = static_cast<QSGDefaultRenderContext *>(d->context);
3591 QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
3592 if (cb)
3593 cb->beginExternal();
3594 }
3595}
3596
3597/*!
3598 When mixing raw graphics (OpenGL, Vulkan, Metal, etc.) commands with scene
3599 graph rendering, it is necessary to call this function after recording
3600 commands to the command buffer used by the scene graph to render its main
3601 render pass. This is to avoid clobbering state.
3602
3603 In practice this function is often called from a slot connected to the
3604 beforeRenderPassRecording() or afterRenderPassRecording() signals.
3605
3606 The function does not need to be called when recording commands to the
3607 application's own command buffer (such as, a VkCommandBuffer or
3608 MTLCommandBuffer + MTLRenderCommandEncoder created and managed by the
3609 application, not retrieved from the scene graph). With graphics APIs where
3610 no native command buffer concept is exposed (OpenGL, Direct 3D 11),
3611 beginExternalCommands() and endExternalCommands() together provide a
3612 replacement for the Qt 5 resetOpenGLState() function.
3613
3614 Calling this function and beginExternalCommands() is not necessary within the
3615 \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode
3616 because the scene graph performs the necessary steps implicitly for render
3617 nodes.
3618
3619 \sa beginExternalCommands(), QQuickOpenGLUtils::resetOpenGLState()
3620
3621 \since 5.14
3622 */
3623void QQuickWindow::endExternalCommands()
3624{
3625 Q_D(QQuickWindow);
3626 if (d->rhi && d->context && d->context->isValid()) {
3627 QSGDefaultRenderContext *rc = static_cast<QSGDefaultRenderContext *>(d->context);
3628 QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
3629 if (cb)
3630 cb->endExternal();
3631 }
3632}
3633
3634/*!
3635 \qmlproperty string Window::title
3636
3637 The window's title in the windowing system.
3638
3639 The window title might appear in the title area of the window decorations,
3640 depending on the windowing system and the window flags. It might also
3641 be used by the windowing system to identify the window in other contexts,
3642 such as in the task switcher.
3643 */
3644
3645/*!
3646 \qmlproperty Qt::WindowModality Window::modality
3647
3648 The modality of the window.
3649
3650 A modal window prevents other windows from receiving input events.
3651 Possible values are Qt.NonModal (the default), Qt.WindowModal,
3652 and Qt.ApplicationModal.
3653 */
3654
3655/*!
3656 \qmlproperty Qt::WindowFlags Window::flags
3657
3658 The window flags of the window.
3659
3660 The window flags control the window's appearance in the windowing system,
3661 whether it's a dialog, popup, or a regular window, and whether it should
3662 have a title bar, etc.
3663
3664 The flags that you read from this property might differ from the ones
3665 that you set if the requested flags could not be fulfilled.
3666
3667 \snippet qml/splashWindow.qml entire
3668
3669 \sa Qt::WindowFlags, {Qt Quick Examples - Window and Screen}
3670 */
3671
3672/*!
3673 \qmlattachedproperty Window Window::window
3674 \since 5.7
3675
3676 This attached property holds the item's window.
3677 The Window attached property can be attached to any Item.
3678*/
3679
3680/*!
3681 \qmlattachedproperty int Window::width
3682 \qmlattachedproperty int Window::height
3683 \since 5.5
3684
3685 These attached properties hold the size of the item's window.
3686 The Window attached property can be attached to any Item.
3687*/
3688
3689/*!
3690 \qmlproperty int Window::x
3691 \qmlproperty int Window::y
3692 \qmlproperty int Window::width
3693 \qmlproperty int Window::height
3694
3695 Defines the window's position and size.
3696
3697 The (x,y) position is relative to the \l Screen if there is only one,
3698 or to the virtual desktop (arrangement of multiple screens).
3699
3700 \note Not all windowing systems support setting or querying top level
3701 window positions. On such a system, programmatically moving windows
3702 may not have any effect, and artificial values may be returned for
3703 the current positions, such as \c QPoint(0, 0).
3704
3705 \qml
3706 Window { x: 100; y: 100; width: 100; height: 100 }
3707 \endqml
3708
3709 \image screen-and-window-dimensions.jpg {Diagram showing Window.x,
3710 Window.y positions and Screen available dimensions}
3711 */
3712
3713/*!
3714 \qmlproperty int Window::minimumWidth
3715 \qmlproperty int Window::minimumHeight
3716 \since 5.1
3717
3718 Defines the window's minimum size.
3719
3720 This is a hint to the window manager to prevent resizing below the specified
3721 width and height.
3722 */
3723
3724/*!
3725 \qmlproperty int Window::maximumWidth
3726 \qmlproperty int Window::maximumHeight
3727 \since 5.1
3728
3729 Defines the window's maximum size.
3730
3731 This is a hint to the window manager to prevent resizing above the specified
3732 width and height.
3733 */
3734
3735/*!
3736 \qmlproperty bool Window::visible
3737
3738 Whether the window is visible on the screen.
3739
3740 Setting visible to false is the same as setting \l visibility to \l {QWindow::}{Hidden}.
3741
3742 The default value is \c false, unless overridden by setting \l visibility.
3743
3744 \sa visibility
3745 */
3746
3747/*!
3748 \keyword qml-window-visibility-prop
3749 \qmlproperty QWindow::Visibility Window::visibility
3750
3751 The screen-occupation state of the window.
3752
3753 Visibility is whether the window should appear in the windowing system as
3754 normal, minimized, maximized, fullscreen or hidden.
3755
3756 To set the visibility to \l {QWindow::}{AutomaticVisibility} means to give the
3757 window a default visible state, which might be \l {QWindow::}{FullScreen} or
3758 \l {QWindow::}{Windowed} depending on the platform. However when reading the
3759 visibility property you will always get the actual state, never
3760 \c AutomaticVisibility.
3761
3762 When a window is not \l visible, its visibility is \c Hidden.
3763 Setting visibility to \l {QWindow::}{Hidden} is the same as setting \l visible to \c false.
3764
3765 The default value is \l {QWindow::}{Hidden}
3766
3767 \snippet qml/windowVisibility.qml entire
3768
3769 \sa visible, {Qt Quick Examples - Window and Screen}
3770 \since 5.1
3771 */
3772
3773/*!
3774 \qmlattachedproperty QWindow::Visibility Window::visibility
3775 \readonly
3776 \since 5.4
3777
3778 This attached property holds whether the window is currently shown
3779 in the windowing system as normal, minimized, maximized, fullscreen or
3780 hidden. The \c Window attached property can be attached to any Item. If the
3781 item is not shown in any window, the value will be \l {QWindow::}{Hidden}.
3782
3783 \sa visible, {qml-window-visibility-prop}{visibility}
3784*/
3785
3786/*!
3787 \qmlproperty Item Window::contentItem
3788 \readonly
3789 \brief The invisible root item of the scene.
3790*/
3791
3792/*!
3793 \qmlproperty Qt::ScreenOrientation Window::contentOrientation
3794
3795 This is a hint to the window manager in case it needs to display
3796 additional content like popups, dialogs, status bars, or similar
3797 in relation to the window.
3798
3799 The recommended orientation is \l {Screen::orientation}{Screen.orientation}, but
3800 an application doesn't have to support all possible orientations,
3801 and thus can opt to ignore the current screen orientation.
3802
3803 The difference between the window and the content orientation
3804 determines how much to rotate the content by.
3805
3806 The default value is Qt::PrimaryOrientation.
3807
3808 \sa Screen
3809
3810 \since 5.1
3811 */
3812
3813/*!
3814 \qmlproperty real Window::opacity
3815
3816 The opacity of the window.
3817
3818 If the windowing system supports window opacity, this can be used to fade the
3819 window in and out, or to make it semitransparent.
3820
3821 A value of 1.0 or above is treated as fully opaque, whereas a value of 0.0 or below
3822 is treated as fully transparent. Values inbetween represent varying levels of
3823 translucency between the two extremes.
3824
3825 The default value is 1.0.
3826
3827 \since 5.1
3828 */
3829
3830/*!
3831 \qmlproperty Screen Window::screen
3832
3833 The screen with which the window is associated.
3834
3835 If specified before showing a window, will result in the window being shown
3836 on that screen, unless an explicit window position has been set. The value
3837 must be an element from the \l{Application::screens}{Application.screens}
3838 array.
3839
3840 \note To ensure that the window is associated with the desired screen when
3841 the underlying native window is created, make sure this property is set as
3842 early as possible and that the setting of its value is not deferred. This
3843 can be particularly important on embedded platforms without a windowing system,
3844 where only one window per screen is allowed at a time. Setting the screen after
3845 a window has been created does not move the window if the new screen is part of
3846 the same virtual desktop as the old screen.
3847
3848 \since 5.9
3849
3850 \sa QWindow::setScreen(), QWindow::screen(), QScreen, {QtQuick::Application}{Application}
3851 */
3852
3853/*!
3854 \qmlproperty QWindow Window::transientParent
3855 \since 5.13
3856
3857 The window for which this window is a transient pop-up.
3858
3859 This is a hint to the window manager that this window is a dialog or pop-up
3860 on behalf of the transient parent. It usually means that the transient
3861 window will be centered over its transient parent when it is initially
3862 shown, that minimizing the parent window will also minimize the transient
3863 window, and so on; however results vary somewhat from platform to platform.
3864
3865 Declaring a Window inside an Item or another Window, either via the
3866 \l{Window::data}{default property} or a dedicated property, will automatically
3867 set up a transient parent relationship to the containing window,
3868 unless the \l transientParent property is explicitly set. This applies
3869 when creating Window items via \l [QML] {QtQml::Qt::createComponent()}
3870 {Qt.createComponent} or \l [QML] {QtQml::Qt::createQmlObject()}
3871 {Qt.createQmlObject} as well, as long as an Item or Window is passed
3872 as the \c parent argument.
3873
3874 A Window with a transient parent will not be shown until its transient
3875 parent is shown, even if the \l visible property is \c true. This also
3876 applies for the automatic transient parent relationship described above.
3877 In particular, if the Window's containing element is an Item, the window
3878 will not be shown until the containing item is added to a scene, via its
3879 \l{Concepts - Visual Parent in Qt Quick}{visual parent hierarchy}. Setting
3880 the \l transientParent to \c null will override this behavior:
3881
3882 \snippet qml/nestedWindowTransientParent.qml 0
3883 \snippet qml/nestedWindowTransientParent.qml 1
3884
3885 In order to cause the window to be centered above its transient parent by
3886 default, depending on the window manager, it may also be necessary to set
3887 the \l Window::flags property with a suitable \l Qt::WindowType (such as
3888 \c Qt::Dialog).
3889
3890 \sa {QQuickWindow::}{parent()}
3891*/
3892
3893/*!
3894 \property QQuickWindow::transientParent
3895 \brief The window for which this window is a transient pop-up.
3896 \since 5.13
3897
3898 This is a hint to the window manager that this window is a dialog or pop-up
3899 on behalf of the transient parent, which may be any kind of \l QWindow.
3900
3901 In order to cause the window to be centered above its transient parent by
3902 default, depending on the window manager, it may also be necessary to set
3903 the \l flags property with a suitable \l Qt::WindowType (such as \c Qt::Dialog).
3904
3905 \sa parent()
3906 */
3907
3908/*!
3909 \qmlproperty Item Window::activeFocusItem
3910 \since 5.1
3911
3912 The item which currently has active focus or \c null if there is
3913 no item with active focus.
3914 */
3915
3916/*!
3917 \qmlattachedproperty Item Window::activeFocusItem
3918 \since 5.4
3919
3920 This attached property holds the item which currently has active focus or
3921 \c null if there is no item with active focus. The Window attached property
3922 can be attached to any Item.
3923*/
3924
3925/*!
3926 \qmlproperty bool Window::active
3927 \since 5.1
3928
3929 The active status of the window.
3930
3931 \snippet qml/windowPalette.qml declaration-and-color
3932 \snippet qml/windowPalette.qml closing-brace
3933
3934 \sa requestActivate()
3935 */
3936
3937/*!
3938 \qmlattachedproperty bool Window::active
3939 \since 5.4
3940
3941 This attached property tells whether the window is active. The Window
3942 attached property can be attached to any Item.
3943
3944 Here is an example which changes a label to show the active state of the
3945 window in which it is shown:
3946
3947 \snippet qml/windowActiveAttached.qml entire
3948*/
3949
3950/*!
3951 \qmlmethod void QtQuick::Window::requestActivate()
3952 \since 5.1
3953
3954 Requests the window to be activated, i.e. receive keyboard focus.
3955 */
3956
3957/*!
3958 \qmlmethod void QtQuick::Window::alert(int msec)
3959 \since 5.1
3960
3961 Causes an alert to be shown for \a msec milliseconds. If \a msec is \c 0
3962 (the default), then the alert is shown indefinitely until the window
3963 becomes active again.
3964
3965 In alert state, the window indicates that it demands attention, for example
3966 by flashing or bouncing the taskbar entry.
3967*/
3968
3969/*!
3970 \qmlmethod void QtQuick::Window::close()
3971
3972 Closes the window.
3973
3974 When this method is called, or when the user tries to close the window by
3975 its title bar button, the \l closing signal will be emitted. If there is no
3976 handler, or the handler does not revoke permission to close, the window
3977 will subsequently close. If the QGuiApplication::quitOnLastWindowClosed
3978 property is \c true, and there are no other windows open, the application
3979 will quit.
3980*/
3981
3982/*!
3983 \qmlmethod void QtQuick::Window::raise()
3984
3985 Raises the window in the windowing system.
3986
3987 Requests that the window be raised to appear above other windows.
3988*/
3989
3990/*!
3991 \qmlmethod void QtQuick::Window::lower()
3992
3993 Lowers the window in the windowing system.
3994
3995 Requests that the window be lowered to appear below other windows.
3996*/
3997
3998/*!
3999 \qmlmethod void QtQuick::Window::show()
4000
4001 Shows the window.
4002
4003 This is equivalent to calling showFullScreen(), showMaximized(), or showNormal(),
4004 depending on the platform's default behavior for the window type and flags.
4005
4006 \sa showFullScreen(), showMaximized(), showNormal(), hide(), QQuickItem::flags()
4007*/
4008
4009/*!
4010 \qmlmethod void QtQuick::Window::hide()
4011
4012 Hides the window.
4013
4014 Equivalent to setting \l visible to \c false or \l visibility to \l {QWindow::}{Hidden}.
4015
4016 \sa show()
4017*/
4018
4019/*!
4020 \qmlmethod void QtQuick::Window::showMinimized()
4021
4022 Shows the window as minimized.
4023
4024 Equivalent to setting \l visibility to \l {QWindow::}{Minimized}.
4025*/
4026
4027/*!
4028 \qmlmethod void QtQuick::Window::showMaximized()
4029
4030 Shows the window as maximized.
4031
4032 Equivalent to setting \l visibility to \l {QWindow::}{Maximized}.
4033*/
4034
4035/*!
4036 \qmlmethod void QtQuick::Window::showFullScreen()
4037
4038 Shows the window as fullscreen.
4039
4040 Equivalent to setting \l visibility to \l {QWindow::}{FullScreen}.
4041*/
4042
4043/*!
4044 \qmlmethod void QtQuick::Window::showNormal()
4045
4046 Shows the window as normal, i.e. neither maximized, minimized, nor fullscreen.
4047
4048 Equivalent to setting \l visibility to \l {QWindow::}{Windowed}.
4049*/
4050
4051/*!
4052 \enum QQuickWindow::RenderStage
4053 \since 5.4
4054
4055 \value BeforeSynchronizingStage Before synchronization.
4056 \value AfterSynchronizingStage After synchronization.
4057 \value BeforeRenderingStage Before rendering.
4058 \value AfterRenderingStage After rendering.
4059 \value AfterSwapStage After the frame is swapped.
4060 \value NoStage As soon as possible. This value was added in Qt 5.6.
4061
4062 \sa {Scene Graph and Rendering}
4063 */
4064
4065/*!
4066 \since 5.4
4067
4068 Schedules \a job to run when the rendering of this window reaches
4069 the given \a stage.
4070
4071 This is a convenience to the equivalent signals in QQuickWindow for
4072 "one shot" tasks.
4073
4074 The window takes ownership over \a job and will delete it when the
4075 job is completed.
4076
4077 If rendering is shut down before \a job has a chance to run, the
4078 job will be run and then deleted as part of the scene graph cleanup.
4079 If the window is never shown and no rendering happens before the QQuickWindow
4080 is destroyed, all pending jobs will be destroyed without their run()
4081 method being called.
4082
4083 If the rendering is happening on a different thread, then the job
4084 will happen on the rendering thread.
4085
4086 If \a stage is \l NoStage, \a job will be run at the earliest opportunity
4087 whenever the render thread is not busy rendering a frame. If the window is
4088 not exposed, and is not renderable, at the time the job is either posted or
4089 handled, the job is deleted without executing the run() method. If a
4090 non-threaded renderer is in use, the run() method of the job is executed
4091 synchronously. When rendering with OpenGL, the OpenGL context is changed to
4092 the renderer's context before executing any job, including \l NoStage jobs.
4093
4094 \note This function does not trigger rendering; the jobs targeting any other
4095 stage than NoStage will be stored run until rendering is triggered elsewhere.
4096 To force the job to run earlier, call QQuickWindow::update();
4097
4098 \sa beforeRendering(), afterRendering(), beforeSynchronizing(),
4099 afterSynchronizing(), frameSwapped(), sceneGraphInvalidated()
4100 */
4101
4102void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage)
4103{
4104 Q_D(QQuickWindow);
4105
4106 d->renderJobMutex.lock();
4107 if (stage == BeforeSynchronizingStage) {
4108 d->beforeSynchronizingJobs << job;
4109 } else if (stage == AfterSynchronizingStage) {
4110 d->afterSynchronizingJobs << job;
4111 } else if (stage == BeforeRenderingStage) {
4112 d->beforeRenderingJobs << job;
4113 } else if (stage == AfterRenderingStage) {
4114 d->afterRenderingJobs << job;
4115 } else if (stage == AfterSwapStage) {
4116 d->afterSwapJobs << job;
4117 } else if (stage == NoStage) {
4118 if (d->renderControl && d->rhi && d->rhi->thread() == QThread::currentThread()) {
4119 job->run();
4120 delete job;
4121 } else if (isExposed()) {
4122 d->windowManager->postJob(this, job);
4123 } else {
4124 delete job;
4125 }
4126 }
4127 d->renderJobMutex.unlock();
4128}
4129
4130void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs)
4131{
4132 renderJobMutex.lock();
4133 QList<QRunnable *> jobList = *jobs;
4134 jobs->clear();
4135 renderJobMutex.unlock();
4136
4137 for (QRunnable *r : std::as_const(jobList)) {
4138 r->run();
4139 delete r;
4140 }
4141}
4142
4143void QQuickWindow::runJobsAfterSwap()
4144{
4145 Q_D(QQuickWindow);
4146 d->runAndClearJobs(&d->afterSwapJobs);
4147}
4148
4149/*!
4150 \fn void QQuickWindow::devicePixelRatioChanged()
4151 \since 6.11
4152 This signal is emitted when the effective device pixel ratio has
4153 been changed.
4154 \sa effectiveDevicePixelRatio()
4155 */
4156
4157/*!
4158 \qmlsignal QtQuick::Window::devicePixelRatioChanged()
4159 */
4160
4161/*!
4162 \property QQuickWindow::devicePixelRatio
4163 \since 6.11
4164
4165 Returns the ratio between physical pixels and device-independent pixels for the window. This value is dependent on the screen the window is on, and may change when the window is moved.
4166 */
4167
4168/*!
4169 Returns the device pixel ratio for this window.
4170
4171 This is different from QWindow::devicePixelRatio() in that it supports
4172 redirected rendering via QQuickRenderControl and QQuickRenderTarget. When
4173 using a QQuickRenderControl, the QQuickWindow is often not fully created,
4174 meaning it is never shown and there is no underlying native window created
4175 in the windowing system. As a result, querying properties like the device
4176 pixel ratio cannot give correct results. This function takes into account
4177 both QQuickRenderControl::renderWindowFor() and
4178 QQuickRenderTarget::devicePixelRatio(). When no redirection is in effect,
4179 the result is same as QWindow::devicePixelRatio().
4180
4181 \sa QQuickRenderControl, QQuickRenderTarget, setRenderTarget(), QWindow::devicePixelRatio()
4182 */
4183qreal QQuickWindow::effectiveDevicePixelRatio() const
4184{
4185 Q_D(const QQuickWindow);
4186 QWindow *w = QQuickRenderControl::renderWindowFor(const_cast<QQuickWindow *>(this));
4187 if (w)
4188 return w->devicePixelRatio();
4189
4190 if (!d->customRenderTarget.isNull())
4191 return d->customRenderTarget.devicePixelRatio();
4192
4193 return devicePixelRatio();
4194}
4195
4196/*!
4197 \return the current renderer interface. The value is always valid and is never null.
4198
4199 \note This function can be called at any time after constructing the
4200 QQuickWindow, even while isSceneGraphInitialized() is still false. However,
4201 some renderer interface functions, in particular
4202 QSGRendererInterface::getResource() will not be functional until the
4203 scenegraph is up and running. Backend queries, like
4204 QSGRendererInterface::graphicsApi() or QSGRendererInterface::shaderType(),
4205 will always be functional on the other hand.
4206
4207 \note The ownership of the returned pointer stays with Qt. The returned
4208 instance may or may not be shared between different QQuickWindow instances,
4209 depending on the scenegraph backend in use. Therefore applications are
4210 expected to query the interface object for each QQuickWindow instead of
4211 reusing the already queried pointer.
4212
4213 \sa QSGRenderNode, QSGRendererInterface
4214
4215 \since 5.8
4216 */
4217QSGRendererInterface *QQuickWindow::rendererInterface() const
4218{
4219 Q_D(const QQuickWindow);
4220
4221 // no context validity check - it is essential to be able to return a
4222 // renderer interface instance before scenegraphInitialized() is emitted
4223 // (depending on the backend, that can happen way too late for some of the
4224 // rif use cases, like examining the graphics api or shading language in
4225 // use)
4226
4227 return d->context->sceneGraphContext()->rendererInterface(d->context);
4228}
4229
4230/*!
4231 \return the QRhi object used by this window for rendering.
4232
4233 Available only when the window is using Qt's 3D API and shading language
4234 abstractions, meaning the result is always null when using the \c software
4235 adaptation.
4236
4237 The result is valid only when rendering has been initialized, which is
4238 indicated by the emission of the sceneGraphInitialized() signal. Before
4239 that point, the returned value is null. With a regular, on-screen
4240 QQuickWindow scenegraph initialization typically happens when the native
4241 window gets exposed (shown) the first time. When using QQuickRenderControl,
4242 initialization is done in the explicit
4243 \l{QQuickRenderControl::initialize()}{initialize()} call.
4244
4245 In practice this function is a shortcut to querying the QRhi via the
4246 QSGRendererInterface.
4247
4248 \since 6.6
4249 */
4250QRhi *QQuickWindow::rhi() const
4251{
4252 Q_D(const QQuickWindow);
4253 return d->rhi;
4254}
4255
4256/*!
4257 \return the QRhiSwapChain used by this window, if there is one.
4258
4259 \note Only on-screen windows backed by one of the standard render loops
4260 (such as, \c basic or \c threaded) will have a swapchain. Otherwise the
4261 returned value is null. For example, the result is always null when the
4262 window is used with QQuickRenderControl.
4263
4264 \since 6.6
4265 */
4266QRhiSwapChain *QQuickWindow::swapChain() const
4267{
4268 Q_D(const QQuickWindow);
4269 return d->swapchain;
4270}
4271
4272/*!
4273 Requests the specified graphics \a api.
4274
4275 When the built-in, default graphics adaptation is used, \a api specifies
4276 which graphics API (OpenGL, Vulkan, Metal, or Direct3D) the scene graph
4277 should use to render. In addition, the \c software backend is built-in as
4278 well, and can be requested by setting \a api to
4279 QSGRendererInterface::Software.
4280
4281 Unlike setSceneGraphBackend(), which can only be used to request a given
4282 backend (shipped either built-in or installed as dynamically loaded
4283 plugins), this function works with the higher level concept of graphics
4284 APIs. It covers the backends that ship with Qt Quick, and thus have
4285 corresponding values in the QSGRendererInterface::GraphicsApi enum.
4286
4287 When this function is not called at all, and the equivalent environment
4288 variable \c{QSG_RHI_BACKEND} is not set either, the scene graph will choose
4289 the graphics API to use based on the platform.
4290
4291 This function becomes important in applications that are only prepared for
4292 rendering with a given API. For example, if there is native OpenGL or
4293 Vulkan rendering done by the application, it will want to ensure Qt Quick
4294 is rendering using OpenGL or Vulkan too. Such applications are expected to
4295 call this function early in their main() function.
4296
4297 \note The call to the function must happen before constructing the first
4298 QQuickWindow in the application. The graphics API cannot be changed
4299 afterwards.
4300
4301 \note When used in combination with QQuickRenderControl, this rule is
4302 relaxed: it is possible to change the graphics API, but only when all
4303 existing QQuickRenderControl and QQuickWindow instances have been
4304 destroyed.
4305
4306 To query what graphics API the scene graph is using to render,
4307 QSGRendererInterface::graphicsApi() after the scene graph
4308 \l{QQuickWindow::isSceneGraphInitialized()}{has initialized}, which
4309 typically happens either when the window becomes visible for the first time, or
4310 when QQuickRenderControl::initialize() is called.
4311
4312 To switch back to the default behavior, where the scene graph chooses a
4313 graphics API based on the platform and other conditions, set \a api to
4314 QSGRendererInterface::Unknown.
4315
4316 \since 6.0
4317 */
4318void QQuickWindow::setGraphicsApi(QSGRendererInterface::GraphicsApi api)
4319{
4320 // Special cases: these are different scenegraph backends.
4321 switch (api) {
4322 case QSGRendererInterface::Software:
4323 setSceneGraphBackend(QStringLiteral("software"));
4324 break;
4325 case QSGRendererInterface::OpenVG:
4326 setSceneGraphBackend(QStringLiteral("openvg"));
4327 break;
4328 default:
4329 break;
4330 }
4331
4332 // Standard case: tell the QRhi-based default adaptation what graphics api
4333 // (QRhi backend) to use.
4334 if (QSGRendererInterface::isApiRhiBased(api) || api == QSGRendererInterface::Unknown)
4335 QSGRhiSupport::instance_internal()->configure(api);
4336}
4337
4338/*!
4339 \return the graphics API that would be used by the scene graph if it was
4340 initialized at this point in time.
4341
4342 The standard way to query the API used by the scene graph is to use
4343 QSGRendererInterface::graphicsApi() once the scene graph has initialized,
4344 for example when or after the sceneGraphInitialized() signal is emitted. In
4345 that case one gets the true, real result, because then it is known that
4346 everything was initialized correctly using that graphics API.
4347
4348 This is not always convenient. If the application needs to set up external
4349 frameworks, or needs to work with setGraphicsDevice() in a manner that
4350 depends on the scene graph's built in API selection logic, it is not always
4351 feasiable to defer such operations until after the QQuickWindow has been
4352 made visible or QQuickRenderControl::initialize() has been called.
4353
4354 Therefore, this static function is provided as a counterpart to
4355 setGraphicsApi(): it can be called at any time, and the result reflects
4356 what API the scene graph would choose if it was initialized at the point of
4357 the call.
4358
4359 \note This static function is intended to be called on the main (GUI)
4360 thread only. For querying the API when rendering, use QSGRendererInterface
4361 since that object lives on the render thread.
4362
4363 \note This function does not take scene graph backends into account.
4364
4365 \since 6.0
4366 */
4367QSGRendererInterface::GraphicsApi QQuickWindow::graphicsApi()
4368{
4369 // Note that this applies the settings e.g. from the env vars
4370 // (QSG_RHI_BACKEND) if it was not done at least once already. Whereas if
4371 // setGraphicsApi() was called before, or the scene graph is already
4372 // initialized, then this is just a simple query.
4373 return QSGRhiSupport::instance()->graphicsApi();
4374}
4375
4376/*!
4377 Requests a Qt Quick scenegraph \a backend. Backends can either be built-in
4378 or be installed in form of dynamically loaded plugins.
4379
4380 \overload
4381
4382 \note The call to the function must happen before constructing the first
4383 QQuickWindow in the application. It cannot be changed afterwards.
4384
4385 See \l{Switch Between Adaptations in Your Application} for more information
4386 about the list of backends. If \a backend is invalid or an error occurs, the
4387 request is ignored.
4388
4389 \note Calling this function is equivalent to setting the
4390 \c QT_QUICK_BACKEND or \c QMLSCENE_DEVICE environment variables. However, this
4391 API is safer to use in applications that spawn other processes as there is
4392 no need to worry about environment inheritance.
4393
4394 \since 5.8
4395 */
4396void QQuickWindow::setSceneGraphBackend(const QString &backend)
4397{
4398 QSGContext::setBackend(backend);
4399}
4400
4401/*!
4402 Returns the requested Qt Quick scenegraph backend.
4403
4404 \note The return value of this function may still be outdated by
4405 subsequent calls to setSceneGraphBackend() until the first QQuickWindow in the
4406 application has been constructed.
4407
4408 \note The value only reflects the request in the \c{QT_QUICK_BACKEND}
4409 environment variable after a QQuickWindow has been constructed.
4410
4411 \since 5.9
4412 */
4413QString QQuickWindow::sceneGraphBackend()
4414{
4415 return QSGContext::backend();
4416}
4417
4418/*!
4419 Sets the graphics device objects for this window. The scenegraph will use
4420 existing device, physical device, and other objects specified by \a device
4421 instead of creating new ones.
4422
4423 This function is very often used in combination with QQuickRenderControl
4424 and setRenderTarget(), in order to redirect Qt Quick rendering into a
4425 texture.
4426
4427 A default constructed QQuickGraphicsDevice does not change the default
4428 behavior in any way. Once a \a device created via one of the
4429 QQuickGraphicsDevice factory functions, such as,
4430 QQuickGraphicsDevice::fromDeviceObjects(), is passed in, and the scenegraph
4431 uses a matching graphics API (with the example of fromDeviceObjects(), that
4432 would be Vulkan), the scenegraph will use the existing device objects (such
4433 as, the \c VkPhysicalDevice, \c VkDevice, and graphics queue family index,
4434 in case of Vulkan) encapsulated by the QQuickGraphicsDevice. This allows
4435 using the same device, and so sharing resources, such as buffers and
4436 textures, between Qt Quick and native rendering engines.
4437
4438 \warning This function can only be called before initializing the
4439 scenegraph and will have no effect if called afterwards. In practice this
4440 typically means calling it right before QQuickRenderControl::initialize().
4441
4442 As an example, this time with Direct3D, the typical usage is expected to be
4443 the following:
4444
4445 \badcode
4446 // native graphics resources set up by a custom D3D rendering engine
4447 ID3D11Device *device;
4448 ID3D11DeviceContext *context;
4449 ID3D11Texture2D *texture;
4450 ...
4451 // now to redirect Qt Quick content into 'texture' we could do the following:
4452 QQuickRenderControl *renderControl = new QQuickRenderControl;
4453 QQuickWindow *window = new QQuickWindow(renderControl); // this window will never be shown on-screen
4454 ...
4455 window->setGraphicsDevice(QQuickGraphicsDevice::fromDeviceAndContext(device, context));
4456 renderControl->initialize();
4457 window->setRenderTarget(QQuickRenderTarget::fromD3D11Texture(texture, textureSize);
4458 ...
4459 \endcode
4460
4461 The key aspect of using this function is to ensure that resources or
4462 handles to resources, such as \c texture in the above example, are visible
4463 to and usable by both the external rendering engine and the scenegraph
4464 renderer. This requires using the same graphics device (or with OpenGL,
4465 OpenGL context).
4466
4467 QQuickGraphicsDevice instances are implicitly shared, copyable, and
4468 can be passed by value. They do not own the associated native objects (such
4469 as, the ID3D11Device in the example).
4470
4471 \note Using QQuickRenderControl does not always imply having to call this
4472 function. When adopting an existing device or context is not needed, this
4473 function should not be called, and the scene graph will then initialize its
4474 own devices and contexts normally, just as it would with an on-screen
4475 QQuickWindow.
4476
4477 \since 6.0
4478
4479 \sa QQuickRenderControl, setRenderTarget(), setGraphicsApi()
4480 */
4481void QQuickWindow::setGraphicsDevice(const QQuickGraphicsDevice &device)
4482{
4483 Q_D(QQuickWindow);
4484 d->customDeviceObjects = device;
4485}
4486
4487/*!
4488 \return the QQuickGraphicsDevice passed to setGraphicsDevice(), or a
4489 default constructed one otherwise
4490
4491 \since 6.0
4492
4493 \sa setGraphicsDevice()
4494 */
4495QQuickGraphicsDevice QQuickWindow::graphicsDevice() const
4496{
4497 Q_D(const QQuickWindow);
4498 return d->customDeviceObjects;
4499}
4500
4501/*!
4502 Sets the graphics configuration for this window. \a config contains various
4503 settings that may be taken into account by the scene graph when
4504 initializing the underlying graphics devices and contexts.
4505
4506 Such additional configuration, specifying for example what device
4507 extensions to enable for Vulkan, becomes relevant and essential when
4508 integrating native graphics rendering code that relies on certain
4509 extensions. The same is true when integrating with an external 3D or VR
4510 engines, such as OpenXR.
4511
4512 \note The configuration is ignored when adopting existing graphics devices
4513 via setGraphicsDevice() since the scene graph is then not in control of the
4514 actual construction of those objects.
4515
4516 QQuickGraphicsConfiguration instances are implicitly shared, copyable, and
4517 can be passed by value.
4518
4519 \warning Setting a QQuickGraphicsConfiguration on a QQuickWindow must
4520 happen early enough, before the scene graph is initialized for the first
4521 time for that window. With on-screen windows this means the call must be
4522 done before invoking show() on the QQuickWindow or QQuickView. With
4523 QQuickRenderControl the configuration must be finalized before calling
4524 \l{QQuickRenderControl::initialize()}{initialize()}.
4525
4526 \since 6.0
4527 */
4528void QQuickWindow::setGraphicsConfiguration(const QQuickGraphicsConfiguration &config)
4529{
4530 Q_D(QQuickWindow);
4531 d->graphicsConfig = config;
4532}
4533
4534/*!
4535 \return the QQuickGraphicsConfiguration passed to
4536 setGraphicsConfiguration(), or a default constructed one otherwise.
4537
4538 \since 6.0
4539
4540 \sa setGraphicsConfiguration()
4541 */
4542QQuickGraphicsConfiguration QQuickWindow::graphicsConfiguration() const
4543{
4544 Q_D(const QQuickWindow);
4545 return d->graphicsConfig;
4546}
4547
4548/*!
4549 Creates a text node. When the scenegraph is not initialized, the return value is null.
4550
4551 \since 6.7
4552 \sa QSGTextNode
4553 */
4554QSGTextNode *QQuickWindow::createTextNode() const
4555{
4556 Q_D(const QQuickWindow);
4557 return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createTextNode(d->context) : nullptr;
4558}
4559
4560/*!
4561 Creates a simple rectangle node. When the scenegraph is not initialized, the return value is null.
4562
4563 This is cross-backend alternative to constructing a QSGSimpleRectNode directly.
4564
4565 \since 5.8
4566 \sa QSGRectangleNode
4567 */
4568QSGRectangleNode *QQuickWindow::createRectangleNode() const
4569{
4570 Q_D(const QQuickWindow);
4571 return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createRectangleNode() : nullptr;
4572}
4573
4574/*!
4575 Creates a simple image node. When the scenegraph is not initialized, the return value is null.
4576
4577 This is cross-backend alternative to constructing a QSGSimpleTextureNode directly.
4578
4579 \since 5.8
4580 \sa QSGImageNode
4581 */
4582QSGImageNode *QQuickWindow::createImageNode() const
4583{
4584 Q_D(const QQuickWindow);
4585 return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createImageNode() : nullptr;
4586}
4587
4588/*!
4589 Creates a nine patch node. When the scenegraph is not initialized, the return value is null.
4590
4591 \since 5.8
4592 */
4593QSGNinePatchNode *QQuickWindow::createNinePatchNode() const
4594{
4595 Q_D(const QQuickWindow);
4596 return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createNinePatchNode() : nullptr;
4597}
4598
4599/*!
4600 \since 5.10
4601
4602 Returns the render type of text-like elements in Qt Quick.
4603 The default is QQuickWindow::QtTextRendering.
4604
4605 \sa setTextRenderType()
4606*/
4607QQuickWindow::TextRenderType QQuickWindow::textRenderType()
4608{
4609 return QQuickWindowPrivate::textRenderType;
4610}
4611
4612/*!
4613 \since 5.10
4614
4615 Sets the default render type of text-like elements in Qt Quick to \a renderType.
4616
4617 \note setting the render type will only affect elements created afterwards;
4618 the render type of existing elements will not be modified.
4619
4620 \sa textRenderType()
4621*/
4622void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
4623{
4624 QQuickWindowPrivate::textRenderType = renderType;
4625}
4626
4627
4628/*!
4629 \since 6.0
4630 \qmlproperty Palette Window::palette
4631
4632 This property holds the palette currently set for the window.
4633
4634 The default palette depends on the system environment. QGuiApplication maintains a system/theme
4635 palette which serves as a default for all application windows. You can also set the default palette
4636 for windows by passing a custom palette to QGuiApplication::setPalette(), before loading any QML.
4637
4638 Window propagates explicit palette properties to child items and controls,
4639 overriding any system defaults for that property.
4640
4641 \snippet qml/windowPalette.qml entire
4642
4643 \sa Item::palette, Popup::palette, ColorGroup, SystemPalette
4644 //! internal \sa QQuickAbstractPaletteProvider, QQuickPalette
4645*/
4646
4647#ifndef QT_NO_DEBUG_STREAM
4648QDebug operator<<(QDebug debug, const QQuickWindow *win)
4649{
4650 QDebugStateSaver saver(debug);
4651 debug.nospace();
4652 if (!win) {
4653 debug << "QQuickWindow(nullptr)";
4654 return debug;
4655 }
4656
4657 debug << win->metaObject()->className() << '(' << static_cast<const void *>(win);
4658 if (win->isActive())
4659 debug << " active";
4660 if (win->isExposed())
4661 debug << " exposed";
4662 debug << ", visibility=" << win->visibility() << ", flags=" << win->flags();
4663 if (!win->title().isEmpty())
4664 debug << ", title=" << win->title();
4665 if (!win->objectName().isEmpty())
4666 debug << ", name=" << win->objectName();
4667 if (win->parent())
4668 debug << ", parent=" << static_cast<const void *>(win->parent());
4669 if (win->transientParent())
4670 debug << ", transientParent=" << static_cast<const void *>(win->transientParent());
4671 debug << ", geometry=";
4672 QtDebugUtils::formatQRect(debug, win->geometry());
4673 debug << ')';
4674 return debug;
4675}
4676#endif
4677
4678QT_END_NAMESPACE
4679
4680#include "qquickwindow.moc"
4681#include "moc_qquickwindow_p.cpp"
4682#include "moc_qquickwindow.cpp"
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
static void updatePixelRatioHelper(QQuickItem *item, float pixelRatio)
void forcePolishHelper(QQuickItem *item)
void forceUpdate(QQuickItem *item)
QDebug operator<<(QDebug debug, const QQuickWindow *win)
static QSGNode * qquickitem_before_paintNode(QQuickItemPrivate *d)
static QSGNode * fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &returnedPaintNode)
const QList< QQuickItem * > & itemsToPolish
bool check(QQuickItem *item, int itemsRemainingBeforeUpdatePolish)
PolishLoopDetector(const QList< QQuickItem * > &itemsToPolish)
QRhiRenderPassDescriptor * rpDesc
QRhiRenderBuffer * renderBuffer