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