7#include <QtWidgets/private/qwidgetrepaintmanager_p.h>
9#include "private/qquickwindow_p.h"
10#include "private/qquickitem_p.h"
11#include "private/qquickitemchangelistener_p.h"
12#include "private/qquickrendercontrol_p.h"
13#include "private/qsgrhisupport_p.h"
15#include "private/qsgsoftwarerenderer_p.h"
17#include <private/qqmldebugconnector_p.h>
18#include <private/qquickprofiler_p.h>
19#include <private/qqmldebugserviceinterfaces_p.h>
21#include <QtQml/qqmlengine.h>
22#include <QtQml/qqmlcomponent.h>
23#include <private/qqmlengine_p.h>
24#include <QtCore/qbasictimer.h>
25#include <QtGui/QOffscreenSurface>
26#include <QtGui/private/qguiapplication_p.h>
27#include <QtGui/qpa/qplatformintegration.h>
29#include <QtGui/QPainter>
31#include <QtQuick/QSGRendererInterface>
34#if QT_CONFIG(messagebox)
35# include <QtWidgets/QMessageBox>
37# include <QtCore/QLibraryInfo>
38# include <QtCore/qt_windows.h>
41#include <QtQuick/qquickgraphicsdevice.h>
42#include <QtQuick/qquickrendertarget.h>
44#include "private/qwidget_p.h"
46#if QT_CONFIG(graphicsview)
47#include <QtWidgets/qgraphicsscene.h>
48#include <QtWidgets/qgraphicsview.h>
52#include <QtGui/private/qvulkandefaultinstance_p.h>
57QQuickWidgetOffscreenWindow::QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control)
58:QQuickWindow(dd, control)
60 setTitle(QString::fromLatin1(
"Offscreen"));
61 setObjectName(QString::fromLatin1(
"QQuickWidgetOffscreenWindow"));
73 visibility = visible ? QWindow::Windowed : QWindow::Hidden;
74 q->visibilityChanged(visibility);
79
80
81
82
83
84
85
86
87
90 if (widget->windowHandle())
92 if (QWidget *nativeParent = widget->nativeParentWidget())
94 return widget->window();
111 Q_DECLARE_PUBLIC(QQuickWidgetRenderControl)
120#if QT_CONFIG(graphicsview)
136#if QT_CONFIG(accessibility)
137QAccessibleInterface *QQuickWidgetOffscreenWindow::accessibleRoot()
const
139 Q_D(
const QQuickWidgetOffscreenWindow);
140 if (d->renderControl) {
141 auto *priv =
static_cast<QQuickWidgetRenderControlPrivate *>(
142 QQuickRenderControlPrivate::get(d->renderControl)
144 return QAccessible::queryAccessibleInterface(priv->m_quickWidget);
151 : QQuickRenderControl(*(
new QQuickWidgetRenderControlPrivate(
this, quickWidget)),
nullptr)
157 Q_D(QQuickWidgetRenderControl);
159 QQuickWidget *quickWidget = d->m_quickWidget;
161#if QT_CONFIG(graphicsview)
162 QWidgetPrivate *widgetd = QWidgetPrivate::get(quickWidget);
163 if (widgetd->extra) {
164 if (
auto proxy = widgetd->extra->proxyWidget) {
165 auto scene = proxy->scene();
167 const auto views = scene->views();
168 if (!views.isEmpty()) {
171 auto candidateView = views.first();
172 return compositingWidgetFor(candidateView)->windowHandle();
179 QWidget *renderWidget = compositingWidgetFor(quickWidget);
181 *offset = quickWidget->mapTo(renderWidget, QPoint());
183 return renderWidget->windowHandle();
191 offscreenWindow->setScreen(q->screen());
194 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInitialized()), q, SLOT(createFramebufferObject()));
195 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInvalidated()), q, SLOT(destroyFramebufferObject()));
196 QWidget::connect(offscreenWindow, &QQuickWindow::focusObjectChanged, q, &QQuickWidget::propagateFocusObjectChanged);
198#if QT_CONFIG(accessibility)
199 QAccessible::installFactory(&qAccessibleQuickWidgetFactory);
212 renderControl =
new QQuickWidgetRenderControl(q);
213 if (!offscreenWindow)
214 offscreenWindow =
new QQuickWidgetOffscreenWindow(*
new QQuickWidgetOffscreenWindowPrivate(), renderControl);
217 auto sgRendererInterface = offscreenWindow->rendererInterface();
218 if (sgRendererInterface && sgRendererInterface->graphicsApi() == QSGRendererInterface::Software)
229 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering))
230 setRenderToTexture();
232 qWarning(
"QQuickWidget is not supported on this platform.");
237 if (!engine.isNull() && !engine.data()->incubationController())
238 engine.data()->setIncubationController(offscreenWindow->incubationController());
240 q->setMouseTracking(
true);
241 q->setFocusPolicy(Qt::StrongFocus);
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258 q->setAttribute(Qt::WA_AcceptTouchEvents);
261#if QT_CONFIG(quick_draganddrop)
262 q->setAcceptDrops(
true);
265 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
266 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
271 Q_Q(
const QQuickWidget);
272 if (!engine.isNull())
275 engine =
new QQmlEngine(
const_cast<QQuickWidget*>(q));
276 engine.data()->setIncubationController(offscreenWindow->incubationController());
283 rhi->makeThreadLocalNativeContextCurrent();
293 rhi->removeCleanupCallback(q);
304 if (offscreenWindow->isPersistentSceneGraph()
305 && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)
306 && rhiConfig().api() == QPlatformBackingStoreRhiConfig::OpenGL)
317 QScopedPointer<QQuickWindow> oldOffScreenWindow(offscreenWindow);
318 offscreenWindow =
nullptr;
321 renderControl =
new QQuickWidgetRenderControl(q);
324 if (oldOffScreenWindow)
325 offscreenWindow->setColor(oldOffScreenWindow->color());
327 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
328 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
330 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
331 sgItem->setParentItem(offscreenWindow->contentItem());
337 , offscreenWindow(
nullptr)
345 , resizeMode(QQuickWidget::SizeViewToRootObject)
375 q->destroyFramebufferObject();
376 delete offscreenWindow;
378 offscreenRenderer.reset();
386 if (!source.isEmpty()) {
387 component =
new QQmlComponent(engine.data(), source, q);
389 q->continueExecute();
391 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
392 q, SLOT(continueExecute()));
402 component =
new QQmlComponent(engine.data(), uri, typeName, q);
404 q->continueExecute();
406 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
407 q, SLOT(continueExecute()));
412 const QRectF &oldGeometry)
415 if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) {
417 resizetimer.start(0,q);
419 QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
429 q->createFramebufferObject();
433 qWarning(
"QQuickWidget: Attempted to render scene with no rhi");
443 QQuickRenderControlPrivate::FrameStatus frameStatus = QQuickRenderControlPrivate::get(renderControl)->frameStatus;
444 if (frameStatus == QQuickRenderControlPrivate::DeviceLostInBeginFrame) {
451 if (frameStatus != QQuickRenderControlPrivate::RecordingFrame) {
452 qWarning(
"QQuickWidget: Failed to begin recording a frame");
470 if (!offscreenWindow)
472 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
473 auto softwareRenderer =
static_cast<QSGSoftwareRenderer*>(cd->renderer);
474 if (softwareRenderer && !softwareImage.isNull()) {
475 softwareRenderer->setCurrentPaintDevice(&softwareImage);
477 softwareRenderer->markDirty();
482 updateRegion += softwareRenderer->flushRegion();
492 if (!q->isVisible() || fakeHidden)
497#if QT_CONFIG(graphicsview)
498 if (q->window()->graphicsProxyWidget())
499 QWidgetPrivate::nearestGraphicsProxyWidget(q)->update();
503 if (!useSoftwareRenderer)
505 else if (!updateRegion.isEmpty())
506 q->update(updateRegion);
521 QRhiCommandBuffer *cb =
nullptr;
522 rhi->beginOffscreenFrame(&cb);
523 QRhiResourceUpdateBatch *resUpd =
rhi->nextResourceUpdateBatch();
525 resUpd->readBackTexture(QRhiReadbackDescription(
outputTexture), &readResult);
526 cb->resourceUpdate(resUpd);
527 rhi->endOffscreenFrame();
528 if (!readResult.data.isEmpty()) {
529 QImage wrapperImage(
reinterpret_cast<
const uchar *>(readResult.data.constData()),
530 readResult.pixelSize.width(), readResult.pixelSize.height(),
531 QImage::Format_RGBA8888_Premultiplied);
532 if (
rhi->isYUpInFramebuffer())
533 return wrapperImage.flipped();
535 return wrapperImage.copy();
540 return offscreenWindow->grabWindow();
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
689
690
691
694
695
696
697
698QQuickWidget::QQuickWidget(QWidget *parent)
699 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
705
706
707
708
709
710QQuickWidget::QQuickWidget(
const QUrl &source, QWidget *parent)
711 : QQuickWidget(parent)
717
718
719
720
721
722
723QQuickWidget::QQuickWidget(QAnyStringView uri, QAnyStringView typeName, QWidget *parent)
724 : QQuickWidget(parent)
726 loadFromModule(uri, typeName);
730
731
732
733
734
735
736QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
737 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
739 d_func()->init(engine);
743
744
745QQuickWidget::~QQuickWidget()
754 d->rhi->removeCleanupCallback(
this);
765
766
767
768
769
770
771
772
773
776
777
778
779
780
781
782
783
784void QQuickWidget::setSource(
const QUrl& url)
792
793
794
795
796void QQuickWidget::setContent(
const QUrl& url, QQmlComponent *component, QObject* item)
800 d->component = component;
802 if (d->component && d->component->isError()) {
803 const QList<QQmlError> errorList = d->component->errors();
804 for (
const QQmlError &error : errorList) {
805 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
808 emit statusChanged(status());
812 d->setRootObject(item);
813 emit statusChanged(status());
816
817
818
819
820
821
822
823
824
825
826void QQuickWidget::setInitialProperties(
const QVariantMap &initialProperties)
829 d->initialProperties = initialProperties;
833
834
835
836
837
838
839
840
841
842
843
844
845void QQuickWidget::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
849 d->execute(uri, typeName);
853
854
855
856
857QUrl QQuickWidget::source()
const
859 Q_D(
const QQuickWidget);
864
865
866
867QQmlEngine* QQuickWidget::engine()
const
869 Q_D(
const QQuickWidget);
871 return const_cast<QQmlEngine *>(d->engine.data());
875
876
877
878
879
880
881QQmlContext* QQuickWidget::rootContext()
const
883 Q_D(
const QQuickWidget);
885 return d->engine.data()->rootContext();
889
890
891
892
893
894
895
896
897
900
901
902
903
904
905
908
909
910
911
912
913
914
915
916
917
918
919
920
923
924
925
927QQuickWidget::Status QQuickWidget::status()
const
929 Q_D(
const QQuickWidget);
930 if (!d->engine && !d->source.isEmpty())
931 return QQuickWidget::Error;
934 return QQuickWidget::Null;
936 if (d->component->status() == QQmlComponent::Ready && !d->root)
937 return QQuickWidget::Error;
939 return QQuickWidget::Status(d->component->status());
943
944
945
946
947
948QList<QQmlError> QQuickWidget::errors()
const
950 Q_D(
const QQuickWidget);
951 QList<QQmlError> errs;
954 errs = d->component->errors();
956 if (!d->engine && !d->source.isEmpty()) {
958 error.setDescription(QLatin1String(
"QQuickWidget: invalid qml engine."));
961 if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
963 error.setDescription(QLatin1String(
"QQuickWidget: invalid root object."));
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
987void QQuickWidget::setResizeMode(ResizeMode mode)
990 if (d->resizeMode == mode)
994 if (d->resizeMode == SizeViewToRootObject) {
995 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
996 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
1000 d->resizeMode = mode;
1009 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
1010 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
1011 p->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
1023 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
1024 QSize newSize = QSize(root->width(), root->height());
1025 if (newSize.isValid()) {
1026 if (newSize != q->size()) {
1028 q->updateGeometry();
1029 }
else if (offscreenWindow->size().isEmpty()) {
1032 offscreenWindow->resize(newSize);
1033 offscreenWindow->contentItem()->setSize(newSize);
1036 }
else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
1037 const bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
1038 const bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
1040 if (needToUpdateWidth && needToUpdateHeight) {
1045 const QSizeF newSize(q->width(), q->height());
1046 offscreenWindow->resize(newSize.toSize());
1047 offscreenWindow->contentItem()->setSize(newSize);
1048 root->setSize(newSize);
1049 }
else if (needToUpdateWidth) {
1050 const int newWidth = q->width();
1051 offscreenWindow->setWidth(newWidth);
1052 offscreenWindow->contentItem()->setWidth(newWidth);
1053 root->setWidth(newWidth);
1054 }
else if (needToUpdateHeight) {
1055 const int newHeight = q->height();
1056 offscreenWindow->setHeight(newHeight);
1057 offscreenWindow->contentItem()->setHeight(newHeight);
1058 root->setHeight(newHeight);
1064
1065
1066
1067
1071 if (offscreenWindow ==
nullptr)
1074 const QPoint &pos = q->mapToGlobal(QPoint(0, 0));
1075 if (offscreenWindow->position() != pos)
1076 offscreenWindow->setPosition(pos);
1081 QSize rootObjectSize(0,0);
1082 int widthCandidate = -1;
1083 int heightCandidate = -1;
1085 widthCandidate = root->width();
1086 heightCandidate = root->height();
1088 if (widthCandidate > 0) {
1089 rootObjectSize.setWidth(widthCandidate);
1091 if (heightCandidate > 0) {
1092 rootObjectSize.setHeight(heightCandidate);
1094 return rootObjectSize;
1101 QString translatedMessage;
1102 QString untranslatedMessage;
1103 QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String(
"QRhi"), &translatedMessage, &untranslatedMessage);
1105 static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError);
1106 const bool signalConnected = q->isSignalConnected(errorSignal);
1107 if (signalConnected)
1108 emit q->sceneGraphError(QQuickWindow::ContextNotAvailable, translatedMessage);
1110#if defined(Q_OS_WIN) && QT_CONFIG(messagebox)
1111 if (!signalConnected && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1112 QMessageBox::critical(q, QCoreApplication::applicationName(), translatedMessage);
1114 if (!signalConnected)
1115 qFatal(
"%s", qPrintable(untranslatedMessage));
1121 case QSGRendererInterface::OpenGL:
1122 return QPlatformBackingStoreRhiConfig::OpenGL;
1123 case QSGRendererInterface::Vulkan:
1124 return QPlatformBackingStoreRhiConfig::Vulkan;
1125 case QSGRendererInterface::Direct3D11:
1126 return QPlatformBackingStoreRhiConfig::D3D11;
1127 case QSGRendererInterface::Direct3D12:
1128 return QPlatformBackingStoreRhiConfig::D3D12;
1129 case QSGRendererInterface::Metal:
1130 return QPlatformBackingStoreRhiConfig::Metal;
1132 return QPlatformBackingStoreRhiConfig::Null;
1143 QRhi *backingStoreRhi = QWidgetPrivate::rhi();
1144 if (backingStoreRhi &&
rhi != backingStoreRhi) {
1148 if (rhi == offscreenRenderer.rhi()) {
1159 const bool onlyNeedsSgInit = rhi && !offscreenWindow->isSceneGraphInitialized();
1161 if (!onlyNeedsSgInit) {
1165 if (QRhi *backingStoreRhi = QWidgetPrivate::rhi()) {
1166 rhi = backingStoreRhi;
1168 rhi->addCleanupCallback(q, [
this](QRhi *rhi) {
1169 if (
this->rhi == rhi) {
1172 this->rhi =
nullptr;
1183 offscreenRenderer.setConfig(rhiConfig());
1184 offscreenRenderer.setFormat(q->format());
1186 if (offscreenRenderer.create())
1187 rhi = offscreenRenderer.rhi();
1192 if (rhi && rhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()))) {
1193 qWarning(
"The top-level window is not using the expected graphics API for composition, "
1194 "'%s' is not compatible with this QQuickWidget",
1195 rhi->backendName());
1201 if (!offscreenWindow->isSceneGraphInitialized()) {
1202 offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi));
1203#if QT_CONFIG(vulkan)
1204 if (QWindow *w = q->window()->windowHandle())
1205 offscreenWindow->setVulkanInstance(w->vulkanInstance());
1206 else if (rhi == offscreenRenderer.rhi())
1207 offscreenWindow->setVulkanInstance(QVulkanDefaultInstance::instance());
1212 qWarning(
"QQuickWidget: Failed to get a QRhi from the top-level widget's window");
1216void QQuickWidget::createFramebufferObject()
1222 if (size().isEmpty())
1228 const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
1229 d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
1230 d->offscreenWindow->contentItem()->setSize(QSizeF(width(), height()));
1232 if (d->useSoftwareRenderer) {
1233 const QSize imageSize = size() * devicePixelRatio();
1234 d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
1235 d->softwareImage.setDevicePixelRatio(devicePixelRatio());
1236 d->forceFullUpdate =
true;
1241 qWarning(
"QQuickWidget: Attempted to create output texture with no QRhi");
1245 int samples = d->requestedSamples;
1246 if (d->rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer))
1247 samples = QSGRhiSupport::chooseSampleCount(samples, d->rhi);
1251 const int minTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMin);
1252 const int maxTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMax);
1254 QSize fboSize = size() * devicePixelRatio();
1255 if (fboSize.width() > maxTexSize || fboSize.height() > maxTexSize) {
1256 qWarning(
"QQuickWidget: Requested backing texture size is %dx%d, but the maximum texture size for the 3D API implementation is %dx%d",
1257 fboSize.width(), fboSize.height(),
1258 maxTexSize, maxTexSize);
1260 fboSize.setWidth(qMin(maxTexSize, qMax(minTexSize, fboSize.width())));
1261 fboSize.setHeight(qMin(maxTexSize, qMax(minTexSize, fboSize.height())));
1264 if (!d->outputTexture) {
1265 d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
1266 if (!d->outputTexture->create()) {
1267 qWarning(
"QQuickWidget: failed to create output texture of size %dx%d",
1268 fboSize.width(), fboSize.height());
1271 if (!d->depthStencil) {
1272 d->depthStencil = d->rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, fboSize, samples,
1273 QSGRhiSupport::depthStencilBufferFlags());
1274 if (!d->depthStencil->create()) {
1275 qWarning(
"QQuickWidget: failed to create depth/stencil buffer of size %dx%d and sample count %d",
1276 fboSize.width(), fboSize.height(), samples);
1279 if (samples > 1 && !d->msaaBuffer) {
1280 d->msaaBuffer = d->rhi->newRenderBuffer(QRhiRenderBuffer::Color, fboSize, samples);
1281 if (!d->msaaBuffer->create()) {
1282 qWarning(
"QQuickWidget: failed to create multisample renderbuffer of size %dx%d and sample count %d",
1283 fboSize.width(), fboSize.height(), samples);
1287 QRhiTextureRenderTargetDescription rtDesc;
1288 QRhiColorAttachment colorAtt;
1290 colorAtt.setTexture(d->outputTexture);
1292 colorAtt.setRenderBuffer(d->msaaBuffer);
1293 colorAtt.setResolveTexture(d->outputTexture);
1295 rtDesc.setColorAttachments({ colorAtt });
1296 rtDesc.setDepthStencilBuffer(d->depthStencil);
1297 d->rt = d->rhi->newTextureRenderTarget(rtDesc);
1298 d->rtRp = d->rt->newCompatibleRenderPassDescriptor();
1299 d->rt->setRenderPassDescriptor(d->rtRp);
1302 if (d->outputTexture->pixelSize() != fboSize) {
1303 d->outputTexture->setPixelSize(fboSize);
1304 if (!d->outputTexture->create()) {
1305 qWarning(
"QQuickWidget: failed to create resized output texture of size %dx%d",
1306 fboSize.width(), fboSize.height());
1308 d->depthStencil->setPixelSize(fboSize);
1309 if (!d->depthStencil->create()) {
1310 qWarning(
"QQuickWidget: failed to create resized depth/stencil buffer of size %dx%d",
1311 fboSize.width(), fboSize.height());
1313 if (d->msaaBuffer) {
1314 d->msaaBuffer->setPixelSize(fboSize);
1315 if (!d->msaaBuffer->create()) {
1316 qWarning(
"QQuickWidget: failed to create resized multisample renderbuffer of size %dx%d",
1317 fboSize.width(), fboSize.height());
1322 d->offscreenWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(d->rt));
1324 d->renderControl->setSamples(samples);
1329 Q_ASSERT(!d->offscreenWindow->handle());
1332void QQuickWidget::destroyFramebufferObject()
1336 if (d->useSoftwareRenderer) {
1337 d->softwareImage = QImage();
1345 delete d->depthStencil;
1346 d->depthStencil =
nullptr;
1347 delete d->msaaBuffer;
1348 d->msaaBuffer =
nullptr;
1349 delete d->outputTexture;
1350 d->outputTexture =
nullptr;
1353QQuickWidget::ResizeMode QQuickWidget::resizeMode()
const
1355 Q_D(
const QQuickWidget);
1356 return d->resizeMode;
1360
1361
1362void QQuickWidget::continueExecute()
1365 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)),
this, SLOT(continueExecute()));
1367 if (d->component->isError()) {
1368 const QList<QQmlError> errorList = d->component->errors();
1369 for (
const QQmlError &error : errorList) {
1370 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1373 emit statusChanged(status());
1377 std::unique_ptr<QObject> obj(d->initialProperties.empty()
1378 ? d->component->create()
1379 : d->component->createWithInitialProperties(d->initialProperties));
1381 if (d->component->isError()) {
1382 const QList<QQmlError> errorList = d->component->errors();
1383 for (
const QQmlError &error : errorList) {
1384 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1387 emit statusChanged(status());
1393 if (d->source.isEmpty())
1394 d->source = d->component->url();
1396 d->setRootObject(obj.release());
1397 emit statusChanged(status());
1401
1402
1409 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
1411 sgItem->setParentItem(offscreenWindow->contentItem());
1412 }
else if (qobject_cast<QWindow *>(obj)) {
1413 qWarning() <<
"QQuickWidget does not support using windows as a root item." << Qt::endl
1415 <<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
1417 qWarning() <<
"QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
1419 <<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
1420 <<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
1425 initialSize = rootObjectSize();
1426 bool resized = q->testAttribute(Qt::WA_Resized);
1427 if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
1428 initialSize != q->size()) {
1429 q->resize(initialSize);
1444 QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()));
1446 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(offscreenWindow);
1453 const bool debugLayerRequested = wd->graphicsConfig.isDebugLayerEnabled();
1454 config.setDebugLayer(debugLayerRequested);
1465 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
1466 flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending;
1471
1472
1473
1474void QQuickWidget::timerEvent(QTimerEvent* e)
1477 if (!e || e->timerId() == d->resizetimer.timerId()) {
1479 d->resizetimer.stop();
1480 }
else if (e->timerId() == d->updateTimer.timerId()) {
1481 d->eventPending =
false;
1482 d->updateTimer.stop();
1483 if (d->updatePending)
1484 d->renderSceneGraph();
1489
1490
1491
1492QSize QQuickWidget::sizeHint()
const
1494 Q_D(
const QQuickWidget);
1495 QSize rootObjectSize = d->rootObjectSize();
1496 if (rootObjectSize.isEmpty()) {
1499 return rootObjectSize;
1504
1505
1506
1507
1508
1509
1510QSize QQuickWidget::initialSize()
const
1512 Q_D(
const QQuickWidget);
1513 return d->initialSize;
1517
1518
1519
1520
1521
1522QQuickItem *QQuickWidget::rootObject()
const
1524 Q_D(
const QQuickWidget);
1529
1530
1531
1532
1533void QQuickWidget::resizeEvent(QResizeEvent *e)
1536 if (d->resizeMode == SizeRootObjectToView)
1539 if (e->size().isEmpty()) {
1541 d->fakeHidden =
true;
1545 bool needsSync =
false;
1546 if (d->fakeHidden) {
1548 d->fakeHidden =
false;
1553 if (d->useSoftwareRenderer) {
1555 if (d->softwareImage.size() != size() * devicePixelRatio()) {
1556 createFramebufferObject();
1562 if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized())
1564 if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) {
1566 createFramebufferObject();
1572 d->initializeWithRhi();
1576 qWarning(
"QQuickWidget::resizeEvent() no QRhi");
1581 d->render(needsSync);
1585bool QQuickWidget::focusNextPrevChild(
bool next)
1589 const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
1592 auto *currentTarget = da->focusTargetItem();
1593 Q_ASSERT(currentTarget);
1595 auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next,
false);
1598 return QWidget::focusNextPrevChild(next);
1601 const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
1602 QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
1603 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
1604 QCoreApplication::sendEvent(d->offscreenWindow, &event);
1606 QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
1607 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
1608 QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
1610 return event.isAccepted();
1614void QQuickWidget::keyPressEvent(QKeyEvent *e)
1617 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
1620 QCoreApplication::sendEvent(d->offscreenWindow, e);
1624void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
1627 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
1630 QCoreApplication::sendEvent(d->offscreenWindow, e);
1634void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
1637 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->position().x(),
1644 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1645 e->button(), e->buttons(), e->modifiers(), e->source());
1647 mappedEvent.setTimestamp(e->timestamp());
1648 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1649 e->setAccepted(mappedEvent.isAccepted());
1653void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
1656 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1657 e->button(), e->buttons());
1661 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(),
1662 e->button(), e->buttons(), e->modifiers(), e->source());
1663 pressEvent.setTimestamp(e->timestamp());
1664 QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
1665 e->setAccepted(pressEvent.isAccepted());
1666 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1667 e->button(), e->buttons(), e->modifiers(), e->source());
1668 mappedEvent.setTimestamp(e->timestamp());
1669 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1673void QQuickWidget::showEvent(QShowEvent *)
1676 bool shouldTriggerUpdate =
true;
1678 if (!d->useSoftwareRenderer) {
1679 d->initializeWithRhi();
1681 if (d->offscreenWindow->isSceneGraphInitialized()) {
1682 shouldTriggerUpdate =
false;
1691 if (!d->eventPending && d->updatePending) {
1692 d->updatePending =
false;
1698 if (shouldTriggerUpdate)
1702 d->offscreenWindow->setVisible(
true);
1703 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1704 service->setParentWindow(d->offscreenWindow, window()->windowHandle());
1708void QQuickWidget::hideEvent(QHideEvent *)
1711 if (!d->offscreenWindow->isPersistentSceneGraph())
1712 d->invalidateRenderControl();
1714 d->offscreenWindow->setVisible(
false);
1715 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1716 service->setParentWindow(d->offscreenWindow, d->offscreenWindow);
1720void QQuickWidget::mousePressEvent(QMouseEvent *e)
1723 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
1726 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1727 e->button(), e->buttons(), e->modifiers(), e->source());
1728 mappedEvent.setTimestamp(e->timestamp());
1729 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1730 e->setAccepted(mappedEvent.isAccepted());
1734void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
1737 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
1740 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1741 e->button(), e->buttons(), e->modifiers(), e->source());
1742 mappedEvent.setTimestamp(e->timestamp());
1743 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1744 e->setAccepted(mappedEvent.isAccepted());
1747#if QT_CONFIG(wheelevent)
1749void QQuickWidget::wheelEvent(QWheelEvent *e)
1752 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1753 e->angleDelta().x(), e->angleDelta().y());
1756 QCoreApplication::sendEvent(d->offscreenWindow, e);
1761
1762
1763void QQuickWidget::focusInEvent(QFocusEvent * event)
1767 using FocusTarget = QWindowPrivate::FocusTarget;
1768 const Qt::FocusReason reason = event->reason();
1774 case Qt::TabFocusReason:
1775 case Qt::BacktabFocusReason: {
1776 const bool forward = reason == Qt::FocusReason::TabFocusReason;
1777 const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
1778 QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
1784 d->offscreenWindow->focusInEvent(event);
1788
1789
1790void QQuickWidget::focusOutEvent(QFocusEvent * event)
1793 d->offscreenWindow->focusOutEvent(event);
1799 if (states & Qt::WindowMinimized)
1800 return Qt::WindowMinimized;
1801 if (states & Qt::WindowMaximized)
1802 return Qt::WindowMaximized;
1803 if (states & Qt::WindowFullScreen)
1804 return Qt::WindowFullScreen;
1807 return Qt::WindowNoState;
1812 auto item = qobject_cast<QQuickItem *>(object);
1817 for (
auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
1818 if (e->queries() & query) {
1819 auto value = e->value(query);
1820 if (value.canConvert<QRectF>())
1821 e->setValue(query, item->mapRectToScene(value.toRectF()));
1825 if (e->queries() & Qt::ImCursorPosition) {
1826 auto value = e->value(Qt::ImCursorPosition);
1827 if (value.canConvert<QPointF>())
1828 e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
1833bool QQuickWidget::event(QEvent *e)
1837 switch (e->type()) {
1840 case QEvent::TouchBegin:
1841 case QEvent::TouchEnd:
1842 case QEvent::TouchUpdate:
1843 case QEvent::TouchCancel: {
1845 bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
1846 if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
1851 QPointerEvent *pointerEvent =
static_cast<QPointerEvent *>(e);
1852 auto deliveredPoints = pointerEvent->points();
1853 for (
auto &point : deliveredPoints) {
1854 if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
1855 point.setAccepted(
true);
1861 case QEvent::FocusAboutToChange:
1862 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1864 case QEvent::InputMethod:
1865 return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1866 case QEvent::InputMethodQuery:
1868 bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1873 remapInputMethodQueryEvent(d->offscreenWindow->focusObject(),
static_cast<QInputMethodQueryEvent *>(e));
1877 case QEvent::WindowAboutToChangeInternal:
1878 d->handleWindowAboutToChange();
1881 case QEvent::WindowChangeInternal:
1882 d->handleWindowChange();
1885 case QEvent::ScreenChangeInternal:
1887 QScreen *newScreen = screen();
1888 if (d->offscreenWindow)
1889 d->offscreenWindow->setScreen(newScreen);
1892 case QEvent::DevicePixelRatioChange:
1893 if (d->useSoftwareRenderer || d->outputTexture) {
1896 createFramebufferObject();
1899 if (d->offscreenWindow) {
1900 QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
1901 QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent);
1906 d->updatePosition();
1909 case QEvent::WindowStateChange:
1910 d->offscreenWindow->setWindowState(resolveWindowState(windowState()));
1913 case QEvent::ShortcutOverride:
1914 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1916 case QEvent::Enter: {
1917 QEnterEvent *enterEvent =
static_cast<QEnterEvent *>(e);
1918 QEnterEvent mappedEvent(enterEvent->position(), enterEvent->scenePosition(),
1919 enterEvent->globalPosition());
1920 const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1921 e->setAccepted(mappedEvent.isAccepted());
1928 return QWidget::event(e);
1931#if QT_CONFIG(quick_draganddrop)
1934void QQuickWidget::dragEnterEvent(QDragEnterEvent *e)
1939 d->offscreenWindow->event(e);
1944void QQuickWidget::dragMoveEvent(QDragMoveEvent *e)
1949 d->offscreenWindow->event(e);
1953void QQuickWidget::dragLeaveEvent(QDragLeaveEvent *e)
1956 d->offscreenWindow->event(e);
1960void QQuickWidget::dropEvent(QDropEvent *e)
1963 d->offscreenWindow->event(e);
1971void QQuickWidget::triggerUpdate()
1974 d->updatePending =
true;
1975 if (!d->eventPending) {
1984 const int exhaustDelay = 5;
1985 d->updateTimer.start(exhaustDelay, Qt::PreciseTimer,
this);
1986 d->eventPending =
true;
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001void QQuickWidget::setFormat(
const QSurfaceFormat &format)
2004 QSurfaceFormat currentFormat = d->offscreenWindow->format();
2005 QSurfaceFormat newFormat = format;
2006 newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
2007 newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
2008 newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
2014 d->requestedSamples = newFormat.samples();
2015 newFormat.setSamples(0);
2017 d->offscreenWindow->setFormat(newFormat);
2021
2022
2023
2024
2025
2026
2027QSurfaceFormat QQuickWidget::format()
const
2029 Q_D(
const QQuickWidget);
2030 return d->offscreenWindow->format();
2034
2035
2036
2037
2038QImage QQuickWidget::grabFramebuffer()
const
2040 return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053void QQuickWidget::setClearColor(
const QColor &color)
2056 d->offscreenWindow->setColor(color);
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077QQuickWindow *QQuickWidget::quickWindow()
const
2079 Q_D(
const QQuickWidget);
2080 return d->offscreenWindow;
2084
2085
2086void QQuickWidget::paintEvent(QPaintEvent *event)
2089 if (d->useSoftwareRenderer) {
2090 QPainter painter(
this);
2091 d->updateRegion = d->updateRegion.united(event->region());
2092 if (d->updateRegion.isNull()) {
2094 painter.drawImage(rect(), d->softwareImage);
2096 QTransform transform;
2097 transform.scale(devicePixelRatio(), devicePixelRatio());
2099 QRegion targetRegion;
2100 d->updateRegion.swap(targetRegion);
2101 for (
auto targetRect : targetRegion) {
2102 auto sourceRect = transform.mapRect(QRectF(targetRect));
2103 painter.drawImage(targetRect, d->softwareImage, sourceRect);
2109void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject)
2112 if (QApplication::focusObject() !=
this)
2114 if (QWindow *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel))
2115 emit window->focusObjectChanged(focusObject);
2120#include "moc_qquickwidget_p.cpp"
2122#include "moc_qquickwidget.cpp"
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h