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

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