aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickwindow.cpp')
-rw-r--r--src/quick/items/qquickwindow.cpp1464
1 files changed, 1011 insertions, 453 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index d71e6ec1a5..51c67a6a4c 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickwindow.h"
#include "qquickwindow_p.h"
@@ -44,15 +8,18 @@
#include "qquickitem_p.h"
#include "qquickevents_p_p.h"
#include "qquickgraphicsdevice_p.h"
+#include "qquickwindowcontainer_p.h"
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgplaintexture_p.h>
#include <QtQuick/private/qquickpointerhandler_p.h>
+#include <QtQuick/private/qquickpointerhandler_p_p.h>
#include <private/qsgrenderloop_p.h>
#include <private/qsgrhisupport_p.h>
#include <private/qquickrendercontrol_p.h>
#include <private/qquickanimatorcontroller_p.h>
#include <private/qquickprofiler_p.h>
+#include <private/qquicktextinterface_p.h>
#include <private/qguiapplication_p.h>
@@ -71,7 +38,7 @@
#include <QtQml/qqmlinfo.h>
#include <QtQml/private/qqmlmetatype_p.h>
-#include <QtQuick/private/qquickpixmapcache_p.h>
+#include <QtQuick/private/qquickpixmap_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmldebugconnector_p.h>
@@ -83,14 +50,21 @@
#ifndef QT_NO_DEBUG_STREAM
#include <private/qdebug_p.h>
#endif
+#include <QtCore/qpointer.h>
-#include <QtGui/private/qrhi_p.h>
+#include <rhi/qrhi.h>
+
+#include <utility>
+#include <mutex>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace)
Q_DECLARE_LOGGING_CATEGORY(lcMouse)
Q_DECLARE_LOGGING_CATEGORY(lcTouch)
+Q_DECLARE_LOGGING_CATEGORY(lcPtr)
Q_LOGGING_CATEGORY(lcDirty, "qt.quick.dirty")
+Q_LOGGING_CATEGORY(lcQuickWindow, "qt.quick.window")
Q_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient")
bool QQuickWindowPrivate::defaultAlphaBuffer = false;
@@ -114,8 +88,8 @@ public:
QAnimationDriver *animationDriver = m_renderLoop->animationDriver();
if (animationDriver) {
- connect(animationDriver, SIGNAL(stopped()), this, SLOT(animationStopped()));
- connect(m_renderLoop, SIGNAL(timeToIncubate()), this, SLOT(incubate()));
+ connect(animationDriver, &QAnimationDriver::stopped, this, &QQuickWindowIncubationController::animationStopped);
+ connect(m_renderLoop, &QSGRenderLoop::timeToIncubate, this, &QQuickWindowIncubationController::incubate);
}
}
@@ -163,10 +137,6 @@ private:
int m_timer;
};
-#include "qquickwindow.moc"
-#include "moc_qquickwindow_p.cpp"
-
-
#if QT_CONFIG(accessibility)
/*!
Returns an accessibility interface for this window, or 0 if such an
@@ -200,6 +170,9 @@ have a scope focused item), and the other items will have their focus cleared.
QQuickRootItem::QQuickRootItem()
{
+ // child items with ItemObservesViewport can treat the window's content item
+ // as the ultimate viewport: avoid populating SG nodes that fall outside
+ setFlag(ItemIsViewport);
}
/*! \reimp */
@@ -232,6 +205,8 @@ void QQuickWindow::showEvent(QShowEvent *)
void QQuickWindow::hideEvent(QHideEvent *)
{
Q_D(QQuickWindow);
+ if (auto da = d->deliveryAgentPrivate())
+ da->handleWindowHidden(this);
if (d->windowManager)
d->windowManager->hide(this);
}
@@ -314,7 +289,7 @@ struct PolishLoopDetector
**/
bool check(QQuickItem *item, int itemsRemainingBeforeUpdatePolish)
{
- if (itemsToPolish.count() > itemsRemainingBeforeUpdatePolish) {
+ if (itemsToPolish.size() > itemsRemainingBeforeUpdatePolish) {
// Detected potential polish loop.
++numPolishLoopsInSequence;
if (numPolishLoopsInSequence >= 1000) {
@@ -358,6 +333,22 @@ struct PolishLoopDetector
int numPolishLoopsInSequence = 0;
};
+static const QQuickItem *firstItemWithDirtyChildrenStacking(const QQuickItem *item)
+{
+ if (QQuickItemPrivate::get(item)->dirtyAttributes
+ & QQuickItemPrivate::ChildrenStackingChanged) {
+ return item;
+ }
+
+ const auto childItems = item->childItems();
+ for (const auto *childItem : childItems) {
+ if (auto *dirtyItem = firstItemWithDirtyChildrenStacking(childItem))
+ return dirtyItem;
+ }
+
+ return nullptr;
+}
+
void QQuickWindowPrivate::polishItems()
{
// An item can trigger polish on another item, or itself for that matter,
@@ -373,7 +364,7 @@ void QQuickWindowPrivate::polishItems()
QQuickItem *item = itemsToPolish.takeLast();
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
itemPrivate->polishScheduled = false;
- const int itemsRemaining = itemsToPolish.count();
+ const int itemsRemaining = itemsToPolish.size();
itemPrivate->updatePolish();
item->updatePolish();
if (polishLoopDetector.check(item, itemsRemaining) == true)
@@ -391,6 +382,11 @@ void QQuickWindowPrivate::polishItems()
deliveryAgentPrivate()->updateFocusItemTransform();
}
#endif
+
+ if (auto *dirtyItem = firstItemWithDirtyChildrenStacking(contentItem)) {
+ qCDebug(lcQuickWindow) << dirtyItem << "has dirty child stacking order";
+ updateChildWindowStackingOrder();
+ }
}
/*!
@@ -424,29 +420,19 @@ static void updatePixelRatioHelper(QQuickItem *item, float pixelRatio)
void QQuickWindow::physicalDpiChanged()
{
Q_D(QQuickWindow);
- const qreal newPixelRatio = screen()->devicePixelRatio();
- if (qFuzzyCompare(newPixelRatio, d->devicePixelRatio))
+ const qreal newPixelRatio = effectiveDevicePixelRatio();
+ if (qFuzzyCompare(newPixelRatio, d->lastReportedItemDevicePixelRatio))
return;
- d->devicePixelRatio = newPixelRatio;
+ d->lastReportedItemDevicePixelRatio = newPixelRatio;
if (d->contentItem)
updatePixelRatioHelper(d->contentItem, newPixelRatio);
+ d->forcePolish();
}
-void QQuickWindow::handleScreenChanged(QScreen *screen)
+void QQuickWindow::handleFontDatabaseChanged()
{
Q_D(QQuickWindow);
- if (screen) {
- physicalDpiChanged();
- // When physical DPI changes on the same screen, either the resolution or the device pixel
- // ratio changed. We must check what it is. Device pixel ratio does not have its own
- // ...Changed() signal.
- d->physicalDpiChangedConnection = connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)),
- this, SLOT(physicalDpiChanged()));
- } else {
- disconnect(d->physicalDpiChangedConnection);
- }
-
- d->forcePolish();
+ d->pendingFontUpdate = true;
}
void forcePolishHelper(QQuickItem *item)
@@ -460,6 +446,13 @@ void forcePolishHelper(QQuickItem *item)
forcePolishHelper(items.at(i));
}
+void QQuickWindow::handleScreenChanged(QScreen *screen)
+{
+ Q_D(QQuickWindow);
+ Q_UNUSED(screen);
+ d->forcePolish();
+}
+
/*!
Schedules polish events on all items in the scene.
*/
@@ -482,42 +475,65 @@ void forceUpdate(QQuickItem *item)
forceUpdate(items.at(i));
}
-void QQuickWindowRenderTarget::reset(QRhi *rhi, QSGRenderer *renderer)
+void QQuickWindowRenderTarget::reset(QRhi *rhi, ResetFlags flags)
{
if (rhi) {
- if (renderer)
- renderer->invalidatePipelineCacheDependency(rpDesc);
- if (owns) {
- delete renderTarget;
- delete rpDesc;
- delete texture;
- delete depthStencil;
- }
+ if (rt.owns)
+ delete rt.renderTarget;
+
+ delete res.texture;
+ delete res.renderBuffer;
+ delete res.rpDesc;
+ }
+
+ rt = {};
+ res = {};
+
+ if (!flags.testFlag(ResetFlag::KeepImplicitBuffers))
+ implicitBuffers.reset(rhi);
+
+ if (sw.owns)
+ delete sw.paintDevice;
+
+ sw = {};
+}
+
+void QQuickWindowRenderTarget::ImplicitBuffers::reset(QRhi *rhi)
+{
+ if (rhi) {
+ delete depthStencil;
+ delete depthStencilTexture;
+ delete multisampleTexture;
}
+ *this = {};
+}
+
+void QQuickWindowPrivate::invalidateFontData(QQuickItem *item)
+{
+ QQuickTextInterface *textItem = qobject_cast<QQuickTextInterface *>(item);
+ if (textItem != nullptr)
+ textItem->invalidate();
- renderTarget = nullptr;
- rpDesc = nullptr;
- texture = nullptr;
- depthStencil = nullptr;
- owns = false;
+ QList<QQuickItem *> children = item->childItems();
+ for (QQuickItem *child : children)
+ invalidateFontData(child);
}
void QQuickWindowPrivate::ensureCustomRenderTarget()
{
// resolve() can be expensive when importing an existing native texture, so
- // it is important to only do it when the QQuickRenderTarget* was really changed
- if (!redirect.renderTargetDirty || !rhi)
+ // it is important to only do it when the QQuickRenderTarget was really changed.
+ if (!redirect.renderTargetDirty)
return;
redirect.renderTargetDirty = false;
- redirect.rt.reset(rhi, renderer);
-
- // a default constructed QQuickRenderTarget means no redirection
- if (customRenderTarget.isNull())
- return;
+ redirect.rt.reset(rhi, QQuickWindowRenderTarget::ResetFlag::KeepImplicitBuffers);
- QQuickRenderTargetPrivate::get(&customRenderTarget)->resolve(rhi, &redirect.rt);
+ if (!QQuickRenderTargetPrivate::get(&customRenderTarget)->resolve(rhi, &redirect.rt)) {
+ qWarning("Failed to set up render target redirection for QQuickWindow");
+ redirect.rt.reset(rhi);
+ }
}
void QQuickWindowPrivate::setCustomCommandBuffer(QRhiCommandBuffer *cb)
@@ -532,11 +548,6 @@ void QQuickWindowPrivate::syncSceneGraph()
ensureCustomRenderTarget();
- // Calculate the dpr the same way renderSceneGraph() will.
- qreal devicePixelRatio = q->effectiveDevicePixelRatio();
- if (redirect.rt.renderTarget && !QQuickRenderControl::renderWindowFor(q))
- devicePixelRatio = 1;
-
QRhiCommandBuffer *cb = nullptr;
if (rhi) {
if (redirect.commandBuffer)
@@ -544,12 +555,18 @@ void QQuickWindowPrivate::syncSceneGraph()
else
cb = swapchain->currentFrameCommandBuffer();
}
- context->prepareSync(devicePixelRatio, cb, graphicsConfig);
+ context->prepareSync(q->effectiveDevicePixelRatio(), cb, graphicsConfig);
animationController->beforeNodeSync();
emit q->beforeSynchronizing();
runAndClearJobs(&beforeSynchronizingJobs);
+
+ if (pendingFontUpdate) {
+ QFont::cleanup();
+ invalidateFontData(contentItem);
+ }
+
if (!renderer) {
forceUpdate(contentItem);
@@ -566,16 +583,15 @@ void QQuickWindowPrivate::syncSceneGraph()
animationController->afterNodeSync();
- // Copy the current state of clearing from window into renderer.
renderer->setClearColor(clearColor);
- // Cannot skip clearing the color buffer in Qt 6 anymore.
- const QSGAbstractRenderer::ClearMode mode = QSGAbstractRenderer::ClearColorBuffer
- | QSGAbstractRenderer::ClearStencilBuffer
- | QSGAbstractRenderer::ClearDepthBuffer;
- renderer->setClearMode(mode);
renderer->setVisualizationMode(visualizationMode);
+ if (pendingFontUpdate) {
+ context->invalidateGlyphCaches();
+ pendingFontUpdate = false;
+ }
+
emit q->afterSynchronizing();
runAndClearJobs(&afterSynchronizingJobs);
}
@@ -592,19 +608,45 @@ void QQuickWindowPrivate::emitAfterRenderPassRecording(void *ud)
emit w->afterRenderPassRecording();
}
-void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfaceSize)
+int QQuickWindowPrivate::multiViewCount()
+{
+ if (rhi) {
+ ensureCustomRenderTarget();
+ if (redirect.rt.rt.renderTarget)
+ return redirect.rt.rt.multiViewCount;
+ }
+
+ // Note that on QRhi level 0 and 1 are often used interchangeably, as both mean
+ // no-multiview. Here in Qt Quick let's always use 1 as the default
+ // (no-multiview), so that higher layers (effects, materials) do not need to
+ // handle both 0 and 1, only 1.
+ return 1;
+}
+
+QRhiRenderTarget *QQuickWindowPrivate::activeCustomRhiRenderTarget()
+{
+ if (rhi) {
+ ensureCustomRenderTarget();
+ return redirect.rt.rt.renderTarget;
+ }
+ return nullptr;
+}
+
+void QQuickWindowPrivate::renderSceneGraph()
{
Q_Q(QQuickWindow);
if (!renderer)
return;
+ ensureCustomRenderTarget();
+
+ QSGRenderTarget sgRenderTarget;
if (rhi) {
- ensureCustomRenderTarget();
QRhiRenderTarget *rt;
QRhiRenderPassDescriptor *rp;
QRhiCommandBuffer *cb;
- if (redirect.rt.renderTarget) {
- rt = redirect.rt.renderTarget;
+ if (redirect.rt.rt.renderTarget) {
+ rt = redirect.rt.rt.renderTarget;
rp = rt->renderPassDescriptor();
if (!rp) {
qWarning("Custom render target is set but no renderpass descriptor has been provided.");
@@ -624,70 +666,53 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
rp = rpDescForSwapchain;
cb = swapchain->currentFrameCommandBuffer();
}
- context->beginNextRhiFrame(renderer, rt, rp, cb,
- emitBeforeRenderPassRecording,
- emitAfterRenderPassRecording,
- q);
+ sgRenderTarget = QSGRenderTarget(rt, rp, cb);
+ sgRenderTarget.multiViewCount = multiViewCount();
} else {
- context->beginNextFrame(renderer,
- emitBeforeRenderPassRecording,
- emitAfterRenderPassRecording,
- q);
+ sgRenderTarget = QSGRenderTarget(redirect.rt.sw.paintDevice);
}
+ context->beginNextFrame(renderer,
+ sgRenderTarget,
+ emitBeforeRenderPassRecording,
+ emitAfterRenderPassRecording,
+ q);
+
animationController->advance();
emit q->beforeRendering();
runAndClearJobs(&beforeRenderingJobs);
+ const qreal devicePixelRatio = q->effectiveDevicePixelRatio();
+ QSize pixelSize;
+ if (redirect.rt.rt.renderTarget)
+ pixelSize = redirect.rt.rt.renderTarget->pixelSize();
+ else if (redirect.rt.sw.paintDevice)
+ pixelSize = QSize(redirect.rt.sw.paintDevice->width(), redirect.rt.sw.paintDevice->height());
+ else if (rhi)
+ pixelSize = swapchain->currentPixelSize();
+ else // software or other backend
+ pixelSize = q->size() * devicePixelRatio;
+
+ renderer->setDevicePixelRatio(devicePixelRatio);
+ renderer->setDeviceRect(QRect(QPoint(0, 0), pixelSize));
+ renderer->setViewportRect(QRect(QPoint(0, 0), pixelSize));
+
QSGAbstractRenderer::MatrixTransformFlags matrixFlags;
- const bool flipY = rhi ? !rhi->isYUpInNDC() : false;
+ bool flipY = rhi ? !rhi->isYUpInNDC() : false;
+ if (!customRenderTarget.isNull() && customRenderTarget.mirrorVertically())
+ flipY = !flipY;
if (flipY)
matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
- const qreal devicePixelRatio = q->effectiveDevicePixelRatio();
- if (redirect.rt.renderTarget) {
- QRect rect(QPoint(0, 0), redirect.rt.renderTarget->pixelSize());
- renderer->setDeviceRect(rect);
- renderer->setViewportRect(rect);
- if (QQuickRenderControl::renderWindowFor(q)) {
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size), matrixFlags);
- renderer->setDevicePixelRatio(devicePixelRatio);
- } else {
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()), matrixFlags);
- renderer->setDevicePixelRatio(1);
- }
- } else {
- QSize pixelSize;
- QSizeF logicalSize;
- if (surfaceSize.isEmpty()) {
- pixelSize = size * devicePixelRatio;
- logicalSize = size;
- } else {
- pixelSize = surfaceSize;
- logicalSize = QSizeF(surfaceSize) / devicePixelRatio;
- }
- QRect rect(QPoint(0, 0), pixelSize);
- renderer->setDeviceRect(rect);
- renderer->setViewportRect(rect);
- renderer->setProjectionMatrixToRect(QRectF(QPoint(0, 0), logicalSize), matrixFlags);
- renderer->setDevicePixelRatio(devicePixelRatio);
- }
- if (rhi) {
- context->renderNextRhiFrame(renderer);
- } else {
- // This is the software backend (or some custom scenegraph context
- // plugin) in practice, because the default implementation always
- // hits the QRhi-based path in Qt 6.
- context->renderNextFrame(renderer);
- }
+ const QRectF rect(QPointF(0, 0), pixelSize / devicePixelRatio);
+ renderer->setProjectionMatrixToRect(rect, matrixFlags, rhi && !rhi->isYUpInNDC());
+
+ context->renderNextFrame(renderer);
emit q->afterRendering();
runAndClearJobs(&afterRenderingJobs);
- if (rhi)
- context->endNextRhiFrame(renderer);
- else
- context->endNextFrame(renderer);
+ context->endNextFrame(renderer);
if (renderer && renderer->hasVisualizationModeWithContinuousUpdate()) {
// For the overdraw visualizer. This update is not urgent so avoid a
@@ -700,7 +725,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
QQuickWindowPrivate::QQuickWindowPrivate()
: contentItem(nullptr)
, dirtyItemList(nullptr)
- , devicePixelRatio(0)
+ , lastReportedItemDevicePixelRatio(0)
, context(nullptr)
, renderer(nullptr)
, windowManager(nullptr)
@@ -708,24 +733,42 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, clearColor(Qt::white)
, persistentGraphics(true)
, persistentSceneGraph(true)
- , componentCompleted(true)
, inDestructor(false)
, incubationController(nullptr)
, hasActiveSwapchain(false)
, hasRenderableSwapchain(false)
, swapchainJustBecameRenderable(false)
+ , updatesEnabled(true)
{
}
QQuickWindowPrivate::~QQuickWindowPrivate()
{
inDestructor = true;
- redirect.rt.reset(rhi, renderer);
+ redirect.rt.reset(rhi);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
service->removeWindow(q_func());
deliveryAgent = nullptr;
}
+void QQuickWindowPrivate::setPalette(QQuickPalette* palette)
+{
+ if (windowPaletteRef == palette)
+ return;
+
+ if (windowPaletteRef)
+ disconnect(windowPaletteRef, &QQuickPalette::changed, this, &QQuickWindowPrivate::updateWindowPalette);
+ windowPaletteRef = palette;
+ updateWindowPalette();
+ if (windowPaletteRef)
+ connect(windowPaletteRef, &QQuickPalette::changed, this, &QQuickWindowPrivate::updateWindowPalette);
+}
+
+void QQuickWindowPrivate::updateWindowPalette()
+{
+ QQuickPaletteProviderPrivateBase::setPalette(windowPaletteRef);
+}
+
void QQuickWindowPrivate::updateChildrenPalettes(const QPalette &parentPalette)
{
Q_Q(QQuickWindow);
@@ -764,8 +807,14 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
Q_ASSERT(windowManager || renderControl);
- if (QScreen *screen = q->screen())
- devicePixelRatio = screen->devicePixelRatio();
+ QObject::connect(static_cast<QGuiApplication *>(QGuiApplication::instance()),
+ &QGuiApplication::fontDatabaseChanged,
+ q,
+ &QQuickWindow::handleFontDatabaseChanged);
+
+ if (q->screen()) {
+ lastReportedItemDevicePixelRatio = q->effectiveDevicePixelRatio();
+ }
QSGContext *sg;
if (renderControl) {
@@ -787,15 +836,14 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
animationController.reset(new QQuickAnimatorController(q));
- QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
- QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
- QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection);
+ QObject::connect(context, &QSGRenderContext::initialized, q, &QQuickWindow::sceneGraphInitialized, Qt::DirectConnection);
+ QObject::connect(context, &QSGRenderContext::invalidated, q, &QQuickWindow::sceneGraphInvalidated, Qt::DirectConnection);
+ QObject::connect(context, &QSGRenderContext::invalidated, q, &QQuickWindow::cleanupSceneGraph, Qt::DirectConnection);
- QObject::connect(q, SIGNAL(focusObjectChanged(QObject*)), q, SIGNAL(activeFocusItemChanged()));
- QObject::connect(q, SIGNAL(screenChanged(QScreen*)), q, SLOT(handleScreenChanged(QScreen*)));
- QObject::connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
- q, SLOT(handleApplicationStateChanged(Qt::ApplicationState)));
- QObject::connect(q, SIGNAL(frameSwapped()), q, SLOT(runJobsAfterSwap()), Qt::DirectConnection);
+ QObject::connect(q, &QQuickWindow::focusObjectChanged, q, &QQuickWindow::activeFocusItemChanged);
+ QObject::connect(q, &QQuickWindow::screenChanged, q, &QQuickWindow::handleScreenChanged);
+ QObject::connect(qApp, &QGuiApplication::applicationStateChanged, q, &QQuickWindow::handleApplicationStateChanged);
+ QObject::connect(q, &QQuickWindow::frameSwapped, q, &QQuickWindow::runJobsAfterSwap, Qt::DirectConnection);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
service->addWindow(q);
@@ -804,8 +852,11 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state)
{
Q_D(QQuickWindow);
- if (state != Qt::ApplicationActive && d->contentItem)
- d->deliveryAgentPrivate()->handleWindowDeactivate(this);
+ if (state != Qt::ApplicationActive && d->contentItem) {
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->handleWindowDeactivate(this);
+ }
}
/*!
@@ -831,19 +882,27 @@ void QQuickWindowPrivate::dirtyItem(QQuickItem *)
}
/*!
- \obsolete Use QPointerEvent::exclusiveGrabber()
+ \deprecated Use QPointerEvent::exclusiveGrabber().
Returns the item which currently has the mouse grab.
*/
QQuickItem *QQuickWindow::mouseGrabberItem() const
{
Q_D(const QQuickWindow);
- auto epd = const_cast<QQuickWindowPrivate *>(d)->deliveryAgentPrivate()->mousePointData();
- if (!epd && d->deliveryAgentPrivate()->eventsInDelivery.isEmpty()) {
+ auto da = const_cast<QQuickWindowPrivate *>(d)->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ // The normal use case is to call this function while an event is being delivered;
+ // but if the caller knows about the event, it should call QPointerEvent::exclusiveGrabber() instead.
+ if (auto epd = da->mousePointData())
+ return qmlobject_cast<QQuickItem *>(epd->exclusiveGrabber);
+
+ if (Q_LIKELY(d->deliveryAgentPrivate()->eventsInDelivery.isEmpty()))
+ // mousePointData() checked that already: it's one reason epd can be null
qCDebug(lcMouse, "mouse grabber ambiguous: no event is currently being delivered");
- return qmlobject_cast<QQuickItem *>(QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice())->
- firstPointExclusiveGrabber());
- }
- return qobject_cast<QQuickItem *>(epd->exclusiveGrabber);
+ // If no event is being delivered, we can return "the mouse" grabber,
+ // but in general there could be more than one mouse, could be only a touchscreen etc.
+ // That's why this function is obsolete.
+ return qmlobject_cast<QQuickItem *>(QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice())->
+ firstPointExclusiveGrabber());
}
void QQuickWindowPrivate::cleanup(QSGNode *n)
@@ -858,28 +917,22 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
/*!
\qmltype Window
\instantiates QQuickWindow
- \inqmlmodule QtQuick.Window
+ \inqmlmodule QtQuick
\ingroup qtquick-visual
\brief Creates a new top-level window.
The Window object creates a new top-level window for a Qt Quick scene. It automatically sets up the
- window for use with \c {QtQuick 2.x} graphical types.
-
- To use this type, you will need to import the module with the following line:
- \code
- import QtQuick.Window 2.2
- \endcode
-
- Omitting this import will allow you to have a QML environment without
- access to window system features.
+ window for use with \c {QtQuick} graphical types.
- A Window can be declared inside an Item or inside another Window; in that
+ A Window can be declared inside an Item or inside another Window, in which
case the inner Window will automatically become "transient for" the outer
- Window: that is, most platforms will show it centered upon the outer window
- by default, and there may be other platform-dependent behaviors, depending
- also on the \l flags. If the nested window is intended to be a dialog in
- your application, you should also set \l flags to Qt.Dialog, because some
- window managers will not provide the centering behavior without that flag.
+ Window, with the outer Window as its \l transientParent. Most platforms will
+ show the Window centered upon the outer window in this case, and there may be
+ other platform-dependent behaviors, depending also on the \l flags. If the nested
+ window is intended to be a dialog in your application, you should also set \l flags
+ to \c Qt.Dialog, because some window managers will not provide the centering behavior
+ without that flag.
+
You can also declare multiple windows inside a top-level \l QtObject, in which
case the windows will have no transient relationship.
@@ -888,9 +941,27 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
When the user attempts to close a window, the \l closing signal will be
emitted. You can force the window to stay open (for example to prompt the
- user to save changes) by writing an \c onClosing handler and setting
- \c {close.accepted = false}.
+ user to save changes) by writing an \c onClosing handler that sets
+ \c {close.accepted = false} unless it's safe to close the window (for example,
+ because there are no more unsaved changes).
+
+ \code
+ onClosing: (close) => {
+ if (document.changed) {
+ close.accepted = false
+ confirmExitPopup.open()
+ }
+ }
+
+ // The confirmExitPopup allows user to save or discard the document,
+ // or to cancel the closing.
+ \endcode
+
+ \note If using \l {Qt Quick Controls}, it's recommended to use
+ \l ApplicationWindow instead of Window, as it has better styling
+ support.
*/
+
/*!
\class QQuickWindow
\since 5.0
@@ -1075,7 +1146,11 @@ QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent)
}
/*!
- \internal
+ Constructs a window for displaying a QML scene, whose rendering will
+ be controlled by the \a control object.
+ Please refer to QQuickRenderControl's documentation for more information.
+
+ \since 5.4
*/
QQuickWindow::QQuickWindow(QQuickRenderControl *control)
: QWindow(*(new QQuickWindowPrivate), nullptr)
@@ -1115,18 +1190,15 @@ QQuickWindow::~QQuickWindow()
delete root;
d->deliveryAgent = nullptr; // avoid forwarding events there during destruction
- d->renderJobMutex.lock();
- qDeleteAll(d->beforeSynchronizingJobs);
- d->beforeSynchronizingJobs.clear();
- qDeleteAll(d->afterSynchronizingJobs);
- d->afterSynchronizingJobs.clear();
- qDeleteAll(d->beforeRenderingJobs);
- d->beforeRenderingJobs.clear();
- qDeleteAll(d->afterRenderingJobs);
- d->afterRenderingJobs.clear();
- qDeleteAll(d->afterSwapJobs);
- d->afterSwapJobs.clear();
- d->renderJobMutex.unlock();
+
+ {
+ const std::lock_guard locker(d->renderJobMutex);
+ qDeleteAll(std::exchange(d->beforeSynchronizingJobs, {}));
+ qDeleteAll(std::exchange(d->afterSynchronizingJobs, {}));
+ qDeleteAll(std::exchange(d->beforeRenderingJobs, {}));
+ qDeleteAll(std::exchange(d->afterRenderingJobs, {}));;
+ qDeleteAll(std::exchange(d->afterSwapJobs, {}));
+ }
// It is important that the pixmap cache is cleaned up during shutdown.
// Besides playing nice, this also solves a practical problem that
@@ -1144,18 +1216,24 @@ void qtquick_shadereffect_purge_gui_thread_shader_cache();
This function tries to release redundant resources currently held by the QML scene.
Calling this function requests the scene graph to release cached graphics
- resources, such as graphics pipeline objects or shader programs.
-
- \note The releasing of cached graphics resources is not dependent on the
- hint from setPersistentGraphics().
+ resources, such as graphics pipeline objects, shader programs, or image
+ data.
Additionally, depending on the render loop in use, this function may also
- result in the scene graph and all rendering resources to be released. If
- this happens, the sceneGraphInvalidated() signal will be emitted, allowing
- users to clean up their own graphics resources. The
- setPersistentGraphics() and setPersistentSceneGraph() functions can be
- used to prevent this from happening, if handling the cleanup is not feasible
- in the application, at the cost of higher memory usage.
+ result in the scene graph and all window-related rendering resources to be
+ released. If this happens, the sceneGraphInvalidated() signal will be
+ emitted, allowing users to clean up their own graphics resources. The
+ setPersistentGraphics() and setPersistentSceneGraph() functions can be used
+ to prevent this from happening, if handling the cleanup is not feasible in
+ the application, at the cost of higher memory usage.
+
+ \note The releasing of cached graphics resources, such as graphics
+ pipelines or shader programs is not dependent on the persistency hints. The
+ releasing of those will happen regardless of the values of the persistent
+ graphics and scenegraph hints.
+
+ \note This function is not related to the QQuickItem::releaseResources()
+ virtual function.
\sa sceneGraphInvalidated(), setPersistentGraphics(), setPersistentSceneGraph()
*/
@@ -1299,12 +1377,15 @@ QQuickItem *QQuickWindow::contentItem() const
\brief The item which currently has active focus or \c null if there is
no item with active focus.
+
+ \sa QQuickItem::forceActiveFocus(), {Keyboard Focus in Qt Quick}
*/
QQuickItem *QQuickWindow::activeFocusItem() const
{
Q_D(const QQuickWindow);
-
- return d->deliveryAgentPrivate()->activeFocusItem;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ return da->activeFocusItem;
}
/*!
@@ -1314,20 +1395,88 @@ QQuickItem *QQuickWindow::activeFocusItem() const
QObject *QQuickWindow::focusObject() const
{
Q_D(const QQuickWindow);
-
- if (!d->inDestructor && d->deliveryAgentPrivate()->activeFocusItem)
- return d->deliveryAgentPrivate()->activeFocusItem;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ if (!d->inDestructor && da->activeFocusItem)
+ return da->activeFocusItem;
return const_cast<QQuickWindow*>(this);
}
+/*!
+ \internal
+
+ Clears all exclusive and passive grabs for the points in \a pointerEvent.
+
+ We never allow any kind of grab to persist after release, unless we're waiting
+ for a synth event from QtGui (as with most tablet events), so for points that
+ are fully released, the grab is cleared.
+
+ Called when QQuickWindow::event dispatches events, or when the QQuickOverlay
+ has filtered an event so that it bypasses normal delivery.
+*/
+void QQuickWindowPrivate::clearGrabbers(QPointerEvent *pointerEvent)
+{
+ if (pointerEvent->isEndEvent()
+ && !(QQuickDeliveryAgentPrivate::isTabletEvent(pointerEvent)
+ && (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)
+ || QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
+ if (pointerEvent->isSinglePointEvent()) {
+ if (static_cast<QSinglePointEvent *>(pointerEvent)->buttons() == Qt::NoButton) {
+ auto &firstPt = pointerEvent->point(0);
+ pointerEvent->setExclusiveGrabber(firstPt, nullptr);
+ pointerEvent->clearPassiveGrabbers(firstPt);
+ }
+ } else {
+ for (auto &point : pointerEvent->points()) {
+ if (point.state() == QEventPoint::State::Released) {
+ pointerEvent->setExclusiveGrabber(point, nullptr);
+ pointerEvent->clearPassiveGrabbers(point);
+ }
+ }
+ }
+ }
+}
+
/*! \reimp */
-bool QQuickWindow::event(QEvent *e)
+bool QQuickWindow::event(QEvent *event)
{
Q_D(QQuickWindow);
// bypass QWindow::event dispatching of input events: deliveryAgent takes care of it
QQuickDeliveryAgent *da = d->deliveryAgent;
- if (e->isPointerEvent()) {
+ if (event->isPointerEvent()) {
+ /*
+ We can't bypass the virtual functions like mousePressEvent() tabletEvent() etc.,
+ for the sake of code that subclasses QQuickWindow and overrides them, even though
+ we no longer need them as entry points for Qt Quick event delivery.
+ So dispatch to them now, ahead of normal delivery, and stop them from calling
+ back into this function if they were called from here (avoid recursion).
+ It could also be that user code expects them to work as entry points, too;
+ in that case, windowEventDispatch _won't_ be set, so the event comes here and
+ we'll dispatch it further below.
+ */
+ if (d->windowEventDispatch)
+ return false;
+ {
+ const bool wasAccepted = event->isAccepted();
+ QBoolBlocker windowEventDispatchGuard(d->windowEventDispatch, true);
+ qCDebug(lcPtr) << "dispatching to window functions in case of override" << event;
+ QWindow::event(event);
+ if (event->isAccepted() && !wasAccepted)
+ return true;
+ }
+ /*
+ QQuickWindow does not override touchEvent(). If the application has a subclass
+ of QQuickWindow which allows the event to remain accepted, it means they want
+ to stop propagation here, so return early (below). But otherwise we will call
+ QWindow::touchEvent(), which will ignore(); in that case, we need to continue
+ with the usual delivery below, so we need to undo the ignore().
+ */
+ auto pe = static_cast<QPointerEvent *>(event);
+ if (QQuickDeliveryAgentPrivate::isTouchEvent(pe))
+ event->accept();
+ // end of dispatch to user-overridden virtual window functions
+
/*
When delivering update and release events to existing grabbers,
use the subscene delivery agent, if any. A possible scenario:
@@ -1341,67 +1490,105 @@ bool QQuickWindow::event(QEvent *e)
With single-point events (mouse, or only one finger) it's simplified: there can only be one subscene of interest;
for (pt : pe->points()) would only iterate once, so we might as well skip that logic.
*/
- auto pe = static_cast<QPointerEvent *>(e);
- if (pe->pointCount() > 1) {
- bool ret = false;
- Q_ASSERT(QQuickDeliveryAgentPrivate::isTouchEvent(pe));
- // Split up the multi-point event according to the relevant QQuickDeliveryAgent that should deliver to each existing grabber
- // but send ungrabbed points to d->deliveryAgent()
- QFlatMap<QQuickDeliveryAgent*, QList<QEventPoint>> deliveryAgentsNeedingPoints;
- QEventPoint::States eventStates;
- for (const auto &pt : pe->points()) {
- eventStates |= pt.state();
- auto *ptda = QQuickDeliveryAgent::grabberAgent(pe, pt);
- if (!ptda)
- ptda = da;
- if (ptda) {
- auto danpit = deliveryAgentsNeedingPoints.find(ptda);
- if (danpit == deliveryAgentsNeedingPoints.end()) {
- deliveryAgentsNeedingPoints.insert(ptda, QList<QEventPoint>() << pt);
+ if (pe->pointCount()) {
+ const bool synthMouse = QQuickDeliveryAgentPrivate::isSynthMouse(pe);
+ if (QQuickDeliveryAgentPrivate::subsceneAgentsExist) {
+ bool ret = false;
+ // Split up the multi-point event according to the relevant QQuickDeliveryAgent that should deliver to each existing grabber
+ // but send ungrabbed points to d->deliveryAgent()
+ QFlatMap<QQuickDeliveryAgent*, QList<QEventPoint>> deliveryAgentsNeedingPoints;
+ QEventPoint::States eventStates;
+
+ auto insert = [&](QQuickDeliveryAgent *ptda, const QEventPoint &pt) {
+ if (pt.state() == QEventPoint::Pressed && !synthMouse)
+ pe->clearPassiveGrabbers(pt);
+ auto &ptList = deliveryAgentsNeedingPoints[ptda];
+ auto idEquals = [](auto id) { return [id] (const auto &e) { return e.id() == id; }; };
+ if (std::none_of(ptList.cbegin(), ptList.cend(), idEquals(pt.id())))
+ ptList.append(pt);
+ };
+
+ for (const auto &pt : pe->points()) {
+ eventStates |= pt.state();
+ auto epd = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(pe->pointingDevice()))->queryPointById(pt.id());
+ Q_ASSERT(epd);
+ bool foundAgent = false;
+ if (!epd->exclusiveGrabber.isNull() && !epd->exclusiveGrabberContext.isNull()) {
+ if (auto ptda = qobject_cast<QQuickDeliveryAgent *>(epd->exclusiveGrabberContext.data())) {
+ insert(ptda, pt);
+ qCDebug(lcPtr) << pe->type() << "point" << pt.id() << pt.state()
+ << "@" << pt.scenePosition() << "will be re-delivered via known grabbing agent" << ptda << "to" << epd->exclusiveGrabber.data();
+ foundAgent = true;
+ }
+ }
+ for (auto pgda : epd->passiveGrabbersContext) {
+ if (auto ptda = qobject_cast<QQuickDeliveryAgent *>(pgda.data())) {
+ insert(ptda, pt);
+ qCDebug(lcPtr) << pe->type() << "point" << pt.id() << pt.state()
+ << "@" << pt.scenePosition() << "will be re-delivered via known passive-grabbing agent" << ptda;
+ foundAgent = true;
+ }
+ }
+ // fallback: if we didn't find remembered/known grabber agent(s), expect the root DA to handle it
+ if (!foundAgent)
+ insert(da, pt);
+ }
+ for (auto daAndPoints : deliveryAgentsNeedingPoints) {
+ if (pe->pointCount() > 1) {
+ Q_ASSERT(QQuickDeliveryAgentPrivate::isTouchEvent(pe));
+ // if all points have the same state, set the event type accordingly
+ QEvent::Type eventType = pe->type();
+ switch (eventStates) {
+ case QEventPoint::State::Pressed:
+ eventType = QEvent::TouchBegin;
+ break;
+ case QEventPoint::State::Released:
+ eventType = QEvent::TouchEnd;
+ break;
+ default:
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+ // Make a new touch event for the subscene, the same way QQuickItemPrivate::localizedTouchEvent() does it
+ QMutableTouchEvent te(eventType, pe->pointingDevice(), pe->modifiers(), daAndPoints.second);
+ te.setTimestamp(pe->timestamp());
+ te.accept();
+ qCDebug(lcTouch) << daAndPoints.first << "shall now receive" << &te;
+ ret = daAndPoints.first->event(&te) || ret;
} else {
- danpit.value().append(pt);
+ qCDebug(lcPtr) << daAndPoints.first << "shall now receive" << pe;
+ ret = daAndPoints.first->event(pe) || ret;
}
}
- }
- // Make new touch events for each subscene, the same way QQuickItemPrivate::localizedTouchEvent() does it
- for (auto daAndPoints : deliveryAgentsNeedingPoints) {
- // if all points have the same state, set the event type accordingly
- QEvent::Type eventType = pe->type();
- switch (eventStates) {
- case QEventPoint::State::Pressed:
- eventType = QEvent::TouchBegin;
- break;
- case QEventPoint::State::Released:
- eventType = QEvent::TouchEnd;
- break;
- default:
- eventType = QEvent::TouchUpdate;
- break;
+
+ if (ret)
+ return true;
+ } else if (!synthMouse) {
+ // clear passive grabbers unless it's a system synth-mouse event
+ // QTBUG-104890: Windows sends synth mouse events (which should be ignored) after touch events
+ for (const auto &pt : pe->points()) {
+ if (pt.state() == QEventPoint::Pressed)
+ pe->clearPassiveGrabbers(pt);
}
- QMutableTouchEvent te(eventType, pe->pointingDevice(), pe->modifiers(), daAndPoints.second);
- te.setTimestamp(pe->timestamp());
- te.accept();
- qCDebug(lcTouch) << "subscene touch:" << daAndPoints.first << "shall now receive" << &te;
- ret = daAndPoints.first->event(&te) || ret;
}
- if (ret)
- return true;
- } else if (pe->pointCount() && !pe->isBeginEvent()) {
- // single-point event
- if (auto *ptda = QQuickDeliveryAgent::grabberAgent(pe, pe->points().first()))
- da = ptda;
}
- // else if it has no points, it's probably a TouchCancel, and DeliveryAgent needs to handle it.
+
+ // If it has no points, it's probably a TouchCancel, and DeliveryAgent needs to handle it.
+ // If we didn't handle it in the block above, handle it now.
// TODO should we deliver to all DAs at once then, since we don't know which one should get it?
// or fix QTBUG-90851 so that the event always has points?
- if (da && da->event(e))
+ bool ret = (da && da->event(event));
+
+ d->clearGrabbers(pe);
+
+ if (ret)
return true;
- } else if (e->isInputEvent()) {
- if (da && da->event(e))
+ } else if (event->isInputEvent()) {
+ if (da && da->event(event))
return true;
}
- switch (e->type()) {
+ switch (event->type()) {
// a few more types that are not QInputEvents, but QQuickDeliveryAgent needs to handle them anyway
case QEvent::FocusAboutToChange:
case QEvent::Enter:
@@ -1416,19 +1603,20 @@ bool QQuickWindow::event(QEvent *e)
#endif
if (d->inDestructor)
return false;
- if (da && da->event(e))
+ if (da && da->event(event))
return true;
break;
case QEvent::LanguageChange:
+ case QEvent::LocaleChange:
if (d->contentItem)
- QCoreApplication::sendEvent(d->contentItem, e);
+ QCoreApplication::sendEvent(d->contentItem, event);
break;
case QEvent::UpdateRequest:
if (d->windowManager)
d->windowManager->handleUpdateRequest(this);
break;
case QEvent::PlatformSurface:
- if ((static_cast<QPlatformSurfaceEvent *>(e))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
+ if ((static_cast<QPlatformSurfaceEvent *>(event))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
// Ensure that the rendering thread is notified before
// the QPlatformWindow is destroyed.
if (d->windowManager)
@@ -1436,32 +1624,102 @@ bool QQuickWindow::event(QEvent *e)
}
break;
case QEvent::WindowDeactivate:
- d->deliveryAgentPrivate()->handleWindowDeactivate(this);
+ if (auto da = d->deliveryAgentPrivate())
+ da->handleWindowDeactivate(this);
+ Q_FALLTHROUGH();
+ case QEvent::WindowActivate:
+ if (d->contentItem)
+ QCoreApplication::sendEvent(d->contentItem, event);
+ break;
+ case QEvent::ApplicationPaletteChange:
+ d->inheritPalette(QGuiApplication::palette());
+ if (d->contentItem)
+ QCoreApplication::sendEvent(d->contentItem, event);
break;
+ case QEvent::DevicePixelRatioChange:
+ physicalDpiChanged();
+ break;
+ case QEvent::ChildWindowAdded: {
+ auto *childEvent = static_cast<QChildWindowEvent*>(event);
+ auto *childWindow = childEvent->child();
+ qCDebug(lcQuickWindow) << "Child window" << childWindow << "added to" << this;
+ if (childWindow->handle()) {
+ // The reparenting has already resulted in the native window
+ // being added to its parent, on top of all other windows. We need
+ // to do a synchronous re-stacking of the windows here, to avoid
+ // leaving the window in the wrong position while waiting for the
+ // asynchronous callback to QQuickWindow::polishItems().
+ d->updateChildWindowStackingOrder();
+ } else {
+ qCDebug(lcQuickWindow) << "No platform window yet."
+ << "Deferring child window stacking until surface creation";
+ }
+ break;
+ }
default:
break;
}
- if (e->type() == QEvent::Type(QQuickWindowPrivate::FullUpdateRequest))
+ if (event->type() == QEvent::Type(QQuickWindowPrivate::FullUpdateRequest))
update();
- else if (e->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure))
+ else if (event->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure))
d->windowManager->handleContextCreationFailure(this);
- return QWindow::event(e);
+ if (event->isPointerEvent())
+ return true;
+ else
+ return QWindow::event(event);
+}
+
+void QQuickWindowPrivate::updateChildWindowStackingOrder(QQuickItem *item)
+{
+ Q_Q(QQuickWindow);
+
+ if (!item) {
+ qCDebug(lcQuickWindow) << "Updating child window stacking order for" << q;
+ item = contentItem;
+ }
+ auto *itemPrivate = QQuickItemPrivate::get(item);
+ const auto paintOrderChildItems = itemPrivate->paintOrderChildItems();
+ for (auto *child : paintOrderChildItems) {
+ if (auto *windowContainer = qobject_cast<QQuickWindowContainer*>(child)) {
+ auto *window = windowContainer->containedWindow();
+ if (!window) {
+ qCDebug(lcQuickWindow) << windowContainer << "has no contained window yet";
+ continue;
+ }
+ if (window->parent() != q) {
+ qCDebug(lcQuickWindow) << window << "is not yet child of this window";
+ continue;
+ }
+ qCDebug(lcQuickWindow) << "Raising" << window << "owned by" << windowContainer;
+ window->raise();
+ }
+
+ updateChildWindowStackingOrder(child);
+ }
}
/*! \reimp */
void QQuickWindow::keyPressEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
- d->deliveryAgentPrivate()->deliverKeyEvent(e);
+ if (d->windowEventDispatch)
+ return;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->deliverKeyEvent(e);
}
/*! \reimp */
void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
- d->deliveryAgentPrivate()->deliverKeyEvent(e);
+ if (d->windowEventDispatch)
+ return;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->deliverKeyEvent(e);
}
#if QT_CONFIG(wheelevent)
@@ -1469,7 +1727,11 @@ void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickWindow);
- d->deliveryAgentPrivate()->deliverSinglePointEventUntilAccepted(event);
+ if (d->windowEventDispatch)
+ return;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->deliverSinglePointEventUntilAccepted(event);
}
#endif // wheelevent
@@ -1478,7 +1740,11 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
void QQuickWindow::tabletEvent(QTabletEvent *event)
{
Q_D(QQuickWindow);
- d->deliveryAgentPrivate()->deliverPointerEvent(event);
+ if (d->windowEventDispatch)
+ return;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->deliverPointerEvent(event);
}
#endif // tabletevent
@@ -1486,31 +1752,41 @@ void QQuickWindow::tabletEvent(QTabletEvent *event)
void QQuickWindow::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
- d->deliveryAgentPrivate()->handleMouseEvent(event);
+ if (d->windowEventDispatch)
+ return;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->handleMouseEvent(event);
}
/*! \reimp */
void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
- d->deliveryAgentPrivate()->handleMouseEvent(event);
+ if (d->windowEventDispatch)
+ return;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->handleMouseEvent(event);
}
/*! \reimp */
void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
- d->deliveryAgentPrivate()->handleMouseEvent(event);
+ if (d->windowEventDispatch)
+ return;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->handleMouseEvent(event);
}
/*! \reimp */
void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
- d->deliveryAgentPrivate()->handleMouseEvent(event);
-}
-
-void QQuickWindowPrivate::flushFrameSynchronousEvents()
-{
- Q_Q(QQuickWindow);
- deliveryAgentPrivate()->flushFrameSynchronousEvents(q);
+ if (d->windowEventDispatch)
+ return;
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ da->handleMouseEvent(event);
}
#if QT_CONFIG(cursor)
@@ -1520,15 +1796,22 @@ void QQuickWindowPrivate::updateCursor(const QPointF &scenePos, QQuickItem *root
if (!rootItem)
rootItem = contentItem;
auto cursorItemAndHandler = findCursorItemAndHandler(rootItem, scenePos);
- if (cursorItem != cursorItemAndHandler.first || cursorHandler != cursorItemAndHandler.second) {
+ if (cursorItem != cursorItemAndHandler.first || cursorHandler != cursorItemAndHandler.second ||
+ (cursorItemAndHandler.second && QQuickPointerHandlerPrivate::get(cursorItemAndHandler.second)->cursorDirty)) {
QWindow *renderWindow = QQuickRenderControl::renderWindowFor(q);
QWindow *window = renderWindow ? renderWindow : q;
cursorItem = cursorItemAndHandler.first;
cursorHandler = cursorItemAndHandler.second;
- if (cursorItem)
- window->setCursor(QQuickItemPrivate::get(cursorItem)->effectiveCursor(cursorHandler));
- else
+ if (cursorHandler)
+ QQuickPointerHandlerPrivate::get(cursorItemAndHandler.second)->cursorDirty = false;
+ if (cursorItem) {
+ const auto cursor = QQuickItemPrivate::get(cursorItem)->effectiveCursor(cursorHandler);
+ qCDebug(lcHoverTrace) << "setting cursor" << cursor << "from" << cursorHandler << "or" << cursorItem;
+ window->setCursor(cursor);
+ } else {
+ qCDebug(lcHoverTrace) << "unsetting cursor";
window->unsetCursor();
+ }
}
}
@@ -1543,7 +1826,7 @@ QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAnd
if (itemPrivate->subtreeCursorEnabled) {
QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
+ for (int ii = children.size() - 1; ii >= 0; --ii) {
QQuickItem *child = children.at(ii);
if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
continue;
@@ -1568,9 +1851,44 @@ QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAnd
}
#endif
+void QQuickWindowPrivate::clearFocusObject()
+{
+ if (auto da = deliveryAgentPrivate())
+ da->clearFocusObject();
+}
+
+void QQuickWindowPrivate::setFocusToTarget(FocusTarget target)
+{
+ QQuickItem *newFocusItem = nullptr;
+ if (contentItem) {
+ switch (target) {
+ case FocusTarget::First:
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, true);
+ break;
+ case FocusTarget::Last:
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, false);
+ break;
+ case FocusTarget::Next:
+ case FocusTarget::Prev: {
+ auto da = deliveryAgentPrivate();
+ Q_ASSERT(da);
+ QQuickItem *focusItem = da->focusTargetItem() ? da->focusTargetItem() : contentItem;
+ bool forward = (target == FocusTarget::Next);
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(focusItem, forward);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (newFocusItem)
+ newFocusItem->setFocus(true, Qt::ActiveWindowFocusReason);
+}
+
/*!
- \qmlproperty list<Object> Window::data
- \default
+ \qmlproperty list<QtObject> Window::data
+ \qmldefault
The data property allows you to freely mix visual children, resources
and other Windows in a Window.
@@ -1597,10 +1915,6 @@ void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObje
if (!o)
return;
QQuickWindow *that = static_cast<QQuickWindow *>(property->object);
- if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o)) {
- qCDebug(lcTransient) << window << "is transient for" << that;
- window->setTransientParent(that);
- }
QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(that->contentItem())->data();
itemProperty.append(&itemProperty, o);
}
@@ -1660,9 +1974,7 @@ void QQuickWindowPrivate::rhiCreationFailureMessage(const QString &backendName,
void QQuickWindowPrivate::cleanupNodes()
{
- for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
- delete cleanupNodeList.at(ii);
- cleanupNodeList.clear();
+ qDeleteAll(std::exchange(cleanupNodeList, {}));
}
void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
@@ -1683,7 +1995,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
p->dirty(QQuickItemPrivate::Window);
}
- // Qt 6: Make invalidateSceneGraph a virtual member of QQuickItem
+ // Qt 7: Make invalidateSceneGraph a virtual member of QQuickItem
if (p->flags & QQuickItem::ItemHasContents) {
const QMetaObject *mo = item->metaObject();
int index = mo->indexOfSlot("invalidateSceneGraph()");
@@ -1695,7 +2007,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
}
}
- for (int ii = 0; ii < p->childItems.count(); ++ii)
+ for (int ii = 0; ii < p->childItems.size(); ++ii)
cleanupNodesOnShutdown(p->childItems.at(ii));
}
@@ -1750,7 +2062,7 @@ static QSGNode *fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &return
{
QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
- for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
+ for (; ii < orderedChildren.size() && orderedChildren.at(ii)->z() < 0; ++ii) {
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
if (!childPrivate->explicitVisible &&
(!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
@@ -1765,7 +2077,7 @@ static QSGNode *fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &return
return itemPriv->paintNode;
}
- for (; ii < orderedChildren.count(); ++ii) {
+ for (; ii < orderedChildren.size(); ++ii) {
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
if (!childPrivate->explicitVisible &&
(!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount))
@@ -1793,7 +2105,7 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
if (itemPriv->x != 0. || itemPriv->y != 0.)
matrix.translate(itemPriv->x, itemPriv->y);
- for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
+ for (int ii = itemPriv->transforms.size() - 1; ii >= 0; --ii)
itemPriv->transforms.at(ii)->applyTo(&matrix);
if (itemPriv->scale() != 1. || itemPriv->rotation() != 0.) {
@@ -1809,19 +2121,14 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
itemPriv->itemNode()->setMatrix(matrix);
}
- bool clipEffectivelyChanged = (dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Window)) &&
- ((item->clip() == false) != (itemPriv->clipNode() == nullptr));
- int effectRefCount = itemPriv->extra.isAllocated()?itemPriv->extra->effectRefCount:0;
- bool effectRefEffectivelyChanged = (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Window)) &&
- ((effectRefCount == 0) != (itemPriv->rootNode() == nullptr));
-
+ const bool clipEffectivelyChanged = dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Window);
if (clipEffectivelyChanged) {
- QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *) itemPriv->opacityNode() :
- (QSGNode *) itemPriv->itemNode();
+ QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *)itemPriv->opacityNode()
+ : (QSGNode *)itemPriv->itemNode();
QSGNode *child = itemPriv->rootNode();
- if (item->clip()) {
- Q_ASSERT(itemPriv->clipNode() == nullptr);
+ if (bool initializeClipNode = item->clip() && itemPriv->clipNode() == nullptr;
+ initializeClipNode) {
QQuickDefaultClipNode *clip = new QQuickDefaultClipNode(item->clipRect());
itemPriv->extra.value().clipNode = clip;
clip->update();
@@ -1835,9 +2142,14 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
parent->appendChildNode(clip);
}
- } else {
+ } else if (bool updateClipNode = item->clip() && itemPriv->clipNode() != nullptr;
+ updateClipNode) {
+ QQuickDefaultClipNode *clip = itemPriv->clipNode();
+ clip->setClipRect(item->clipRect());
+ clip->update();
+ } else if (bool removeClipNode = !item->clip() && itemPriv->clipNode() != nullptr;
+ removeClipNode) {
QQuickDefaultClipNode *clip = itemPriv->clipNode();
- Q_ASSERT(clip);
parent->removeChildNode(clip);
if (child) {
clip->removeChildNode(child);
@@ -1851,6 +2163,10 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
}
}
+ const int effectRefCount = itemPriv->extra.isAllocated() ? itemPriv->extra->effectRefCount : 0;
+ const bool effectRefEffectivelyChanged =
+ (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Window))
+ && ((effectRefCount == 0) != (itemPriv->rootNode() == nullptr));
if (effectRefEffectivelyChanged) {
if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
itemPriv->childContainerNode()->removeAllChildNodes();
@@ -1896,25 +2212,26 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
// desired list is shorter.
QSGNode *groupNode = itemPriv->childContainerNode();
QSGNode *currentNode = groupNode->firstChild();
- int added = 0;
- int removed = 0;
- int replaced = 0;
QSGNode *desiredNode = nullptr;
while (currentNode && (desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) {
- // uh oh... reality and our utopic paradise are diverging!
- // we need to reconcile this...
if (currentNode != desiredNode) {
- // for now, we're just removing the node from the children -
- // and replacing it with the new node.
- if (desiredNode->parent())
- desiredNode->parent()->removeChildNode(desiredNode);
- groupNode->insertChildNodeAfter(desiredNode, currentNode);
- groupNode->removeChildNode(currentNode);
- replaced++;
+ // uh oh... reality and our utopic paradise are diverging!
+ // we need to reconcile this...
+ if (currentNode->nextSibling() == desiredNode) {
+ // nice and simple: a node was removed, and the next in line is correct.
+ groupNode->removeChildNode(currentNode);
+ } else {
+ // a node needs to be added..
+ // remove it from any pre-existing parent, and push it before currentNode,
+ // so it's in the correct place...
+ if (desiredNode->parent()) {
+ desiredNode->parent()->removeChildNode(desiredNode);
+ }
+ groupNode->insertChildNodeBefore(desiredNode, currentNode);
+ }
- // since we just replaced currentNode, we also need to reset
- // the pointer.
+ // continue iteration at the correct point, now desiredNode is in place...
currentNode = desiredNode;
}
@@ -1930,7 +2247,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
if (desiredNode->parent())
desiredNode->parent()->removeChildNode(desiredNode);
groupNode->appendChildNode(desiredNode);
- added++;
}
} else if (currentNode) {
// on the other hand, if we processed less than our current node
@@ -1940,7 +2256,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
QSGNode *node = currentNode->nextSibling();
groupNode->removeChildNode(currentNode);
currentNode = node;
- removed++;
}
}
}
@@ -2063,14 +2378,6 @@ void QQuickWindow::cleanupSceneGraph()
d->runAndClearJobs(&d->afterSwapJobs);
}
-void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
-{
- qCDebug(lcTransient) << this << "is transient for" << window;
- setTransientParent(window);
- disconnect(sender(), SIGNAL(windowChanged(QQuickWindow*)),
- this, SLOT(setTransientParent_helper(QQuickWindow*)));
-}
-
QOpenGLContext *QQuickWindowPrivate::openglContext()
{
#if QT_CONFIG(opengl)
@@ -2105,7 +2412,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::frameSwapped()
+ \qmlsignal QtQuick::Window::frameSwapped()
This signal is emitted when a frame has been queued for presenting. With
vertical synchronization enabled the signal is emitted at most once per
@@ -2121,7 +2428,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::sceneGraphInitialized()
+ \qmlsignal QtQuick::Window::sceneGraphInitialized()
\internal
*/
@@ -2143,7 +2450,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::sceneGraphInvalidated()
+ \qmlsignal QtQuick::Window::sceneGraphInvalidated()
\internal
*/
@@ -2163,7 +2470,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::sceneGraphError(SceneGraphError error, QString message)
+ \qmlsignal QtQuick::Window::sceneGraphError(SceneGraphError error, QString message)
This signal is emitted when an \a error occurred during scene graph initialization.
@@ -2187,7 +2494,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
/*!
\qmltype CloseEvent
\instantiates QQuickCloseEvent
- \inqmlmodule QtQuick.Window
+ \inqmlmodule QtQuick
\ingroup qtquick-visual
\brief Notification that a \l Window is about to be closed.
\since 5.1
@@ -2195,8 +2502,6 @@ bool QQuickWindow::isSceneGraphInitialized() const
Notification that a window is about to be closed by the windowing system
(e.g. the user clicked the title bar close button). The CloseEvent contains
an accepted property which can be set to false to abort closing the window.
-
- \sa QQuickWindow::closing()
*/
/*!
@@ -2207,6 +2512,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
*/
/*!
+ \internal
\fn void QQuickWindow::closing(QQuickCloseEvent *close)
\since 5.1
@@ -2221,7 +2527,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::closing(CloseEvent close)
+ \qmlsignal QtQuick::Window::closing(CloseEvent close)
\since 5.1
This signal is emitted when the user tries to close the window.
@@ -2270,9 +2576,6 @@ bool QQuickWindow::isSceneGraphInitialized() const
scenegraph is about to render the next frame. Therefore change the target
only when necessary.
- \note This function should not be used when using the \c software backend.
- Instead, use grabWindow() to render the content into a QImage.
-
\note The window does not take ownership of any native objects referenced
in \a target.
@@ -2320,6 +2623,48 @@ QQuickRenderTarget QQuickWindow::renderTarget() const
return d->customRenderTarget;
}
+#ifdef Q_OS_WEBOS
+class GrabWindowForProtectedContent : public QRunnable
+{
+public:
+ GrabWindowForProtectedContent(QQuickWindow *window, QImage *image, QWaitCondition *condition)
+ : m_window(window)
+ , m_image(image)
+ , m_condition(condition)
+ {
+ }
+
+ bool checkGrabbable()
+ {
+ if (!m_window)
+ return false;
+ if (!m_image)
+ return false;
+ if (!QQuickWindowPrivate::get(m_window))
+ return false;
+
+ return true;
+ }
+
+ void run() override
+ {
+ if (!checkGrabbable())
+ return;
+
+ *m_image = QSGRhiSupport::instance()->grabOffscreenForProtectedContent(m_window);
+ if (m_condition)
+ m_condition->wakeOne();
+ return;
+ }
+
+private:
+ QQuickWindow *m_window;
+ QImage *m_image;
+ QWaitCondition *m_condition;
+
+};
+#endif
+
/*!
Grabs the contents of the window and returns it as an image.
@@ -2344,12 +2689,12 @@ QImage QQuickWindow::grabWindow()
{
Q_D(QQuickWindow);
- if (!isVisible() && !d->renderControl) {
+ if (!d->isRenderable() && !d->renderControl) {
// backends like software can grab regardless of the window state
if (d->windowManager && (d->windowManager->flags() & QSGRenderLoop::SupportsGrabWithoutExpose))
return d->windowManager->grab(this);
- if (!isSceneGraphInitialized() && QSGRhiSupport::instance()->isRhiEnabled()) {
+ if (!isSceneGraphInitialized()) {
// We do not have rendering up and running. Forget the render loop,
// do a frame completely offscreen and synchronously into a
// texture. This can be *very* slow due to all the device/context
@@ -2360,6 +2705,24 @@ QImage QQuickWindow::grabWindow()
}
}
+#ifdef Q_OS_WEBOS
+ if (requestedFormat().testOption(QSurfaceFormat::ProtectedContent)) {
+ QImage image;
+ QMutex mutex;
+ QWaitCondition condition;
+ mutex.lock();
+ GrabWindowForProtectedContent *job = new GrabWindowForProtectedContent(this, &image, &condition);
+ if (!job) {
+ qWarning("QQuickWindow::grabWindow: Failed to create a job for capturing protected content");
+ mutex.unlock();
+ return QImage();
+ }
+ scheduleRenderJob(job, QQuickWindow::NoStage);
+ condition.wait(&mutex);
+ mutex.unlock();
+ return image;
+ }
+#endif
// The common case: we have an exposed window with an initialized
// scenegraph, meaning we can request grabbing via the render loop, or we
// are not targeting the window, in which case the request is to be
@@ -2368,6 +2731,7 @@ QImage QQuickWindow::grabWindow()
return QQuickRenderControlPrivate::get(d->renderControl)->grab();
else if (d->windowManager)
return d->windowManager->grab(this);
+
return QImage();
}
@@ -2443,9 +2807,16 @@ QQmlIncubationController *QQuickWindow::incubationController() const
text. Using such features in combination with the NativeTextRendering
render type will lend poor and sometimes pixelated results.
- \value QtTextRendering Use Qt's own rasterization algorithm.
+ Both \c QtTextRendering and \c CurveTextRendering are hardware-accelerated techniques.
+ \c QtTextRendering is the faster of the two, but uses more memory and will exhibit rendering
+ artifacts at large sizes. \c CurveTextRendering should be considered as an alternative in cases
+ where \c QtTextRendering does not give good visual results or where reducing graphics memory
+ consumption is a priority.
+ \value QtTextRendering Use Qt's own rasterization algorithm.
\value NativeTextRendering Use the operating system's native rasterizer for text.
+ \value CurveTextRendering Text is rendered using a curve rasterizer running directly on
+ the graphics hardware. (Introduced in Qt 6.7.0.)
*/
/*!
@@ -2475,7 +2846,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::beforeSynchronizing()
+ \qmlsignal QtQuick::Window::beforeSynchronizing()
\internal
*/
@@ -2502,7 +2873,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::afterSynchronizing()
+ \qmlsignal QtQuick::Window::afterSynchronizing()
\internal
\since 5.3
*/
@@ -2522,23 +2893,23 @@ QQmlIncubationController *QQuickWindow::incubationController() const
to this signal is still important if the recording of copy type of commands
is desired since those cannot be enqueued within a render pass.
- When using OpenGL, the QOpenGLContext used for rendering by the scene graph
- will be bound at this point.
-
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
- \warning When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific
- states and leaving these enabled or set to non-default values when returning
- from the connected slot can interfere with the scene graph's rendering.
+ \note When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific
+ states and leaving these enabled or set to non-default values when
+ returning from the connected slot can interfere with the scene graph's
+ rendering. The QOpenGLContext used for rendering by the scene graph will be
+ bound when the signal is emitted.
- \sa rendererInterface(), {Scene Graph - OpenGL Under QML}, {Scene Graph - Metal Under QML},
- {Scene Graph - Vulkan Under QML}, {Scene Graph - Direct3D 11 Under QML}
+ \sa rendererInterface(), {Scene Graph - RHI Under QML}, {Scene Graph -
+ OpenGL Under QML}, {Scene Graph - Metal Under QML}, {Scene Graph - Vulkan
+ Under QML}, {Scene Graph - Direct3D 11 Under QML}
*/
/*!
- \qmlsignal QtQuick.Window::Window::beforeRendering()
+ \qmlsignal QtQuick::Window::beforeRendering()
\internal
*/
@@ -2557,23 +2928,23 @@ QQmlIncubationController *QQuickWindow::incubationController() const
and afterRenderPassRecording(), that is typically used to achieve under- or
overlaying of the custom rendering.
- When using OpenGL, the QOpenGLContext used for rendering by the scene graph
- will be bound at this point.
-
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
- \warning When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific
- states and leaving these enabled or set to non-default values when returning
- from the connected slot can interfere with the scene graph's rendering.
+ \note When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific
+ states and leaving these enabled or set to non-default values when
+ returning from the connected slot can interfere with the scene graph's
+ rendering. The QOpenGLContext used for rendering by the scene graph will be
+ bound when the signal is emitted.
- \sa rendererInterface(), {Scene Graph - OpenGL Under QML}, {Scene Graph - Metal Under QML},
- {Scene Graph - Vulkan Under QML}, {Scene Graph - Direct3D 11 Under QML}
+ \sa rendererInterface(), {Scene Graph - RHI Under QML}, {Scene Graph -
+ OpenGL Under QML}, {Scene Graph - Metal Under QML}, {Scene Graph - Vulkan
+ Under QML}, {Scene Graph - Direct3D 11 Under QML}
*/
/*!
- \qmlsignal QtQuick.Window::Window::afterRendering()
+ \qmlsignal QtQuick::Window::afterRendering()
\internal
*/
@@ -2603,10 +2974,12 @@ QQmlIncubationController *QQuickWindow::incubationController() const
\sa rendererInterface()
\since 5.14
+
+ \sa {Scene Graph - RHI Under QML}
*/
/*!
- \qmlsignal QtQuick.Window::Window::beforeRenderPassRecording()
+ \qmlsignal QtQuick::Window::beforeRenderPassRecording()
\internal
\since 5.14
*/
@@ -2636,6 +3009,8 @@ QQmlIncubationController *QQuickWindow::incubationController() const
\sa rendererInterface()
\since 5.14
+
+ \sa {Scene Graph - RHI Under QML}
*/
/*!
@@ -2661,7 +3036,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::beforeFrameBegin()
+ \qmlsignal QtQuick::Window::beforeFrameBegin()
\internal
*/
@@ -2686,12 +3061,12 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::afterFrameEnd()
+ \qmlsignal QtQuick::Window::afterFrameEnd()
\internal
*/
/*!
- \qmlsignal QtQuick.Window::Window::afterRenderPassRecording()
+ \qmlsignal QtQuick::Window::afterRenderPassRecording()
\internal
\since 5.14
*/
@@ -2711,7 +3086,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::afterAnimating()
+ \qmlsignal QtQuick::Window::afterAnimating()
This signal is emitted on the GUI thread before requesting the render thread to
perform the synchronization of the scene graph.
@@ -2745,7 +3120,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
- \qmlsignal QtQuick.Window::Window::sceneGraphAboutToStop()
+ \qmlsignal QtQuick::Window::sceneGraphAboutToStop()
\internal
\since 5.3
*/
@@ -2779,9 +3154,12 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
textures will in most cases be faster to render. When this flag is not set,
the texture will have an alpha channel based on the image's format.
- When \a options contains TextureHasMipmaps, the engine will create a
- texture which can use mipmap filtering. Mipmapped textures can not be in
- an atlas.
+ When \a options contains TextureHasMipmaps, the engine will create a texture
+ which can use mipmap filtering. Mipmapped textures can not be in an atlas.
+
+ Setting TextureHasAlphaChannel in \a options serves no purpose for this
+ function since assuming an alpha channel and blending is the default. To opt
+ out, set TextureIsOpaque.
When the scene graph uses OpenGL, the returned texture will be using \c
GL_TEXTURE_2D as texture target and \c GL_RGBA as internal format. With
@@ -2792,12 +3170,12 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
initialized.
\warning The returned texture is not memory managed by the scene graph and
- must be explicitly deleted by the caller on the rendering thread.
- This is achieved by deleting the texture from a QSGNode destructor
- or by using deleteLater() in the case where the texture already has affinity
- to the rendering thread.
+ must be explicitly deleted by the caller on the rendering thread. This is
+ achieved by deleting the texture from a QSGNode destructor or by using
+ deleteLater() in the case where the texture already has affinity to the
+ rendering thread.
- This function can be called from any thread.
+ This function can be called from both the main and the render thread.
\sa sceneGraphInitialized(), QSGTexture
*/
@@ -2814,8 +3192,59 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
return d->context->createTexture(image, flags);
}
+/*!
+ Creates a new QSGTexture from the supplied \a texture.
+
+ Use \a options to customize the texture attributes. Only the
+ TextureHasAlphaChannel flag is taken into account by this function. When
+ set, the resulting QSGTexture is always treated by the scene graph renderer
+ as needing blending. For textures that are fully opaque, not setting the
+ flag can save the cost of performing alpha blending during rendering. The
+ flag has no direct correspondence to the \l{QRhiTexture::format()}{format}
+ of the QRhiTexture, i.e. not setting the flag while having a texture format
+ such as the commonly used \l QRhiTexture::RGBA8 is perfectly normal.
+
+ Mipmapping is not controlled by \a options since \a texture is already
+ created and has the presence or lack of mipmaps baked in.
+
+ The returned QSGTexture owns the QRhiTexture, meaning \a texture is
+ destroyed together with the returned QSGTexture.
+
+ If \a texture owns its underlying native graphics resources (OpenGL texture
+ object, Vulkan image, etc.), that depends on how the QRhiTexture was created
+ (\l{QRhiTexture::create()} or \l{QRhiTexture::createFrom()}), and that is
+ not controlled or changed by this function.
+
+ \note This is only functional when the scene graph has already initialized
+ and is using the default, \l{QRhi}-based \l{Scene Graph
+ Adaptations}{adaptation}. The return value is \nullptr otherwise.
+
+ \note This function can only be called on the scene graph render thread.
+
+ \since 6.6
+
+ \sa createTextureFromImage(), sceneGraphInitialized(), QSGTexture
+ */
+QSGTexture *QQuickWindow::createTextureFromRhiTexture(QRhiTexture *texture, CreateTextureOptions options) const
+{
+ Q_D(const QQuickWindow);
+ if (!d->rhi)
+ return nullptr;
+
+ QSGPlainTexture *t = new QSGPlainTexture;
+ t->setOwnsTexture(true);
+ t->setTexture(texture);
+ t->setHasAlphaChannel(options & QQuickWindow::TextureHasAlphaChannel);
+ t->setTextureSize(texture->pixelSize());
+ return t;
+}
+
+// Legacy, private alternative to createTextureFromRhiTexture() that internally
+// creates a QRhiTexture wrapping the existing native graphics resource.
+// New code should prefer using the public API.
QSGTexture *QQuickWindowPrivate::createTextureFromNativeTexture(quint64 nativeObjectHandle,
- int nativeLayout,
+ int nativeLayoutOrState,
+ uint nativeFormat,
const QSize &size,
QQuickWindow::CreateTextureOptions options,
TextureFromNativeTextureFlags flags) const
@@ -2824,7 +3253,7 @@ QSGTexture *QQuickWindowPrivate::createTextureFromNativeTexture(quint64 nativeOb
return nullptr;
QSGPlainTexture *texture = new QSGPlainTexture;
- texture->setTextureFromNativeTexture(rhi, nativeObjectHandle, nativeLayout,
+ texture->setTextureFromNativeTexture(rhi, nativeObjectHandle, nativeLayoutOrState, nativeFormat,
size, options, flags);
texture->setHasAlphaChannel(options & QQuickWindow::TextureHasAlphaChannel);
// note that the QRhiTexture does not (and cannot) own the native object
@@ -2839,6 +3268,10 @@ QSGTexture *QQuickWindowPrivate::createTextureFromNativeTexture(quint64 nativeOb
The background color for the window.
Setting this property is more efficient than using a separate Rectangle.
+
+ \note If you set the color to \c "transparent" or to a color with alpha translucency,
+ you should also set suitable \l flags such as \c {flags: Qt.FramelessWindowHint}.
+ Otherwise, window translucency may not be enabled consistently on all platforms.
*/
/*!
@@ -2909,6 +3342,51 @@ void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
*/
/*!
+ \variable QQuickWindow::GraphicsStateInfo::currentFrameSlot
+ \since 5.14
+ \brief the current frame slot index while recording a frame.
+
+ When the scenegraph renders with lower level 3D APIs such as Vulkan or
+ Metal, it is the Qt's responsibility to ensure blocking whenever starting a
+ new frame and finding the CPU is already a certain number of frames ahead
+ of the GPU (because the command buffer submitted in frame no. \c{current} -
+ \c{FramesInFlight} has not yet completed). With other graphics APIs, such
+ as OpenGL or Direct 3D 11 this level of control is not exposed to the API
+ client but rather handled by the implementation of the graphics API.
+
+ By extension, this also means that the appropriate double (or triple)
+ buffering of resources, such as buffers, is up to the graphics API client
+ to manage. Most commonly, a uniform buffer where the data changes between
+ frames cannot simply change its contents when submitting a frame, given
+ that the frame may still be active ("in flight") when starting to record
+ the next frame. To avoid stalling the pipeline, one way is to have multiple
+ buffers (and memory allocations) under the hood, thus realizing at least a
+ double buffered scheme for such resources.
+
+ Applications that integrate rendering done directly with a graphics API
+ such as Vulkan may want to perform a similar double or triple buffering of
+ their own graphics resources, in a way that is compatible with the Qt
+ rendering engine's frame submission process. That then involves knowing the
+ values for the maximum number of in-flight frames (which is typically 2 or
+ 3) and the current frame slot index, which is a number running 0, 1, ..,
+ FramesInFlight-1, and then wrapping around. The former is exposed in the
+ \l{QQuickWindow::GraphicsStateInfo::framesInFlight}{framesInFlight}
+ variable. The latter, current index, is this value.
+
+ For an example of using these values in practice, refer to the {Scene Graph
+ - Vulkan Under QML} and {Scene Graph - Vulkan Texture Import} examples.
+ */
+
+/*!
+ \variable QQuickWindow::GraphicsStateInfo::framesInFlight
+ \since 5.14
+ \brief the maximum number of frames kept in flight.
+
+ See \l{QQuickWindow::GraphicsStateInfo::currentFrameSlot}{currentFrameSlot}
+ for a detailed description.
+ */
+
+/*!
\return a reference to a GraphicsStateInfo struct describing some of the
RHI's internal state, in particular, the double or tripple buffering status
of the backend (such as, the Vulkan or Metal integrations). This is
@@ -3046,10 +3524,12 @@ void QQuickWindow::endExternalCommands()
whether it's a dialog, popup, or a regular window, and whether it should
have a title bar, etc.
- The flags which you read from this property might differ from the ones
+ The flags that you read from this property might differ from the ones
that you set if the requested flags could not be fulfilled.
- \sa Qt::WindowFlags
+ \snippet qml/splashWindow.qml entire
+
+ \sa Qt::WindowFlags, {Qt Quick Examples - Window and Screen}
*/
/*!
@@ -3080,6 +3560,11 @@ void QQuickWindow::endExternalCommands()
The (x,y) position is relative to the \l Screen if there is only one,
or to the virtual desktop (arrangement of multiple screens).
+ \note Not all windowing systems support setting or querying top level
+ window positions. On such a system, programmatically moving windows
+ may not have any effect, and artificial values may be returned for
+ the current positions, such as \c QPoint(0, 0).
+
\qml
Window { x: 100; y: 100; width: 100; height: 100 }
\endqml
@@ -3116,10 +3601,13 @@ void QQuickWindow::endExternalCommands()
Setting visible to false is the same as setting \l visibility to \l {QWindow::}{Hidden}.
+ The default value is \c false, unless overridden by setting \l visibility.
+
\sa visibility
*/
/*!
+ \keyword qml-window-visibility-prop
\qmlproperty QWindow::Visibility Window::visibility
The screen-occupation state of the window.
@@ -3133,15 +3621,18 @@ void QQuickWindow::endExternalCommands()
visibility property you will always get the actual state, never
\c AutomaticVisibility.
- When a window is not visible its visibility is Hidden, and setting
+ When a window is not visible, its visibility is \c Hidden, and setting
visibility to \l {QWindow::}{Hidden} is the same as setting \l visible to \c false.
- \sa visible
+ \snippet qml/windowVisibility.qml entire
+
+ \sa visible, {Qt Quick Examples - Window and Screen}
\since 5.1
*/
/*!
\qmlattachedproperty QWindow::Visibility Window::visibility
+ \readonly
\since 5.4
This attached property holds whether the window is currently shown
@@ -3149,7 +3640,7 @@ void QQuickWindow::endExternalCommands()
hidden. The \c Window attached property can be attached to any Item. If the
item is not shown in any window, the value will be \l {QWindow::}{Hidden}.
- \sa visible, visibility
+ \sa visible, {qml-window-visibility-prop}{visibility}
*/
/*!
@@ -3230,33 +3721,35 @@ void QQuickWindow::endExternalCommands()
shown, that minimizing the parent window will also minimize the transient
window, and so on; however results vary somewhat from platform to platform.
- Normally if you declare a Window inside an Item or inside another Window,
- this relationship is deduced automatically. In that case, if you declare
- this window's \l visible property \c true, it will not actually be shown
- until the \c transientParent window is shown.
-
- However if you set this property, then Qt Quick will no longer wait until
- the \c transientParent window is shown before showing this window. If you
- want to to be able to show a transient window independently of the "parent"
- Item or Window within which it was declared, you can remove that
- relationship by setting \c transientParent to \c null:
-
- \qml
- import QtQuick.Window 2.13
-
- Window {
- // visible is false by default
- Window {
- transientParent: null
- visible: true
- }
- }
- \endqml
+ Declaring a Window inside an Item or another Window, either via the
+ \l{Window::data}{default property} or a dedicated property, will automatically
+ set up a transient parent relationship to the containing window,
+ unless the \l transientParent property is explicitly set. This applies
+ when creating Window items via \l [QML] {QtQml::Qt::createComponent()}
+ {Qt.createComponent} or \l [QML] {QtQml::Qt::createQmlObject()}
+ {Qt.createQmlObject} as well, as long as an Item or Window is passed
+ as the \c parent argument.
+
+ A Window with a transient parent will not be shown until its transient
+ parent is shown, even if the \l visible property is \c true. This also
+ applies for the automatic transient parent relationship described above.
+ In particular, if the Window's containing element is an Item, the window
+ will not be shown until the containing item is added to a scene, via its
+ \l{Concepts - Visual Parent in Qt Quick}{visual parent hierarchy}. Setting
+ the \l transientParent to \c null will override this behavior:
+
+ \snippet qml/nestedWindowTransientParent.qml 0
+ \snippet qml/nestedWindowTransientParent.qml 1
In order to cause the window to be centered above its transient parent by
default, depending on the window manager, it may also be necessary to set
the \l Window::flags property with a suitable \l Qt::WindowType (such as
\c Qt::Dialog).
+
+ If a \l{QtQuick::Window::parent}{visual parent} is set on the Window
+ the visual parent will take precedence over the transientParent.
+
+ \sa QtQuick::Window::parent
*/
/*!
@@ -3297,6 +3790,9 @@ void QQuickWindow::endExternalCommands()
The active status of the window.
+ \snippet qml/windowPalette.qml declaration-and-color
+ \snippet qml/windowPalette.qml closing-brace
+
\sa requestActivate()
*/
@@ -3310,14 +3806,7 @@ void QQuickWindow::endExternalCommands()
Here is an example which changes a label to show the active state of the
window in which it is shown:
- \qml
- import QtQuick 2.4
- import QtQuick.Window 2.2
-
- Text {
- text: Window.active ? "active" : "inactive"
- }
- \endqml
+ \snippet qml/windowActiveAttached.qml entire
*/
/*!
@@ -3507,7 +3996,7 @@ void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs)
jobs->clear();
renderJobMutex.unlock();
- for (QRunnable *r : qAsConst(jobList)) {
+ for (QRunnable *r : std::as_const(jobList)) {
r->run();
delete r;
}
@@ -3520,21 +4009,31 @@ void QQuickWindow::runJobsAfterSwap()
}
/*!
- * Returns the device pixel ratio for this window.
- *
- * This is different from QWindow::devicePixelRatio() in that it supports
- * redirected rendering via QQuickRenderControl. When using a
- * QQuickRenderControl, the QQuickWindow is often not created, meaning it is
- * never shown and there is no underlying native window created in the
- * windowing system. As a result, querying properties like the device pixel
- * ratio cannot give correct results. Use this function instead.
- *
- * \sa QWindow::devicePixelRatio()
+ Returns the device pixel ratio for this window.
+
+ This is different from QWindow::devicePixelRatio() in that it supports
+ redirected rendering via QQuickRenderControl and QQuickRenderTarget. When
+ using a QQuickRenderControl, the QQuickWindow is often not fully created,
+ meaning it is never shown and there is no underlying native window created
+ in the windowing system. As a result, querying properties like the device
+ pixel ratio cannot give correct results. This function takes into account
+ both QQuickRenderControl::renderWindowFor() and
+ QQuickRenderTarget::devicePixelRatio(). When no redirection is in effect,
+ the result is same as QWindow::devicePixelRatio().
+
+ \sa QQuickRenderControl, QQuickRenderTarget, setRenderTarget(), QWindow::devicePixelRatio()
*/
qreal QQuickWindow::effectiveDevicePixelRatio() const
{
+ Q_D(const QQuickWindow);
QWindow *w = QQuickRenderControl::renderWindowFor(const_cast<QQuickWindow *>(this));
- return w ? w->devicePixelRatio() : devicePixelRatio();
+ if (w)
+ return w->devicePixelRatio();
+
+ if (!d->customRenderTarget.isNull())
+ return d->customRenderTarget.devicePixelRatio();
+
+ return devicePixelRatio();
}
/*!
@@ -3572,6 +4071,48 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const
}
/*!
+ \return the QRhi object used by this window for rendering.
+
+ Available only when the window is using Qt's 3D API and shading language
+ abstractions, meaning the result is always null when using the \c software
+ adaptation.
+
+ The result is valid only when rendering has been initialized, which is
+ indicated by the emission of the sceneGraphInitialized() signal. Before
+ that point, the returned value is null. With a regular, on-screen
+ QQuickWindow scenegraph initialization typically happens when the native
+ window gets exposed (shown) the first time. When using QQuickRenderControl,
+ initialization is done in the explicit
+ \l{QQuickRenderControl::initialize()}{initialize()} call.
+
+ In practice this function is a shortcut to querying the QRhi via the
+ QSGRendererInterface.
+
+ \since 6.6
+ */
+QRhi *QQuickWindow::rhi() const
+{
+ Q_D(const QQuickWindow);
+ return d->rhi;
+}
+
+/*!
+ \return the QRhiSwapChain used by this window, if there is one.
+
+ \note Only on-screen windows backed by one of the standard render loops
+ (such as, \c basic or \c threaded) will have a swapchain. Otherwise the
+ returned value is null. For example, the result is always null when the
+ window is used with QQuickRenderControl.
+
+ \since 6.6
+ */
+QRhiSwapChain *QQuickWindow::swapChain() const
+{
+ Q_D(const QQuickWindow);
+ return d->swapchain;
+}
+
+/*!
Requests the specified graphics \a api.
When the built-in, default graphics adaptation is used, \a api specifies
@@ -3615,7 +4156,7 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const
graphics API based on the platform and other conditions, set \a api to
QSGRendererInterface::Unknown.
- \since 5.8
+ \since 6.0
*/
void QQuickWindow::setGraphicsApi(QSGRendererInterface::GraphicsApi api)
{
@@ -3634,7 +4175,7 @@ void QQuickWindow::setGraphicsApi(QSGRendererInterface::GraphicsApi api)
// Standard case: tell the QRhi-based default adaptation what graphics api
// (QRhi backend) to use.
if (QSGRendererInterface::isApiRhiBased(api) || api == QSGRendererInterface::Unknown)
- QSGRhiSupport::configure(api);
+ QSGRhiSupport::instance_internal()->configure(api);
}
/*!
@@ -3684,7 +4225,9 @@ QSGRendererInterface::GraphicsApi QQuickWindow::graphicsApi()
\note The call to the function must happen before constructing the first
QQuickWindow in the application. It cannot be changed afterwards.
- If \a backend is invalid or an error occurs, the request is ignored.
+ See \l{Switch Between Adaptations in Your Application} for more information
+ about the list of backends. If \a backend is invalid or an error occurs, the
+ request is ignored.
\note Calling this function is equivalent to setting the
\c QT_QUICK_BACKEND or \c QMLSCENE_DEVICE environment variables. However, this
@@ -3846,6 +4389,18 @@ QQuickGraphicsConfiguration QQuickWindow::graphicsConfiguration() const
}
/*!
+ Creates a text node. When the scenegraph is not initialized, the return value is null.
+
+ \since 6.7
+ \sa QSGTextNode
+ */
+QSGTextNode *QQuickWindow::createTextNode() const
+{
+ Q_D(const QQuickWindow);
+ return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createTextNode(d->context) : nullptr;
+}
+
+/*!
Creates a simple rectangle node. When the scenegraph is not initialized, the return value is null.
This is cross-backend alternative to constructing a QSGSimpleRectNode directly.
@@ -3915,7 +4470,7 @@ void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
/*!
\since 6.0
- \qmlproperty QQuickPalette Window::palette
+ \qmlproperty Palette Window::palette
This property holds the palette currently set for the window.
@@ -3923,11 +4478,12 @@ void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
palette which serves as a default for all application windows. You can also set the default palette
for windows by passing a custom palette to QGuiApplication::setPalette(), before loading any QML.
- ApplicationWindow propagates explicit palette properties to child controls. If you change a specific
- property on the window's palette, that property propagates to all child controls in the window,
+ Window propagates explicit palette properties to child items and controls,
overriding any system defaults for that property.
- \sa Item::palette, Popup::palette, QQuickColorGroup
+ \snippet qml/windowPalette.qml entire
+
+ \sa Item::palette, Popup::palette, ColorGroup, SystemPalette
//! internal \sa QQuickAbstractPaletteProvider, QQuickPalette
*/
@@ -3937,7 +4493,7 @@ QDebug operator<<(QDebug debug, const QQuickWindow *win)
QDebugStateSaver saver(debug);
debug.nospace();
if (!win) {
- debug << "QQuickWindow(0)";
+ debug << "QQuickWindow(nullptr)";
return debug;
}
@@ -3962,6 +4518,8 @@ QDebug operator<<(QDebug debug, const QQuickWindow *win)
}
#endif
-#include "moc_qquickwindow.cpp"
-
QT_END_NAMESPACE
+
+#include "qquickwindow.moc"
+#include "moc_qquickwindow_p.cpp"
+#include "moc_qquickwindow.cpp"