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"));
71 visibility = visible ? QWindow::Windowed : QWindow::Hidden;
72 q->visibilityChanged(visibility);
90 Q_DECLARE_PUBLIC(QQuickWidgetRenderControl)
98#if QT_CONFIG(graphicsview)
116 : QQuickRenderControl(*(
new QQuickWidgetRenderControlPrivate(
this, quickWidget)),
nullptr)
122 Q_D(QQuickWidgetRenderControl);
124 *offset = d->m_quickWidget->mapTo(d->m_quickWidget->window(), QPoint());
126 QWindow *result =
nullptr;
127#if QT_CONFIG(graphicsview)
128 QWidgetPrivate *widgetd = QWidgetPrivate::get(d->m_quickWidget);
129 if (widgetd->extra) {
130 if (
auto proxy = widgetd->extra->proxyWidget) {
131 auto scene = proxy->scene();
133 const auto views = scene->views();
134 if (!views.isEmpty()) {
137 auto candidateView = views.first();
138 result = candidateView->window()->windowHandle();
145 result = d->m_quickWidget->window()->windowHandle();
155 offscreenWindow->setScreen(q->screen());
158 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInitialized()), q, SLOT(createFramebufferObject()));
159 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInvalidated()), q, SLOT(destroyFramebufferObject()));
160 QWidget::connect(offscreenWindow, &QQuickWindow::focusObjectChanged, q, &QQuickWidget::propagateFocusObjectChanged);
162#if QT_CONFIG(accessibility)
163 QAccessible::installFactory(&qAccessibleQuickWidgetFactory);
176 renderControl =
new QQuickWidgetRenderControl(q);
177 if (!offscreenWindow) {
178 offscreenWindow =
new QQuickWidgetOffscreenWindow(*
new QQuickWidgetOffscreenWindowPrivate(), renderControl);
179 offscreenWindow->setProperty(
"_q_parentWidget", QVariant::fromValue(q));
183 auto sgRendererInterface = offscreenWindow->rendererInterface();
184 if (sgRendererInterface && sgRendererInterface->graphicsApi() == QSGRendererInterface::Software)
195 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering))
196 setRenderToTexture();
198 qWarning(
"QQuickWidget is not supported on this platform.");
203 if (!engine.isNull() && !engine.data()->incubationController())
204 engine.data()->setIncubationController(offscreenWindow->incubationController());
206 q->setMouseTracking(
true);
207 q->setFocusPolicy(Qt::StrongFocus);
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 q->setAttribute(Qt::WA_AcceptTouchEvents);
227#if QT_CONFIG(quick_draganddrop)
228 q->setAcceptDrops(
true);
231 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
232 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
237 Q_Q(
const QQuickWidget);
238 if (!engine.isNull())
241 engine =
new QQmlEngine(
const_cast<QQuickWidget*>(q));
242 engine.data()->setIncubationController(offscreenWindow->incubationController());
249 rhi->makeThreadLocalNativeContextCurrent();
259 if (offscreenWindow->isPersistentSceneGraph()
260 && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)
261 && rhiConfig().api() == QPlatformBackingStoreRhiConfig::OpenGL)
272 QScopedPointer<QQuickWindow> oldOffScreenWindow(offscreenWindow);
273 offscreenWindow =
nullptr;
276 renderControl =
new QQuickWidgetRenderControl(q);
279 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
280 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
282 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
283 sgItem->setParentItem(offscreenWindow->contentItem());
289 , offscreenWindow(
nullptr)
297 , resizeMode(QQuickWidget::SizeViewToRootObject)
327 q->destroyFramebufferObject();
328 delete offscreenWindow;
330 offscreenRenderer.reset();
338 if (!source.isEmpty()) {
339 component =
new QQmlComponent(engine.data(), source, q);
341 q->continueExecute();
343 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
344 q, SLOT(continueExecute()));
354 component =
new QQmlComponent(engine.data(), uri, typeName, q);
356 q->continueExecute();
358 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
359 q, SLOT(continueExecute()));
364 const QRectF &oldGeometry)
367 if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) {
369 resizetimer.start(0,q);
371 QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
381 q->createFramebufferObject();
385 qWarning(
"QQuickWidget: Attempted to render scene with no rhi");
395 QQuickRenderControlPrivate::FrameStatus frameStatus = QQuickRenderControlPrivate::get(renderControl)->frameStatus;
396 if (frameStatus == QQuickRenderControlPrivate::DeviceLostInBeginFrame) {
403 if (frameStatus != QQuickRenderControlPrivate::RecordingFrame) {
404 qWarning(
"QQuickWidget: Failed to begin recording a frame");
422 if (!offscreenWindow)
424 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
425 auto softwareRenderer =
static_cast<QSGSoftwareRenderer*>(cd->renderer);
426 if (softwareRenderer && !softwareImage.isNull()) {
427 softwareRenderer->setCurrentPaintDevice(&softwareImage);
429 softwareRenderer->markDirty();
434 updateRegion += softwareRenderer->flushRegion();
444 if (!q->isVisible() || fakeHidden)
449#if QT_CONFIG(graphicsview)
450 if (q->window()->graphicsProxyWidget())
451 QWidgetPrivate::nearestGraphicsProxyWidget(q)->update();
455 if (!useSoftwareRenderer)
457 else if (!updateRegion.isEmpty())
458 q->update(updateRegion);
473 QRhiCommandBuffer *cb =
nullptr;
474 rhi->beginOffscreenFrame(&cb);
475 QRhiResourceUpdateBatch *resUpd =
rhi->nextResourceUpdateBatch();
476 QRhiReadbackResult readResult;
477 resUpd->readBackTexture(QRhiReadbackDescription(
outputTexture), &readResult);
478 cb->resourceUpdate(resUpd);
479 rhi->endOffscreenFrame();
480 if (!readResult.data.isEmpty()) {
481 QImage wrapperImage(
reinterpret_cast<
const uchar *>(readResult.data.constData()),
482 readResult.pixelSize.width(), readResult.pixelSize.height(),
483 QImage::Format_RGBA8888_Premultiplied);
484 if (
rhi->isYUpInFramebuffer())
485 return wrapperImage.flipped();
487 return wrapperImage.copy();
492 return offscreenWindow->grabWindow();
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
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
647
648
649
652
653
654
655
656QQuickWidget::QQuickWidget(QWidget *parent)
657 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
663
664
665
666
667
668QQuickWidget::QQuickWidget(
const QUrl &source, QWidget *parent)
669 : QQuickWidget(parent)
675
676
677
678
679
680
681QQuickWidget::QQuickWidget(QAnyStringView uri, QAnyStringView typeName, QWidget *parent)
682 : QQuickWidget(parent)
684 loadFromModule(uri, typeName);
688
689
690
691
692
693
694QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
695 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
697 d_func()->init(engine);
701
702
703QQuickWidget::~QQuickWidget()
712 d->rhi->removeCleanupCallback(
this);
723
724
725
726
727
728
729
730
731
734
735
736
737
738
739
740
741
742void QQuickWidget::setSource(
const QUrl& url)
750
751
752
753
754void QQuickWidget::setContent(
const QUrl& url, QQmlComponent *component, QObject* item)
758 d->component = component;
760 if (d->component && d->component->isError()) {
761 const QList<QQmlError> errorList = d->component->errors();
762 for (
const QQmlError &error : errorList) {
763 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
766 emit statusChanged(status());
770 d->setRootObject(item);
771 emit statusChanged(status());
774
775
776
777
778
779
780
781
782
783
784void QQuickWidget::setInitialProperties(
const QVariantMap &initialProperties)
787 d->initialProperties = initialProperties;
791
792
793
794
795
796
797
798
799
800
801
802
803void QQuickWidget::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
807 d->execute(uri, typeName);
811
812
813
814
815QUrl QQuickWidget::source()
const
817 Q_D(
const QQuickWidget);
822
823
824
825QQmlEngine* QQuickWidget::engine()
const
827 Q_D(
const QQuickWidget);
829 return const_cast<QQmlEngine *>(d->engine.data());
833
834
835
836
837
838
839QQmlContext* QQuickWidget::rootContext()
const
841 Q_D(
const QQuickWidget);
843 return d->engine.data()->rootContext();
847
848
849
850
851
852
853
854
855
858
859
860
861
862
863
866
867
868
869
870
871
872
873
874
875
876
877
878
881
882
883
885QQuickWidget::Status QQuickWidget::status()
const
887 Q_D(
const QQuickWidget);
888 if (!d->engine && !d->source.isEmpty())
889 return QQuickWidget::Error;
892 return QQuickWidget::Null;
894 if (d->component->status() == QQmlComponent::Ready && !d->root)
895 return QQuickWidget::Error;
897 return QQuickWidget::Status(d->component->status());
901
902
903
904
905
906QList<QQmlError> QQuickWidget::errors()
const
908 Q_D(
const QQuickWidget);
909 QList<QQmlError> errs;
912 errs = d->component->errors();
914 if (!d->engine && !d->source.isEmpty()) {
916 error.setDescription(QLatin1String(
"QQuickWidget: invalid qml engine."));
919 if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
921 error.setDescription(QLatin1String(
"QQuickWidget: invalid root object."));
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
945void QQuickWidget::setResizeMode(ResizeMode mode)
948 if (d->resizeMode == mode)
952 if (d->resizeMode == SizeViewToRootObject) {
953 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
954 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
958 d->resizeMode = mode;
967 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
968 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
969 p->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
981 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
982 QSize newSize = QSize(root->width(), root->height());
983 if (newSize.isValid()) {
984 if (newSize != q->size()) {
987 }
else if (offscreenWindow->size().isEmpty()) {
990 offscreenWindow->resize(newSize);
991 offscreenWindow->contentItem()->setSize(newSize);
994 }
else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
995 const bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
996 const bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
998 if (needToUpdateWidth && needToUpdateHeight) {
1003 const QSizeF newSize(q->width(), q->height());
1004 offscreenWindow->resize(newSize.toSize());
1005 offscreenWindow->contentItem()->setSize(newSize);
1006 root->setSize(newSize);
1007 }
else if (needToUpdateWidth) {
1008 const int newWidth = q->width();
1009 offscreenWindow->setWidth(newWidth);
1010 offscreenWindow->contentItem()->setWidth(newWidth);
1011 root->setWidth(newWidth);
1012 }
else if (needToUpdateHeight) {
1013 const int newHeight = q->height();
1014 offscreenWindow->setHeight(newHeight);
1015 offscreenWindow->contentItem()->setHeight(newHeight);
1016 root->setHeight(newHeight);
1022
1023
1024
1025
1029 if (offscreenWindow ==
nullptr)
1032 const QPoint &pos = q->mapToGlobal(QPoint(0, 0));
1033 if (offscreenWindow->position() != pos)
1034 offscreenWindow->setPosition(pos);
1039 QSize rootObjectSize(0,0);
1040 int widthCandidate = -1;
1041 int heightCandidate = -1;
1043 widthCandidate = root->width();
1044 heightCandidate = root->height();
1046 if (widthCandidate > 0) {
1047 rootObjectSize.setWidth(widthCandidate);
1049 if (heightCandidate > 0) {
1050 rootObjectSize.setHeight(heightCandidate);
1052 return rootObjectSize;
1059 QString translatedMessage;
1060 QString untranslatedMessage;
1061 QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String(
"QRhi"), &translatedMessage, &untranslatedMessage);
1063 static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError);
1064 const bool signalConnected = q->isSignalConnected(errorSignal);
1065 if (signalConnected)
1066 emit q->sceneGraphError(QQuickWindow::ContextNotAvailable, translatedMessage);
1068#if defined(Q_OS_WIN) && QT_CONFIG(messagebox)
1069 if (!signalConnected && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1070 QMessageBox::critical(q, QCoreApplication::applicationName(), translatedMessage);
1072 if (!signalConnected)
1073 qFatal(
"%s", qPrintable(untranslatedMessage));
1079 case QSGRendererInterface::OpenGL:
1080 return QPlatformBackingStoreRhiConfig::OpenGL;
1081 case QSGRendererInterface::Vulkan:
1082 return QPlatformBackingStoreRhiConfig::Vulkan;
1083 case QSGRendererInterface::Direct3D11:
1084 return QPlatformBackingStoreRhiConfig::D3D11;
1085 case QSGRendererInterface::Direct3D12:
1086 return QPlatformBackingStoreRhiConfig::D3D12;
1087 case QSGRendererInterface::Metal:
1088 return QPlatformBackingStoreRhiConfig::Metal;
1090 return QPlatformBackingStoreRhiConfig::Null;
1101 QRhi *backingStoreRhi = QWidgetPrivate::rhi();
1102 if (backingStoreRhi &&
rhi != backingStoreRhi)
1108 const bool onlyNeedsSgInit = rhi && !offscreenWindow->isSceneGraphInitialized();
1110 if (!onlyNeedsSgInit) {
1114 if (QRhi *backingStoreRhi = QWidgetPrivate::rhi()) {
1115 rhi = backingStoreRhi;
1117 rhi->addCleanupCallback(q, [
this](QRhi *rhi) {
1118 if (
this->rhi == rhi) {
1119 invalidateRenderControl();
1121 this->rhi =
nullptr;
1132 offscreenRenderer.setConfig(rhiConfig());
1133 offscreenRenderer.setFormat(q->format());
1135 if (offscreenRenderer.create())
1136 rhi = offscreenRenderer.rhi();
1141 if (rhi && rhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()))) {
1142 qWarning(
"The top-level window is not using the expected graphics API for composition, "
1143 "'%s' is not compatible with this QQuickWidget",
1144 rhi->backendName());
1150 if (!offscreenWindow->isSceneGraphInitialized()) {
1151 offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi));
1152#if QT_CONFIG(vulkan)
1153 if (QWindow *w = q->window()->windowHandle())
1154 offscreenWindow->setVulkanInstance(w->vulkanInstance());
1155 else if (rhi == offscreenRenderer.rhi())
1156 offscreenWindow->setVulkanInstance(QVulkanDefaultInstance::instance());
1161 qWarning(
"QQuickWidget: Failed to get a QRhi from the top-level widget's window");
1165void QQuickWidget::createFramebufferObject()
1171 if (size().isEmpty())
1177 const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
1178 d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
1179 d->offscreenWindow->contentItem()->setSize(QSizeF(width(), height()));
1181 if (d->useSoftwareRenderer) {
1182 const QSize imageSize = size() * devicePixelRatio();
1183 d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
1184 d->softwareImage.setDevicePixelRatio(devicePixelRatio());
1185 d->forceFullUpdate =
true;
1190 qWarning(
"QQuickWidget: Attempted to create output texture with no QRhi");
1194 int samples = d->requestedSamples;
1195 if (d->rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer))
1196 samples = QSGRhiSupport::chooseSampleCount(samples, d->rhi);
1200 const int minTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMin);
1201 const int maxTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMax);
1203 QSize fboSize = size() * devicePixelRatio();
1204 if (fboSize.width() > maxTexSize || fboSize.height() > maxTexSize) {
1205 qWarning(
"QQuickWidget: Requested backing texture size is %dx%d, but the maximum texture size for the 3D API implementation is %dx%d",
1206 fboSize.width(), fboSize.height(),
1207 maxTexSize, maxTexSize);
1209 fboSize.setWidth(qMin(maxTexSize, qMax(minTexSize, fboSize.width())));
1210 fboSize.setHeight(qMin(maxTexSize, qMax(minTexSize, fboSize.height())));
1213 if (!d->outputTexture) {
1214 d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
1215 if (!d->outputTexture->create()) {
1216 qWarning(
"QQuickWidget: failed to create output texture of size %dx%d",
1217 fboSize.width(), fboSize.height());
1220 if (!d->depthStencil) {
1221 d->depthStencil = d->rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, fboSize, samples);
1222 if (!d->depthStencil->create()) {
1223 qWarning(
"QQuickWidget: failed to create depth/stencil buffer of size %dx%d and sample count %d",
1224 fboSize.width(), fboSize.height(), samples);
1227 if (samples > 1 && !d->msaaBuffer) {
1228 d->msaaBuffer = d->rhi->newRenderBuffer(QRhiRenderBuffer::Color, fboSize, samples);
1229 if (!d->msaaBuffer->create()) {
1230 qWarning(
"QQuickWidget: failed to create multisample renderbuffer of size %dx%d and sample count %d",
1231 fboSize.width(), fboSize.height(), samples);
1235 QRhiTextureRenderTargetDescription rtDesc;
1236 QRhiColorAttachment colorAtt;
1238 colorAtt.setTexture(d->outputTexture);
1240 colorAtt.setRenderBuffer(d->msaaBuffer);
1241 colorAtt.setResolveTexture(d->outputTexture);
1243 rtDesc.setColorAttachments({ colorAtt });
1244 rtDesc.setDepthStencilBuffer(d->depthStencil);
1245 d->rt = d->rhi->newTextureRenderTarget(rtDesc);
1246 d->rtRp = d->rt->newCompatibleRenderPassDescriptor();
1247 d->rt->setRenderPassDescriptor(d->rtRp);
1250 if (d->outputTexture->pixelSize() != fboSize) {
1251 d->outputTexture->setPixelSize(fboSize);
1252 if (!d->outputTexture->create()) {
1253 qWarning(
"QQuickWidget: failed to create resized output texture of size %dx%d",
1254 fboSize.width(), fboSize.height());
1256 d->depthStencil->setPixelSize(fboSize);
1257 if (!d->depthStencil->create()) {
1258 qWarning(
"QQuickWidget: failed to create resized depth/stencil buffer of size %dx%d",
1259 fboSize.width(), fboSize.height());
1261 if (d->msaaBuffer) {
1262 d->msaaBuffer->setPixelSize(fboSize);
1263 if (!d->msaaBuffer->create()) {
1264 qWarning(
"QQuickWidget: failed to create resized multisample renderbuffer of size %dx%d",
1265 fboSize.width(), fboSize.height());
1270 d->offscreenWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(d->rt));
1272 d->renderControl->setSamples(samples);
1277 Q_ASSERT(!d->offscreenWindow->handle());
1280void QQuickWidget::destroyFramebufferObject()
1284 if (d->useSoftwareRenderer) {
1285 d->softwareImage = QImage();
1293 delete d->depthStencil;
1294 d->depthStencil =
nullptr;
1295 delete d->msaaBuffer;
1296 d->msaaBuffer =
nullptr;
1297 delete d->outputTexture;
1298 d->outputTexture =
nullptr;
1301QQuickWidget::ResizeMode QQuickWidget::resizeMode()
const
1303 Q_D(
const QQuickWidget);
1304 return d->resizeMode;
1308
1309
1310void QQuickWidget::continueExecute()
1313 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)),
this, SLOT(continueExecute()));
1315 if (d->component->isError()) {
1316 const QList<QQmlError> errorList = d->component->errors();
1317 for (
const QQmlError &error : errorList) {
1318 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1321 emit statusChanged(status());
1325 std::unique_ptr<QObject> obj(d->initialProperties.empty()
1326 ? d->component->create()
1327 : d->component->createWithInitialProperties(d->initialProperties));
1329 if (d->component->isError()) {
1330 const QList<QQmlError> errorList = d->component->errors();
1331 for (
const QQmlError &error : errorList) {
1332 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1335 emit statusChanged(status());
1341 if (d->source.isEmpty())
1342 d->source = d->component->url();
1344 d->setRootObject(obj.get());
1346 Q_UNUSED(obj.release());
1347 emit statusChanged(status());
1351
1352
1359 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
1361 sgItem->setParentItem(offscreenWindow->contentItem());
1362 }
else if (qobject_cast<QWindow *>(obj)) {
1363 qWarning() <<
"QQuickWidget does not support using windows as a root item." << Qt::endl
1365 <<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
1367 qWarning() <<
"QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
1369 <<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
1370 <<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
1375 initialSize = rootObjectSize();
1376 bool resized = q->testAttribute(Qt::WA_Resized);
1377 if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
1378 initialSize != q->size()) {
1379 q->resize(initialSize);
1394 QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()));
1396 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(offscreenWindow);
1403 const bool debugLayerRequested = wd->graphicsConfig.isDebugLayerEnabled();
1404 config.setDebugLayer(debugLayerRequested);
1415 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
1416 flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending;
1421
1422
1423
1424void QQuickWidget::timerEvent(QTimerEvent* e)
1427 if (!e || e->timerId() == d->resizetimer.timerId()) {
1429 d->resizetimer.stop();
1430 }
else if (e->timerId() == d->updateTimer.timerId()) {
1431 d->eventPending =
false;
1432 d->updateTimer.stop();
1433 if (d->updatePending)
1434 d->renderSceneGraph();
1439
1440
1441
1442QSize QQuickWidget::sizeHint()
const
1444 Q_D(
const QQuickWidget);
1445 QSize rootObjectSize = d->rootObjectSize();
1446 if (rootObjectSize.isEmpty()) {
1449 return rootObjectSize;
1454
1455
1456
1457
1458
1459
1460QSize QQuickWidget::initialSize()
const
1462 Q_D(
const QQuickWidget);
1463 return d->initialSize;
1467
1468
1469
1470
1471QQuickItem *QQuickWidget::rootObject()
const
1473 Q_D(
const QQuickWidget);
1478
1479
1480
1481
1482void QQuickWidget::resizeEvent(QResizeEvent *e)
1485 if (d->resizeMode == SizeRootObjectToView)
1488 if (e->size().isEmpty()) {
1490 d->fakeHidden =
true;
1494 bool needsSync =
false;
1495 if (d->fakeHidden) {
1497 d->fakeHidden =
false;
1502 if (d->useSoftwareRenderer) {
1504 if (d->softwareImage.size() != size() * devicePixelRatio()) {
1505 createFramebufferObject();
1511 if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized())
1513 if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) {
1515 createFramebufferObject();
1521 d->initializeWithRhi();
1525 qWarning(
"QQuickWidget::resizeEvent() no QRhi");
1530 d->render(needsSync);
1534bool QQuickWidget::focusNextPrevChild(
bool next)
1538 const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
1541 auto *currentTarget = da->focusTargetItem();
1542 Q_ASSERT(currentTarget);
1544 auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next,
false);
1547 return QWidget::focusNextPrevChild(next);
1550 const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
1551 QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
1552 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
1553 QCoreApplication::sendEvent(d->offscreenWindow, &event);
1555 QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
1556 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
1557 QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
1559 return event.isAccepted();
1563void QQuickWidget::keyPressEvent(QKeyEvent *e)
1566 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
1569 QCoreApplication::sendEvent(d->offscreenWindow, e);
1573void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
1576 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
1579 QCoreApplication::sendEvent(d->offscreenWindow, e);
1583void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
1586 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->position().x(),
1593 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1594 e->button(), e->buttons(), e->modifiers(), e->source());
1596 mappedEvent.setTimestamp(e->timestamp());
1597 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1598 e->setAccepted(mappedEvent.isAccepted());
1602void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
1605 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1606 e->button(), e->buttons());
1610 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(),
1611 e->button(), e->buttons(), e->modifiers(), e->source());
1612 pressEvent.setTimestamp(e->timestamp());
1613 QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
1614 e->setAccepted(pressEvent.isAccepted());
1615 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1616 e->button(), e->buttons(), e->modifiers(), e->source());
1617 mappedEvent.setTimestamp(e->timestamp());
1618 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1622void QQuickWidget::showEvent(QShowEvent *)
1625 bool shouldTriggerUpdate =
true;
1627 if (!d->useSoftwareRenderer) {
1628 d->initializeWithRhi();
1630 if (d->offscreenWindow->isSceneGraphInitialized()) {
1631 shouldTriggerUpdate =
false;
1640 if (!d->eventPending && d->updatePending) {
1641 d->updatePending =
false;
1647 if (shouldTriggerUpdate)
1651 d->offscreenWindow->setVisible(
true);
1652 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1653 service->setParentWindow(d->offscreenWindow, window()->windowHandle());
1657void QQuickWidget::hideEvent(QHideEvent *)
1660 if (!d->offscreenWindow->isPersistentSceneGraph())
1661 d->invalidateRenderControl();
1663 d->offscreenWindow->setVisible(
false);
1664 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1665 service->setParentWindow(d->offscreenWindow, d->offscreenWindow);
1669void QQuickWidget::mousePressEvent(QMouseEvent *e)
1672 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
1675 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1676 e->button(), e->buttons(), e->modifiers(), e->source());
1677 mappedEvent.setTimestamp(e->timestamp());
1678 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1679 e->setAccepted(mappedEvent.isAccepted());
1683void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
1686 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
1689 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1690 e->button(), e->buttons(), e->modifiers(), e->source());
1691 mappedEvent.setTimestamp(e->timestamp());
1692 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1693 e->setAccepted(mappedEvent.isAccepted());
1696#if QT_CONFIG(wheelevent)
1698void QQuickWidget::wheelEvent(QWheelEvent *e)
1701 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1702 e->angleDelta().x(), e->angleDelta().y());
1705 QCoreApplication::sendEvent(d->offscreenWindow, e);
1710
1711
1712void QQuickWidget::focusInEvent(QFocusEvent * event)
1716 using FocusTarget = QWindowPrivate::FocusTarget;
1717 const Qt::FocusReason reason = event->reason();
1723 case Qt::TabFocusReason:
1724 case Qt::BacktabFocusReason: {
1725 const bool forward = reason == Qt::FocusReason::TabFocusReason;
1726 const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
1727 QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
1733 d->offscreenWindow->focusInEvent(event);
1737
1738
1739void QQuickWidget::focusOutEvent(QFocusEvent * event)
1742 d->offscreenWindow->focusOutEvent(event);
1748 if (states & Qt::WindowMinimized)
1749 return Qt::WindowMinimized;
1750 if (states & Qt::WindowMaximized)
1751 return Qt::WindowMaximized;
1752 if (states & Qt::WindowFullScreen)
1753 return Qt::WindowFullScreen;
1756 return Qt::WindowNoState;
1761 auto item = qobject_cast<QQuickItem *>(object);
1766 for (
auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
1767 if (e->queries() & query) {
1768 auto value = e->value(query);
1769 if (value.canConvert<QRectF>())
1770 e->setValue(query, item->mapRectToScene(value.toRectF()));
1774 if (e->queries() & Qt::ImCursorPosition) {
1775 auto value = e->value(Qt::ImCursorPosition);
1776 if (value.canConvert<QPointF>())
1777 e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
1782bool QQuickWidget::event(QEvent *e)
1786 switch (e->type()) {
1789 case QEvent::TouchBegin:
1790 case QEvent::TouchEnd:
1791 case QEvent::TouchUpdate:
1792 case QEvent::TouchCancel: {
1794 bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
1795 if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
1800 QPointerEvent *pointerEvent =
static_cast<QPointerEvent *>(e);
1801 auto deliveredPoints = pointerEvent->points();
1802 for (
auto &point : deliveredPoints) {
1803 if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
1804 point.setAccepted(
true);
1810 case QEvent::FocusAboutToChange:
1811 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1813 case QEvent::InputMethod:
1814 return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1815 case QEvent::InputMethodQuery:
1817 bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1822 remapInputMethodQueryEvent(d->offscreenWindow->focusObject(),
static_cast<QInputMethodQueryEvent *>(e));
1826 case QEvent::WindowAboutToChangeInternal:
1828 d->rhi->removeCleanupCallback(
this);
1829 d->invalidateRenderControl();
1830 d->deviceLost =
true;
1834 case QEvent::WindowChangeInternal:
1835 d->handleWindowChange();
1838 case QEvent::ScreenChangeInternal:
1840 QScreen *newScreen = screen();
1841 if (d->offscreenWindow)
1842 d->offscreenWindow->setScreen(newScreen);
1845 case QEvent::DevicePixelRatioChange:
1846 if (d->useSoftwareRenderer || d->outputTexture) {
1849 createFramebufferObject();
1852 if (d->offscreenWindow) {
1853 QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
1854 QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent);
1859 d->updatePosition();
1862 case QEvent::WindowStateChange:
1863 d->offscreenWindow->setWindowState(resolveWindowState(windowState()));
1866 case QEvent::ShortcutOverride:
1867 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1869 case QEvent::Enter: {
1870 QEnterEvent *enterEvent =
static_cast<QEnterEvent *>(e);
1871 QEnterEvent mappedEvent(enterEvent->position(), enterEvent->scenePosition(),
1872 enterEvent->globalPosition());
1873 const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1874 e->setAccepted(mappedEvent.isAccepted());
1881 return QWidget::event(e);
1884#if QT_CONFIG(quick_draganddrop)
1887void QQuickWidget::dragEnterEvent(QDragEnterEvent *e)
1892 d->offscreenWindow->event(e);
1897void QQuickWidget::dragMoveEvent(QDragMoveEvent *e)
1902 d->offscreenWindow->event(e);
1906void QQuickWidget::dragLeaveEvent(QDragLeaveEvent *e)
1909 d->offscreenWindow->event(e);
1913void QQuickWidget::dropEvent(QDropEvent *e)
1916 d->offscreenWindow->event(e);
1924void QQuickWidget::triggerUpdate()
1927 d->updatePending =
true;
1928 if (!d->eventPending) {
1937 const int exhaustDelay = 5;
1938 d->updateTimer.start(exhaustDelay, Qt::PreciseTimer,
this);
1939 d->eventPending =
true;
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954void QQuickWidget::setFormat(
const QSurfaceFormat &format)
1957 QSurfaceFormat currentFormat = d->offscreenWindow->format();
1958 QSurfaceFormat newFormat = format;
1959 newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
1960 newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
1961 newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
1967 d->requestedSamples = newFormat.samples();
1968 newFormat.setSamples(0);
1970 d->offscreenWindow->setFormat(newFormat);
1974
1975
1976
1977
1978
1979
1980QSurfaceFormat QQuickWidget::format()
const
1982 Q_D(
const QQuickWidget);
1983 return d->offscreenWindow->format();
1987
1988
1989
1990
1991QImage QQuickWidget::grabFramebuffer()
const
1993 return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006void QQuickWidget::setClearColor(
const QColor &color)
2009 d->offscreenWindow->setColor(color);
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030QQuickWindow *QQuickWidget::quickWindow()
const
2032 Q_D(
const QQuickWidget);
2033 return d->offscreenWindow;
2037
2038
2039void QQuickWidget::paintEvent(QPaintEvent *event)
2042 if (d->useSoftwareRenderer) {
2043 QPainter painter(
this);
2044 d->updateRegion = d->updateRegion.united(event->region());
2045 if (d->updateRegion.isNull()) {
2047 painter.drawImage(rect(), d->softwareImage);
2049 QTransform transform;
2050 transform.scale(devicePixelRatio(), devicePixelRatio());
2052 QRegion targetRegion;
2053 d->updateRegion.swap(targetRegion);
2054 for (
auto targetRect : targetRegion) {
2055 auto sourceRect = transform.mapRect(QRectF(targetRect));
2056 painter.drawImage(targetRect, d->softwareImage, sourceRect);
2062void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject)
2065 if (QApplication::focusObject() !=
this)
2067 if (QWindow *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel))
2068 emit window->focusObjectChanged(focusObject);
2073#include "moc_qquickwidget_p.cpp"
2075#include "moc_qquickwidget.cpp"