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);
92 Q_DECLARE_PUBLIC(QQuickWidgetRenderControl)
100#if QT_CONFIG(graphicsview)
117#if QT_CONFIG(accessibility)
118QAccessibleInterface *QQuickWidgetOffscreenWindow::accessibleRoot()
const
120 Q_D(
const QQuickWidgetOffscreenWindow);
121 if (d->renderControl) {
122 auto *priv =
static_cast<QQuickWidgetRenderControlPrivate *>(
123 QQuickRenderControlPrivate::get(d->renderControl)
125 return QAccessible::queryAccessibleInterface(priv->m_quickWidget);
132 : QQuickRenderControl(*(
new QQuickWidgetRenderControlPrivate(
this, quickWidget)),
nullptr)
138 Q_D(QQuickWidgetRenderControl);
140 *offset = d->m_quickWidget->mapTo(d->m_quickWidget->window(), QPoint());
142 QWindow *result =
nullptr;
143#if QT_CONFIG(graphicsview)
144 QWidgetPrivate *widgetd = QWidgetPrivate::get(d->m_quickWidget);
145 if (widgetd->extra) {
146 if (
auto proxy = widgetd->extra->proxyWidget) {
147 auto scene = proxy->scene();
149 const auto views = scene->views();
150 if (!views.isEmpty()) {
153 auto candidateView = views.first();
154 result = candidateView->window()->windowHandle();
161 result = d->m_quickWidget->window()->windowHandle();
171 offscreenWindow->setScreen(q->screen());
174 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInitialized()), q, SLOT(createFramebufferObject()));
175 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInvalidated()), q, SLOT(destroyFramebufferObject()));
176 QWidget::connect(offscreenWindow, &QQuickWindow::focusObjectChanged, q, &QQuickWidget::propagateFocusObjectChanged);
178#if QT_CONFIG(accessibility)
179 QAccessible::installFactory(&qAccessibleQuickWidgetFactory);
192 renderControl =
new QQuickWidgetRenderControl(q);
193 if (!offscreenWindow)
194 offscreenWindow =
new QQuickWidgetOffscreenWindow(*
new QQuickWidgetOffscreenWindowPrivate(), renderControl);
197 auto sgRendererInterface = offscreenWindow->rendererInterface();
198 if (sgRendererInterface && sgRendererInterface->graphicsApi() == QSGRendererInterface::Software)
209 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering))
210 setRenderToTexture();
212 qWarning(
"QQuickWidget is not supported on this platform.");
217 if (!engine.isNull() && !engine.data()->incubationController())
218 engine.data()->setIncubationController(offscreenWindow->incubationController());
220 q->setMouseTracking(
true);
221 q->setFocusPolicy(Qt::StrongFocus);
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 q->setAttribute(Qt::WA_AcceptTouchEvents);
241#if QT_CONFIG(quick_draganddrop)
242 q->setAcceptDrops(
true);
245 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
246 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
251 Q_Q(
const QQuickWidget);
252 if (!engine.isNull())
255 engine =
new QQmlEngine(
const_cast<QQuickWidget*>(q));
256 engine.data()->setIncubationController(offscreenWindow->incubationController());
263 rhi->makeThreadLocalNativeContextCurrent();
273 rhi->removeCleanupCallback(q);
284 if (offscreenWindow->isPersistentSceneGraph()
285 && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)
286 && rhiConfig().api() == QPlatformBackingStoreRhiConfig::OpenGL)
297 QScopedPointer<QQuickWindow> oldOffScreenWindow(offscreenWindow);
298 offscreenWindow =
nullptr;
301 renderControl =
new QQuickWidgetRenderControl(q);
304 if (oldOffScreenWindow)
305 offscreenWindow->setColor(oldOffScreenWindow->color());
307 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
308 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
310 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
311 sgItem->setParentItem(offscreenWindow->contentItem());
317 , offscreenWindow(
nullptr)
325 , resizeMode(QQuickWidget::SizeViewToRootObject)
355 q->destroyFramebufferObject();
356 delete offscreenWindow;
358 offscreenRenderer.reset();
366 if (!source.isEmpty()) {
367 component =
new QQmlComponent(engine.data(), source, q);
369 q->continueExecute();
371 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
372 q, SLOT(continueExecute()));
382 component =
new QQmlComponent(engine.data(), uri, typeName, q);
384 q->continueExecute();
386 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
387 q, SLOT(continueExecute()));
392 const QRectF &oldGeometry)
395 if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) {
397 resizetimer.start(0,q);
399 QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
409 q->createFramebufferObject();
413 qWarning(
"QQuickWidget: Attempted to render scene with no rhi");
423 QQuickRenderControlPrivate::FrameStatus frameStatus = QQuickRenderControlPrivate::get(renderControl)->frameStatus;
424 if (frameStatus == QQuickRenderControlPrivate::DeviceLostInBeginFrame) {
431 if (frameStatus != QQuickRenderControlPrivate::RecordingFrame) {
432 qWarning(
"QQuickWidget: Failed to begin recording a frame");
450 if (!offscreenWindow)
452 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
453 auto softwareRenderer =
static_cast<QSGSoftwareRenderer*>(cd->renderer);
454 if (softwareRenderer && !softwareImage.isNull()) {
455 softwareRenderer->setCurrentPaintDevice(&softwareImage);
457 softwareRenderer->markDirty();
462 updateRegion += softwareRenderer->flushRegion();
472 if (!q->isVisible() || fakeHidden)
477#if QT_CONFIG(graphicsview)
478 if (q->window()->graphicsProxyWidget())
479 QWidgetPrivate::nearestGraphicsProxyWidget(q)->update();
483 if (!useSoftwareRenderer)
485 else if (!updateRegion.isEmpty())
486 q->update(updateRegion);
501 QRhiCommandBuffer *cb =
nullptr;
502 rhi->beginOffscreenFrame(&cb);
503 QRhiResourceUpdateBatch *resUpd =
rhi->nextResourceUpdateBatch();
504 QRhiReadbackResult readResult;
505 resUpd->readBackTexture(QRhiReadbackDescription(
outputTexture), &readResult);
506 cb->resourceUpdate(resUpd);
507 rhi->endOffscreenFrame();
508 if (!readResult.data.isEmpty()) {
509 QImage wrapperImage(
reinterpret_cast<
const uchar *>(readResult.data.constData()),
510 readResult.pixelSize.width(), readResult.pixelSize.height(),
511 QImage::Format_RGBA8888_Premultiplied);
512 if (
rhi->isYUpInFramebuffer())
513 return wrapperImage.flipped();
515 return wrapperImage.copy();
520 return offscreenWindow->grabWindow();
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
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
669
670
671
674
675
676
677
678QQuickWidget::QQuickWidget(QWidget *parent)
679 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
685
686
687
688
689
690QQuickWidget::QQuickWidget(
const QUrl &source, QWidget *parent)
691 : QQuickWidget(parent)
697
698
699
700
701
702
703QQuickWidget::QQuickWidget(QAnyStringView uri, QAnyStringView typeName, QWidget *parent)
704 : QQuickWidget(parent)
706 loadFromModule(uri, typeName);
710
711
712
713
714
715
716QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
717 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
719 d_func()->init(engine);
723
724
725QQuickWidget::~QQuickWidget()
734 d->rhi->removeCleanupCallback(
this);
745
746
747
748
749
750
751
752
753
756
757
758
759
760
761
762
763
764void QQuickWidget::setSource(
const QUrl& url)
772
773
774
775
776void QQuickWidget::setContent(
const QUrl& url, QQmlComponent *component, QObject* item)
780 d->component = component;
782 if (d->component && d->component->isError()) {
783 const QList<QQmlError> errorList = d->component->errors();
784 for (
const QQmlError &error : errorList) {
785 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
788 emit statusChanged(status());
792 d->setRootObject(item);
793 emit statusChanged(status());
796
797
798
799
800
801
802
803
804
805
806void QQuickWidget::setInitialProperties(
const QVariantMap &initialProperties)
809 d->initialProperties = initialProperties;
813
814
815
816
817
818
819
820
821
822
823
824
825void QQuickWidget::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
829 d->execute(uri, typeName);
833
834
835
836
837QUrl QQuickWidget::source()
const
839 Q_D(
const QQuickWidget);
844
845
846
847QQmlEngine* QQuickWidget::engine()
const
849 Q_D(
const QQuickWidget);
851 return const_cast<QQmlEngine *>(d->engine.data());
855
856
857
858
859
860
861QQmlContext* QQuickWidget::rootContext()
const
863 Q_D(
const QQuickWidget);
865 return d->engine.data()->rootContext();
869
870
871
872
873
874
875
876
877
880
881
882
883
884
885
888
889
890
891
892
893
894
895
896
897
898
899
900
903
904
905
907QQuickWidget::Status QQuickWidget::status()
const
909 Q_D(
const QQuickWidget);
910 if (!d->engine && !d->source.isEmpty())
911 return QQuickWidget::Error;
914 return QQuickWidget::Null;
916 if (d->component->status() == QQmlComponent::Ready && !d->root)
917 return QQuickWidget::Error;
919 return QQuickWidget::Status(d->component->status());
923
924
925
926
927
928QList<QQmlError> QQuickWidget::errors()
const
930 Q_D(
const QQuickWidget);
931 QList<QQmlError> errs;
934 errs = d->component->errors();
936 if (!d->engine && !d->source.isEmpty()) {
938 error.setDescription(QLatin1String(
"QQuickWidget: invalid qml engine."));
941 if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
943 error.setDescription(QLatin1String(
"QQuickWidget: invalid root object."));
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
967void QQuickWidget::setResizeMode(ResizeMode mode)
970 if (d->resizeMode == mode)
974 if (d->resizeMode == SizeViewToRootObject) {
975 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
976 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
980 d->resizeMode = mode;
989 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
990 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
991 p->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
1003 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
1004 QSize newSize = QSize(root->width(), root->height());
1005 if (newSize.isValid()) {
1006 if (newSize != q->size()) {
1008 q->updateGeometry();
1009 }
else if (offscreenWindow->size().isEmpty()) {
1012 offscreenWindow->resize(newSize);
1013 offscreenWindow->contentItem()->setSize(newSize);
1016 }
else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
1017 const bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
1018 const bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
1020 if (needToUpdateWidth && needToUpdateHeight) {
1025 const QSizeF newSize(q->width(), q->height());
1026 offscreenWindow->resize(newSize.toSize());
1027 offscreenWindow->contentItem()->setSize(newSize);
1028 root->setSize(newSize);
1029 }
else if (needToUpdateWidth) {
1030 const int newWidth = q->width();
1031 offscreenWindow->setWidth(newWidth);
1032 offscreenWindow->contentItem()->setWidth(newWidth);
1033 root->setWidth(newWidth);
1034 }
else if (needToUpdateHeight) {
1035 const int newHeight = q->height();
1036 offscreenWindow->setHeight(newHeight);
1037 offscreenWindow->contentItem()->setHeight(newHeight);
1038 root->setHeight(newHeight);
1044
1045
1046
1047
1051 if (offscreenWindow ==
nullptr)
1054 const QPoint &pos = q->mapToGlobal(QPoint(0, 0));
1055 if (offscreenWindow->position() != pos)
1056 offscreenWindow->setPosition(pos);
1061 QSize rootObjectSize(0,0);
1062 int widthCandidate = -1;
1063 int heightCandidate = -1;
1065 widthCandidate = root->width();
1066 heightCandidate = root->height();
1068 if (widthCandidate > 0) {
1069 rootObjectSize.setWidth(widthCandidate);
1071 if (heightCandidate > 0) {
1072 rootObjectSize.setHeight(heightCandidate);
1074 return rootObjectSize;
1081 QString translatedMessage;
1082 QString untranslatedMessage;
1083 QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String(
"QRhi"), &translatedMessage, &untranslatedMessage);
1085 static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError);
1086 const bool signalConnected = q->isSignalConnected(errorSignal);
1087 if (signalConnected)
1088 emit q->sceneGraphError(QQuickWindow::ContextNotAvailable, translatedMessage);
1090#if defined(Q_OS_WIN) && QT_CONFIG(messagebox)
1091 if (!signalConnected && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1092 QMessageBox::critical(q, QCoreApplication::applicationName(), translatedMessage);
1094 if (!signalConnected)
1095 qFatal(
"%s", qPrintable(untranslatedMessage));
1101 case QSGRendererInterface::OpenGL:
1102 return QPlatformBackingStoreRhiConfig::OpenGL;
1103 case QSGRendererInterface::Vulkan:
1104 return QPlatformBackingStoreRhiConfig::Vulkan;
1105 case QSGRendererInterface::Direct3D11:
1106 return QPlatformBackingStoreRhiConfig::D3D11;
1107 case QSGRendererInterface::Direct3D12:
1108 return QPlatformBackingStoreRhiConfig::D3D12;
1109 case QSGRendererInterface::Metal:
1110 return QPlatformBackingStoreRhiConfig::Metal;
1112 return QPlatformBackingStoreRhiConfig::Null;
1123 QRhi *backingStoreRhi = QWidgetPrivate::rhi();
1124 if (backingStoreRhi &&
rhi != backingStoreRhi) {
1128 if (rhi == offscreenRenderer.rhi()) {
1139 const bool onlyNeedsSgInit = rhi && !offscreenWindow->isSceneGraphInitialized();
1141 if (!onlyNeedsSgInit) {
1145 if (QRhi *backingStoreRhi = QWidgetPrivate::rhi()) {
1146 rhi = backingStoreRhi;
1148 rhi->addCleanupCallback(q, [
this](QRhi *rhi) {
1149 if (
this->rhi == rhi) {
1152 this->rhi =
nullptr;
1163 offscreenRenderer.setConfig(rhiConfig());
1164 offscreenRenderer.setFormat(q->format());
1166 if (offscreenRenderer.create())
1167 rhi = offscreenRenderer.rhi();
1172 if (rhi && rhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()))) {
1173 qWarning(
"The top-level window is not using the expected graphics API for composition, "
1174 "'%s' is not compatible with this QQuickWidget",
1175 rhi->backendName());
1181 if (!offscreenWindow->isSceneGraphInitialized()) {
1182 offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi));
1183#if QT_CONFIG(vulkan)
1184 if (QWindow *w = q->window()->windowHandle())
1185 offscreenWindow->setVulkanInstance(w->vulkanInstance());
1186 else if (rhi == offscreenRenderer.rhi())
1187 offscreenWindow->setVulkanInstance(QVulkanDefaultInstance::instance());
1192 qWarning(
"QQuickWidget: Failed to get a QRhi from the top-level widget's window");
1196void QQuickWidget::createFramebufferObject()
1202 if (size().isEmpty())
1208 const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
1209 d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
1210 d->offscreenWindow->contentItem()->setSize(QSizeF(width(), height()));
1212 if (d->useSoftwareRenderer) {
1213 const QSize imageSize = size() * devicePixelRatio();
1214 d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
1215 d->softwareImage.setDevicePixelRatio(devicePixelRatio());
1216 d->forceFullUpdate =
true;
1221 qWarning(
"QQuickWidget: Attempted to create output texture with no QRhi");
1225 int samples = d->requestedSamples;
1226 if (d->rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer))
1227 samples = QSGRhiSupport::chooseSampleCount(samples, d->rhi);
1231 const int minTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMin);
1232 const int maxTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMax);
1234 QSize fboSize = size() * devicePixelRatio();
1235 if (fboSize.width() > maxTexSize || fboSize.height() > maxTexSize) {
1236 qWarning(
"QQuickWidget: Requested backing texture size is %dx%d, but the maximum texture size for the 3D API implementation is %dx%d",
1237 fboSize.width(), fboSize.height(),
1238 maxTexSize, maxTexSize);
1240 fboSize.setWidth(qMin(maxTexSize, qMax(minTexSize, fboSize.width())));
1241 fboSize.setHeight(qMin(maxTexSize, qMax(minTexSize, fboSize.height())));
1244 if (!d->outputTexture) {
1245 d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
1246 if (!d->outputTexture->create()) {
1247 qWarning(
"QQuickWidget: failed to create output texture of size %dx%d",
1248 fboSize.width(), fboSize.height());
1251 if (!d->depthStencil) {
1252 d->depthStencil = d->rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, fboSize, samples);
1253 if (!d->depthStencil->create()) {
1254 qWarning(
"QQuickWidget: failed to create depth/stencil buffer of size %dx%d and sample count %d",
1255 fboSize.width(), fboSize.height(), samples);
1258 if (samples > 1 && !d->msaaBuffer) {
1259 d->msaaBuffer = d->rhi->newRenderBuffer(QRhiRenderBuffer::Color, fboSize, samples);
1260 if (!d->msaaBuffer->create()) {
1261 qWarning(
"QQuickWidget: failed to create multisample renderbuffer of size %dx%d and sample count %d",
1262 fboSize.width(), fboSize.height(), samples);
1266 QRhiTextureRenderTargetDescription rtDesc;
1267 QRhiColorAttachment colorAtt;
1269 colorAtt.setTexture(d->outputTexture);
1271 colorAtt.setRenderBuffer(d->msaaBuffer);
1272 colorAtt.setResolveTexture(d->outputTexture);
1274 rtDesc.setColorAttachments({ colorAtt });
1275 rtDesc.setDepthStencilBuffer(d->depthStencil);
1276 d->rt = d->rhi->newTextureRenderTarget(rtDesc);
1277 d->rtRp = d->rt->newCompatibleRenderPassDescriptor();
1278 d->rt->setRenderPassDescriptor(d->rtRp);
1281 if (d->outputTexture->pixelSize() != fboSize) {
1282 d->outputTexture->setPixelSize(fboSize);
1283 if (!d->outputTexture->create()) {
1284 qWarning(
"QQuickWidget: failed to create resized output texture of size %dx%d",
1285 fboSize.width(), fboSize.height());
1287 d->depthStencil->setPixelSize(fboSize);
1288 if (!d->depthStencil->create()) {
1289 qWarning(
"QQuickWidget: failed to create resized depth/stencil buffer of size %dx%d",
1290 fboSize.width(), fboSize.height());
1292 if (d->msaaBuffer) {
1293 d->msaaBuffer->setPixelSize(fboSize);
1294 if (!d->msaaBuffer->create()) {
1295 qWarning(
"QQuickWidget: failed to create resized multisample renderbuffer of size %dx%d",
1296 fboSize.width(), fboSize.height());
1301 d->offscreenWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(d->rt));
1303 d->renderControl->setSamples(samples);
1308 Q_ASSERT(!d->offscreenWindow->handle());
1311void QQuickWidget::destroyFramebufferObject()
1315 if (d->useSoftwareRenderer) {
1316 d->softwareImage = QImage();
1324 delete d->depthStencil;
1325 d->depthStencil =
nullptr;
1326 delete d->msaaBuffer;
1327 d->msaaBuffer =
nullptr;
1328 delete d->outputTexture;
1329 d->outputTexture =
nullptr;
1332QQuickWidget::ResizeMode QQuickWidget::resizeMode()
const
1334 Q_D(
const QQuickWidget);
1335 return d->resizeMode;
1339
1340
1341void QQuickWidget::continueExecute()
1344 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)),
this, SLOT(continueExecute()));
1346 if (d->component->isError()) {
1347 const QList<QQmlError> errorList = d->component->errors();
1348 for (
const QQmlError &error : errorList) {
1349 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1352 emit statusChanged(status());
1356 std::unique_ptr<QObject> obj(d->initialProperties.empty()
1357 ? d->component->create()
1358 : d->component->createWithInitialProperties(d->initialProperties));
1360 if (d->component->isError()) {
1361 const QList<QQmlError> errorList = d->component->errors();
1362 for (
const QQmlError &error : errorList) {
1363 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1366 emit statusChanged(status());
1372 if (d->source.isEmpty())
1373 d->source = d->component->url();
1375 d->setRootObject(obj.release());
1376 emit statusChanged(status());
1380
1381
1388 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
1390 sgItem->setParentItem(offscreenWindow->contentItem());
1391 }
else if (qobject_cast<QWindow *>(obj)) {
1392 qWarning() <<
"QQuickWidget does not support using windows as a root item." << Qt::endl
1394 <<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
1396 qWarning() <<
"QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
1398 <<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
1399 <<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
1404 initialSize = rootObjectSize();
1405 bool resized = q->testAttribute(Qt::WA_Resized);
1406 if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
1407 initialSize != q->size()) {
1408 q->resize(initialSize);
1423 QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()));
1425 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(offscreenWindow);
1432 const bool debugLayerRequested = wd->graphicsConfig.isDebugLayerEnabled();
1433 config.setDebugLayer(debugLayerRequested);
1444 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
1445 flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending;
1450
1451
1452
1453void QQuickWidget::timerEvent(QTimerEvent* e)
1456 if (!e || e->timerId() == d->resizetimer.timerId()) {
1458 d->resizetimer.stop();
1459 }
else if (e->timerId() == d->updateTimer.timerId()) {
1460 d->eventPending =
false;
1461 d->updateTimer.stop();
1462 if (d->updatePending)
1463 d->renderSceneGraph();
1468
1469
1470
1471QSize QQuickWidget::sizeHint()
const
1473 Q_D(
const QQuickWidget);
1474 QSize rootObjectSize = d->rootObjectSize();
1475 if (rootObjectSize.isEmpty()) {
1478 return rootObjectSize;
1483
1484
1485
1486
1487
1488
1489QSize QQuickWidget::initialSize()
const
1491 Q_D(
const QQuickWidget);
1492 return d->initialSize;
1496
1497
1498
1499
1500
1501QQuickItem *QQuickWidget::rootObject()
const
1503 Q_D(
const QQuickWidget);
1508
1509
1510
1511
1512void QQuickWidget::resizeEvent(QResizeEvent *e)
1515 if (d->resizeMode == SizeRootObjectToView)
1518 if (e->size().isEmpty()) {
1520 d->fakeHidden =
true;
1524 bool needsSync =
false;
1525 if (d->fakeHidden) {
1527 d->fakeHidden =
false;
1532 if (d->useSoftwareRenderer) {
1534 if (d->softwareImage.size() != size() * devicePixelRatio()) {
1535 createFramebufferObject();
1541 if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized())
1543 if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) {
1545 createFramebufferObject();
1551 d->initializeWithRhi();
1555 qWarning(
"QQuickWidget::resizeEvent() no QRhi");
1560 d->render(needsSync);
1564bool QQuickWidget::focusNextPrevChild(
bool next)
1568 const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
1571 auto *currentTarget = da->focusTargetItem();
1572 Q_ASSERT(currentTarget);
1574 auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next,
false);
1577 return QWidget::focusNextPrevChild(next);
1580 const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
1581 QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
1582 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
1583 QCoreApplication::sendEvent(d->offscreenWindow, &event);
1585 QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
1586 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
1587 QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
1589 return event.isAccepted();
1593void QQuickWidget::keyPressEvent(QKeyEvent *e)
1596 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
1599 QCoreApplication::sendEvent(d->offscreenWindow, e);
1603void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
1606 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
1609 QCoreApplication::sendEvent(d->offscreenWindow, e);
1613void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
1616 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->position().x(),
1623 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1624 e->button(), e->buttons(), e->modifiers(), e->source());
1626 mappedEvent.setTimestamp(e->timestamp());
1627 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1628 e->setAccepted(mappedEvent.isAccepted());
1632void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
1635 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1636 e->button(), e->buttons());
1640 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(),
1641 e->button(), e->buttons(), e->modifiers(), e->source());
1642 pressEvent.setTimestamp(e->timestamp());
1643 QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
1644 e->setAccepted(pressEvent.isAccepted());
1645 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1646 e->button(), e->buttons(), e->modifiers(), e->source());
1647 mappedEvent.setTimestamp(e->timestamp());
1648 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1652void QQuickWidget::showEvent(QShowEvent *)
1655 bool shouldTriggerUpdate =
true;
1657 if (!d->useSoftwareRenderer) {
1658 d->initializeWithRhi();
1660 if (d->offscreenWindow->isSceneGraphInitialized()) {
1661 shouldTriggerUpdate =
false;
1670 if (!d->eventPending && d->updatePending) {
1671 d->updatePending =
false;
1677 if (shouldTriggerUpdate)
1681 d->offscreenWindow->setVisible(
true);
1682 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1683 service->setParentWindow(d->offscreenWindow, window()->windowHandle());
1687void QQuickWidget::hideEvent(QHideEvent *)
1690 if (!d->offscreenWindow->isPersistentSceneGraph())
1691 d->invalidateRenderControl();
1693 d->offscreenWindow->setVisible(
false);
1694 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1695 service->setParentWindow(d->offscreenWindow, d->offscreenWindow);
1699void QQuickWidget::mousePressEvent(QMouseEvent *e)
1702 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
1705 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1706 e->button(), e->buttons(), e->modifiers(), e->source());
1707 mappedEvent.setTimestamp(e->timestamp());
1708 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1709 e->setAccepted(mappedEvent.isAccepted());
1713void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
1716 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
1719 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1720 e->button(), e->buttons(), e->modifiers(), e->source());
1721 mappedEvent.setTimestamp(e->timestamp());
1722 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1723 e->setAccepted(mappedEvent.isAccepted());
1726#if QT_CONFIG(wheelevent)
1728void QQuickWidget::wheelEvent(QWheelEvent *e)
1731 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1732 e->angleDelta().x(), e->angleDelta().y());
1735 QCoreApplication::sendEvent(d->offscreenWindow, e);
1740
1741
1742void QQuickWidget::focusInEvent(QFocusEvent * event)
1746 using FocusTarget = QWindowPrivate::FocusTarget;
1747 const Qt::FocusReason reason = event->reason();
1753 case Qt::TabFocusReason:
1754 case Qt::BacktabFocusReason: {
1755 const bool forward = reason == Qt::FocusReason::TabFocusReason;
1756 const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
1757 QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
1763 d->offscreenWindow->focusInEvent(event);
1767
1768
1769void QQuickWidget::focusOutEvent(QFocusEvent * event)
1772 d->offscreenWindow->focusOutEvent(event);
1778 if (states & Qt::WindowMinimized)
1779 return Qt::WindowMinimized;
1780 if (states & Qt::WindowMaximized)
1781 return Qt::WindowMaximized;
1782 if (states & Qt::WindowFullScreen)
1783 return Qt::WindowFullScreen;
1786 return Qt::WindowNoState;
1791 auto item = qobject_cast<QQuickItem *>(object);
1796 for (
auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
1797 if (e->queries() & query) {
1798 auto value = e->value(query);
1799 if (value.canConvert<QRectF>())
1800 e->setValue(query, item->mapRectToScene(value.toRectF()));
1804 if (e->queries() & Qt::ImCursorPosition) {
1805 auto value = e->value(Qt::ImCursorPosition);
1806 if (value.canConvert<QPointF>())
1807 e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
1812bool QQuickWidget::event(QEvent *e)
1816 switch (e->type()) {
1819 case QEvent::TouchBegin:
1820 case QEvent::TouchEnd:
1821 case QEvent::TouchUpdate:
1822 case QEvent::TouchCancel: {
1824 bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
1825 if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
1830 QPointerEvent *pointerEvent =
static_cast<QPointerEvent *>(e);
1831 auto deliveredPoints = pointerEvent->points();
1832 for (
auto &point : deliveredPoints) {
1833 if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
1834 point.setAccepted(
true);
1840 case QEvent::FocusAboutToChange:
1841 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1843 case QEvent::InputMethod:
1844 return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1845 case QEvent::InputMethodQuery:
1847 bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1852 remapInputMethodQueryEvent(d->offscreenWindow->focusObject(),
static_cast<QInputMethodQueryEvent *>(e));
1856 case QEvent::WindowAboutToChangeInternal:
1857 d->handleWindowAboutToChange();
1860 case QEvent::WindowChangeInternal:
1861 d->handleWindowChange();
1864 case QEvent::ScreenChangeInternal:
1866 QScreen *newScreen = screen();
1867 if (d->offscreenWindow)
1868 d->offscreenWindow->setScreen(newScreen);
1871 case QEvent::DevicePixelRatioChange:
1872 if (d->useSoftwareRenderer || d->outputTexture) {
1875 createFramebufferObject();
1878 if (d->offscreenWindow) {
1879 QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
1880 QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent);
1885 d->updatePosition();
1888 case QEvent::WindowStateChange:
1889 d->offscreenWindow->setWindowState(resolveWindowState(windowState()));
1892 case QEvent::ShortcutOverride:
1893 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1895 case QEvent::Enter: {
1896 QEnterEvent *enterEvent =
static_cast<QEnterEvent *>(e);
1897 QEnterEvent mappedEvent(enterEvent->position(), enterEvent->scenePosition(),
1898 enterEvent->globalPosition());
1899 const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1900 e->setAccepted(mappedEvent.isAccepted());
1907 return QWidget::event(e);
1910#if QT_CONFIG(quick_draganddrop)
1913void QQuickWidget::dragEnterEvent(QDragEnterEvent *e)
1918 d->offscreenWindow->event(e);
1923void QQuickWidget::dragMoveEvent(QDragMoveEvent *e)
1928 d->offscreenWindow->event(e);
1932void QQuickWidget::dragLeaveEvent(QDragLeaveEvent *e)
1935 d->offscreenWindow->event(e);
1939void QQuickWidget::dropEvent(QDropEvent *e)
1942 d->offscreenWindow->event(e);
1950void QQuickWidget::triggerUpdate()
1953 d->updatePending =
true;
1954 if (!d->eventPending) {
1963 const int exhaustDelay = 5;
1964 d->updateTimer.start(exhaustDelay, Qt::PreciseTimer,
this);
1965 d->eventPending =
true;
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980void QQuickWidget::setFormat(
const QSurfaceFormat &format)
1983 QSurfaceFormat currentFormat = d->offscreenWindow->format();
1984 QSurfaceFormat newFormat = format;
1985 newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
1986 newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
1987 newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
1993 d->requestedSamples = newFormat.samples();
1994 newFormat.setSamples(0);
1996 d->offscreenWindow->setFormat(newFormat);
2000
2001
2002
2003
2004
2005
2006QSurfaceFormat QQuickWidget::format()
const
2008 Q_D(
const QQuickWidget);
2009 return d->offscreenWindow->format();
2013
2014
2015
2016
2017QImage QQuickWidget::grabFramebuffer()
const
2019 return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032void QQuickWidget::setClearColor(
const QColor &color)
2035 d->offscreenWindow->setColor(color);
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056QQuickWindow *QQuickWidget::quickWindow()
const
2058 Q_D(
const QQuickWidget);
2059 return d->offscreenWindow;
2063
2064
2065void QQuickWidget::paintEvent(QPaintEvent *event)
2068 if (d->useSoftwareRenderer) {
2069 QPainter painter(
this);
2070 d->updateRegion = d->updateRegion.united(event->region());
2071 if (d->updateRegion.isNull()) {
2073 painter.drawImage(rect(), d->softwareImage);
2075 QTransform transform;
2076 transform.scale(devicePixelRatio(), devicePixelRatio());
2078 QRegion targetRegion;
2079 d->updateRegion.swap(targetRegion);
2080 for (
auto targetRect : targetRegion) {
2081 auto sourceRect = transform.mapRect(QRectF(targetRect));
2082 painter.drawImage(targetRect, d->softwareImage, sourceRect);
2088void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject)
2091 if (QApplication::focusObject() !=
this)
2093 if (QWindow *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel))
2094 emit window->focusObjectChanged(focusObject);
2099#include "moc_qquickwidget_p.cpp"
2101#include "moc_qquickwidget.cpp"