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