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

source code of qtdeclarative/src/quick/items/qquickwindow.cpp