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 if (oldOffScreenWindow)
280 offscreenWindow->setColor(oldOffScreenWindow->color());
282 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
283 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
285 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
286 sgItem->setParentItem(offscreenWindow->contentItem());
292 , offscreenWindow(
nullptr)
300 , resizeMode(QQuickWidget::SizeViewToRootObject)
330 q->destroyFramebufferObject();
331 delete offscreenWindow;
333 offscreenRenderer.reset();
341 if (!source.isEmpty()) {
342 component =
new QQmlComponent(engine.data(), source, q);
344 q->continueExecute();
346 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
347 q, SLOT(continueExecute()));
357 component =
new QQmlComponent(engine.data(), uri, typeName, q);
359 q->continueExecute();
361 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
362 q, SLOT(continueExecute()));
367 const QRectF &oldGeometry)
370 if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) {
372 resizetimer.start(0,q);
374 QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
384 q->createFramebufferObject();
388 qWarning(
"QQuickWidget: Attempted to render scene with no rhi");
398 QQuickRenderControlPrivate::FrameStatus frameStatus = QQuickRenderControlPrivate::get(renderControl)->frameStatus;
399 if (frameStatus == QQuickRenderControlPrivate::DeviceLostInBeginFrame) {
406 if (frameStatus != QQuickRenderControlPrivate::RecordingFrame) {
407 qWarning(
"QQuickWidget: Failed to begin recording a frame");
425 if (!offscreenWindow)
427 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
428 auto softwareRenderer =
static_cast<QSGSoftwareRenderer*>(cd->renderer);
429 if (softwareRenderer && !softwareImage.isNull()) {
430 softwareRenderer->setCurrentPaintDevice(&softwareImage);
432 softwareRenderer->markDirty();
437 updateRegion += softwareRenderer->flushRegion();
447 if (!q->isVisible() || fakeHidden)
452#if QT_CONFIG(graphicsview)
453 if (q->window()->graphicsProxyWidget())
454 QWidgetPrivate::nearestGraphicsProxyWidget(q)->update();
458 if (!useSoftwareRenderer)
460 else if (!updateRegion.isEmpty())
461 q->update(updateRegion);
476 QRhiCommandBuffer *cb =
nullptr;
477 rhi->beginOffscreenFrame(&cb);
478 QRhiResourceUpdateBatch *resUpd =
rhi->nextResourceUpdateBatch();
479 QRhiReadbackResult readResult;
480 resUpd->readBackTexture(QRhiReadbackDescription(
outputTexture), &readResult);
481 cb->resourceUpdate(resUpd);
482 rhi->endOffscreenFrame();
483 if (!readResult.data.isEmpty()) {
484 QImage wrapperImage(
reinterpret_cast<
const uchar *>(readResult.data.constData()),
485 readResult.pixelSize.width(), readResult.pixelSize.height(),
486 QImage::Format_RGBA8888_Premultiplied);
487 if (
rhi->isYUpInFramebuffer())
488 return wrapperImage.flipped();
490 return wrapperImage.copy();
495 return offscreenWindow->grabWindow();
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
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
644
645
646
650
651
652
655
656
657
658
659QQuickWidget::QQuickWidget(QWidget *parent)
660 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
666
667
668
669
670
671QQuickWidget::QQuickWidget(
const QUrl &source, QWidget *parent)
672 : QQuickWidget(parent)
678
679
680
681
682
683
684QQuickWidget::QQuickWidget(QAnyStringView uri, QAnyStringView typeName, QWidget *parent)
685 : QQuickWidget(parent)
687 loadFromModule(uri, typeName);
691
692
693
694
695
696
697QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
698 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
700 d_func()->init(engine);
704
705
706QQuickWidget::~QQuickWidget()
715 d->rhi->removeCleanupCallback(
this);
726
727
728
729
730
731
732
733
734
737
738
739
740
741
742
743
744
745void QQuickWidget::setSource(
const QUrl& url)
753
754
755
756
757void QQuickWidget::setContent(
const QUrl& url, QQmlComponent *component, QObject* item)
761 d->component = component;
763 if (d->component && d->component->isError()) {
764 const QList<QQmlError> errorList = d->component->errors();
765 for (
const QQmlError &error : errorList) {
766 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
769 emit statusChanged(status());
773 d->setRootObject(item);
774 emit statusChanged(status());
777
778
779
780
781
782
783
784
785
786
787void QQuickWidget::setInitialProperties(
const QVariantMap &initialProperties)
790 d->initialProperties = initialProperties;
794
795
796
797
798
799
800
801
802
803
804
805
806void QQuickWidget::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
810 d->execute(uri, typeName);
814
815
816
817
818QUrl QQuickWidget::source()
const
820 Q_D(
const QQuickWidget);
825
826
827
828QQmlEngine* QQuickWidget::engine()
const
830 Q_D(
const QQuickWidget);
832 return const_cast<QQmlEngine *>(d->engine.data());
836
837
838
839
840
841
842QQmlContext* QQuickWidget::rootContext()
const
844 Q_D(
const QQuickWidget);
846 return d->engine.data()->rootContext();
850
851
852
853
854
855
856
857
858
861
862
863
864
865
866
869
870
871
872
873
874
875
876
877
878
879
880
881
884
885
886
888QQuickWidget::Status QQuickWidget::status()
const
890 Q_D(
const QQuickWidget);
891 if (!d->engine && !d->source.isEmpty())
892 return QQuickWidget::Error;
895 return QQuickWidget::Null;
897 if (d->component->status() == QQmlComponent::Ready && !d->root)
898 return QQuickWidget::Error;
900 return QQuickWidget::Status(d->component->status());
904
905
906
907
908
909QList<QQmlError> QQuickWidget::errors()
const
911 Q_D(
const QQuickWidget);
912 QList<QQmlError> errs;
915 errs = d->component->errors();
917 if (!d->engine && !d->source.isEmpty()) {
919 error.setDescription(QLatin1String(
"QQuickWidget: invalid qml engine."));
922 if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
924 error.setDescription(QLatin1String(
"QQuickWidget: invalid root object."));
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
948void QQuickWidget::setResizeMode(ResizeMode mode)
951 if (d->resizeMode == mode)
955 if (d->resizeMode == SizeViewToRootObject) {
956 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
957 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
961 d->resizeMode = mode;
970 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
971 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
972 p->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
984 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
985 QSize newSize = QSize(root->width(), root->height());
986 if (newSize.isValid()) {
987 if (newSize != q->size()) {
990 }
else if (offscreenWindow->size().isEmpty()) {
993 offscreenWindow->resize(newSize);
994 offscreenWindow->contentItem()->setSize(newSize);
997 }
else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
998 const bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
999 const bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
1001 if (needToUpdateWidth && needToUpdateHeight) {
1006 const QSizeF newSize(q->width(), q->height());
1007 offscreenWindow->resize(newSize.toSize());
1008 offscreenWindow->contentItem()->setSize(newSize);
1009 root->setSize(newSize);
1010 }
else if (needToUpdateWidth) {
1011 const int newWidth = q->width();
1012 offscreenWindow->setWidth(newWidth);
1013 offscreenWindow->contentItem()->setWidth(newWidth);
1014 root->setWidth(newWidth);
1015 }
else if (needToUpdateHeight) {
1016 const int newHeight = q->height();
1017 offscreenWindow->setHeight(newHeight);
1018 offscreenWindow->contentItem()->setHeight(newHeight);
1019 root->setHeight(newHeight);
1025
1026
1027
1028
1032 if (offscreenWindow ==
nullptr)
1035 const QPoint &pos = q->mapToGlobal(QPoint(0, 0));
1036 if (offscreenWindow->position() != pos)
1037 offscreenWindow->setPosition(pos);
1042 QSize rootObjectSize(0,0);
1043 int widthCandidate = -1;
1044 int heightCandidate = -1;
1046 widthCandidate = root->width();
1047 heightCandidate = root->height();
1049 if (widthCandidate > 0) {
1050 rootObjectSize.setWidth(widthCandidate);
1052 if (heightCandidate > 0) {
1053 rootObjectSize.setHeight(heightCandidate);
1055 return rootObjectSize;
1062 QString translatedMessage;
1063 QString untranslatedMessage;
1064 QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String(
"QRhi"), &translatedMessage, &untranslatedMessage);
1066 static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError);
1067 const bool signalConnected = q->isSignalConnected(errorSignal);
1068 if (signalConnected)
1069 emit q->sceneGraphError(QQuickWindow::ContextNotAvailable, translatedMessage);
1071#if defined(Q_OS_WIN) && QT_CONFIG(messagebox)
1072 if (!signalConnected && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1073 QMessageBox::critical(q, QCoreApplication::applicationName(), translatedMessage);
1075 if (!signalConnected)
1076 qFatal(
"%s", qPrintable(untranslatedMessage));
1082 case QSGRendererInterface::OpenGL:
1083 return QPlatformBackingStoreRhiConfig::OpenGL;
1084 case QSGRendererInterface::Vulkan:
1085 return QPlatformBackingStoreRhiConfig::Vulkan;
1086 case QSGRendererInterface::Direct3D11:
1087 return QPlatformBackingStoreRhiConfig::D3D11;
1088 case QSGRendererInterface::Direct3D12:
1089 return QPlatformBackingStoreRhiConfig::D3D12;
1090 case QSGRendererInterface::Metal:
1091 return QPlatformBackingStoreRhiConfig::Metal;
1093 return QPlatformBackingStoreRhiConfig::Null;
1104 QRhi *backingStoreRhi = QWidgetPrivate::rhi();
1105 if (backingStoreRhi &&
rhi != backingStoreRhi)
1111 const bool onlyNeedsSgInit = rhi && !offscreenWindow->isSceneGraphInitialized();
1113 if (!onlyNeedsSgInit) {
1117 if (QRhi *backingStoreRhi = QWidgetPrivate::rhi()) {
1118 rhi = backingStoreRhi;
1120 rhi->addCleanupCallback(q, [
this](QRhi *rhi) {
1121 if (
this->rhi == rhi) {
1124 this->rhi =
nullptr;
1135 offscreenRenderer.setConfig(rhiConfig());
1136 offscreenRenderer.setFormat(q->format());
1138 if (offscreenRenderer.create())
1139 rhi = offscreenRenderer.rhi();
1144 if (rhi && rhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()))) {
1145 qWarning(
"The top-level window is not using the expected graphics API for composition, "
1146 "'%s' is not compatible with this QQuickWidget",
1147 rhi->backendName());
1153 if (!offscreenWindow->isSceneGraphInitialized()) {
1154 offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi));
1155#if QT_CONFIG(vulkan)
1156 if (QWindow *w = q->window()->windowHandle())
1157 offscreenWindow->setVulkanInstance(w->vulkanInstance());
1158 else if (rhi == offscreenRenderer.rhi())
1159 offscreenWindow->setVulkanInstance(QVulkanDefaultInstance::instance());
1164 qWarning(
"QQuickWidget: Failed to get a QRhi from the top-level widget's window");
1168void QQuickWidget::createFramebufferObject()
1174 if (size().isEmpty())
1180 const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
1181 d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
1182 d->offscreenWindow->contentItem()->setSize(QSizeF(width(), height()));
1184 if (d->useSoftwareRenderer) {
1185 const QSize imageSize = size() * devicePixelRatio();
1186 d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
1187 d->softwareImage.setDevicePixelRatio(devicePixelRatio());
1188 d->forceFullUpdate =
true;
1193 qWarning(
"QQuickWidget: Attempted to create output texture with no QRhi");
1197 int samples = d->requestedSamples;
1198 if (d->rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer))
1199 samples = QSGRhiSupport::chooseSampleCount(samples, d->rhi);
1203 const int minTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMin);
1204 const int maxTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMax);
1206 QSize fboSize = size() * devicePixelRatio();
1207 if (fboSize.width() > maxTexSize || fboSize.height() > maxTexSize) {
1208 qWarning(
"QQuickWidget: Requested backing texture size is %dx%d, but the maximum texture size for the 3D API implementation is %dx%d",
1209 fboSize.width(), fboSize.height(),
1210 maxTexSize, maxTexSize);
1212 fboSize.setWidth(qMin(maxTexSize, qMax(minTexSize, fboSize.width())));
1213 fboSize.setHeight(qMin(maxTexSize, qMax(minTexSize, fboSize.height())));
1216 if (!d->outputTexture) {
1217 d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
1218 if (!d->outputTexture->create()) {
1219 qWarning(
"QQuickWidget: failed to create output texture of size %dx%d",
1220 fboSize.width(), fboSize.height());
1223 if (!d->depthStencil) {
1224 d->depthStencil = d->rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, fboSize, samples);
1225 if (!d->depthStencil->create()) {
1226 qWarning(
"QQuickWidget: failed to create depth/stencil buffer of size %dx%d and sample count %d",
1227 fboSize.width(), fboSize.height(), samples);
1230 if (samples > 1 && !d->msaaBuffer) {
1231 d->msaaBuffer = d->rhi->newRenderBuffer(QRhiRenderBuffer::Color, fboSize, samples);
1232 if (!d->msaaBuffer->create()) {
1233 qWarning(
"QQuickWidget: failed to create multisample renderbuffer of size %dx%d and sample count %d",
1234 fboSize.width(), fboSize.height(), samples);
1238 QRhiTextureRenderTargetDescription rtDesc;
1239 QRhiColorAttachment colorAtt;
1241 colorAtt.setTexture(d->outputTexture);
1243 colorAtt.setRenderBuffer(d->msaaBuffer);
1244 colorAtt.setResolveTexture(d->outputTexture);
1246 rtDesc.setColorAttachments({ colorAtt });
1247 rtDesc.setDepthStencilBuffer(d->depthStencil);
1248 d->rt = d->rhi->newTextureRenderTarget(rtDesc);
1249 d->rtRp = d->rt->newCompatibleRenderPassDescriptor();
1250 d->rt->setRenderPassDescriptor(d->rtRp);
1253 if (d->outputTexture->pixelSize() != fboSize) {
1254 d->outputTexture->setPixelSize(fboSize);
1255 if (!d->outputTexture->create()) {
1256 qWarning(
"QQuickWidget: failed to create resized output texture of size %dx%d",
1257 fboSize.width(), fboSize.height());
1259 d->depthStencil->setPixelSize(fboSize);
1260 if (!d->depthStencil->create()) {
1261 qWarning(
"QQuickWidget: failed to create resized depth/stencil buffer of size %dx%d",
1262 fboSize.width(), fboSize.height());
1264 if (d->msaaBuffer) {
1265 d->msaaBuffer->setPixelSize(fboSize);
1266 if (!d->msaaBuffer->create()) {
1267 qWarning(
"QQuickWidget: failed to create resized multisample renderbuffer of size %dx%d",
1268 fboSize.width(), fboSize.height());
1273 d->offscreenWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(d->rt));
1275 d->renderControl->setSamples(samples);
1280 Q_ASSERT(!d->offscreenWindow->handle());
1283void QQuickWidget::destroyFramebufferObject()
1287 if (d->useSoftwareRenderer) {
1288 d->softwareImage = QImage();
1296 delete d->depthStencil;
1297 d->depthStencil =
nullptr;
1298 delete d->msaaBuffer;
1299 d->msaaBuffer =
nullptr;
1300 delete d->outputTexture;
1301 d->outputTexture =
nullptr;
1304QQuickWidget::ResizeMode QQuickWidget::resizeMode()
const
1306 Q_D(
const QQuickWidget);
1307 return d->resizeMode;
1311
1312
1313void QQuickWidget::continueExecute()
1316 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)),
this, SLOT(continueExecute()));
1318 if (d->component->isError()) {
1319 const QList<QQmlError> errorList = d->component->errors();
1320 for (
const QQmlError &error : errorList) {
1321 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1324 emit statusChanged(status());
1328 std::unique_ptr<QObject> obj(d->initialProperties.empty()
1329 ? d->component->create()
1330 : d->component->createWithInitialProperties(d->initialProperties));
1332 if (d->component->isError()) {
1333 const QList<QQmlError> errorList = d->component->errors();
1334 for (
const QQmlError &error : errorList) {
1335 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1338 emit statusChanged(status());
1344 if (d->source.isEmpty())
1345 d->source = d->component->url();
1347 d->setRootObject(obj.get());
1349 Q_UNUSED(obj.release());
1350 emit statusChanged(status());
1354
1355
1362 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
1364 sgItem->setParentItem(offscreenWindow->contentItem());
1365 }
else if (qobject_cast<QWindow *>(obj)) {
1366 qWarning() <<
"QQuickWidget does not support using windows as a root item." << Qt::endl
1368 <<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
1370 qWarning() <<
"QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
1372 <<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
1373 <<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
1378 initialSize = rootObjectSize();
1379 bool resized = q->testAttribute(Qt::WA_Resized);
1380 if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
1381 initialSize != q->size()) {
1382 q->resize(initialSize);
1397 QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()));
1399 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(offscreenWindow);
1406 const bool debugLayerRequested = wd->graphicsConfig.isDebugLayerEnabled();
1407 config.setDebugLayer(debugLayerRequested);
1418 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
1419 flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending;
1424
1425
1426
1427void QQuickWidget::timerEvent(QTimerEvent* e)
1430 if (!e || e->timerId() == d->resizetimer.timerId()) {
1432 d->resizetimer.stop();
1433 }
else if (e->timerId() == d->updateTimer.timerId()) {
1434 d->eventPending =
false;
1435 d->updateTimer.stop();
1436 if (d->updatePending)
1437 d->renderSceneGraph();
1442
1443
1444
1445QSize QQuickWidget::sizeHint()
const
1447 Q_D(
const QQuickWidget);
1448 QSize rootObjectSize = d->rootObjectSize();
1449 if (rootObjectSize.isEmpty()) {
1452 return rootObjectSize;
1457
1458
1459
1460
1461
1462
1463QSize QQuickWidget::initialSize()
const
1465 Q_D(
const QQuickWidget);
1466 return d->initialSize;
1470
1471
1472
1473
1474
1475QQuickItem *QQuickWidget::rootObject()
const
1477 Q_D(
const QQuickWidget);
1482
1483
1484
1485
1486void QQuickWidget::resizeEvent(QResizeEvent *e)
1489 if (d->resizeMode == SizeRootObjectToView)
1492 if (e->size().isEmpty()) {
1494 d->fakeHidden =
true;
1498 bool needsSync =
false;
1499 if (d->fakeHidden) {
1501 d->fakeHidden =
false;
1506 if (d->useSoftwareRenderer) {
1508 if (d->softwareImage.size() != size() * devicePixelRatio()) {
1509 createFramebufferObject();
1515 if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized())
1517 if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) {
1519 createFramebufferObject();
1525 d->initializeWithRhi();
1529 qWarning(
"QQuickWidget::resizeEvent() no QRhi");
1534 d->render(needsSync);
1538bool QQuickWidget::focusNextPrevChild(
bool next)
1542 const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
1545 auto *currentTarget = da->focusTargetItem();
1546 Q_ASSERT(currentTarget);
1548 auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next,
false);
1551 return QWidget::focusNextPrevChild(next);
1554 const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
1555 QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
1556 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
1557 QCoreApplication::sendEvent(d->offscreenWindow, &event);
1559 QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
1560 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
1561 QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
1563 return event.isAccepted();
1567void QQuickWidget::keyPressEvent(QKeyEvent *e)
1570 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
1573 QCoreApplication::sendEvent(d->offscreenWindow, e);
1577void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
1580 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
1583 QCoreApplication::sendEvent(d->offscreenWindow, e);
1587void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
1590 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->position().x(),
1597 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1598 e->button(), e->buttons(), e->modifiers(), e->source());
1600 mappedEvent.setTimestamp(e->timestamp());
1601 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1602 e->setAccepted(mappedEvent.isAccepted());
1606void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
1609 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1610 e->button(), e->buttons());
1614 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(),
1615 e->button(), e->buttons(), e->modifiers(), e->source());
1616 pressEvent.setTimestamp(e->timestamp());
1617 QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
1618 e->setAccepted(pressEvent.isAccepted());
1619 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1620 e->button(), e->buttons(), e->modifiers(), e->source());
1621 mappedEvent.setTimestamp(e->timestamp());
1622 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1626void QQuickWidget::showEvent(QShowEvent *)
1629 bool shouldTriggerUpdate =
true;
1631 if (!d->useSoftwareRenderer) {
1632 d->initializeWithRhi();
1634 if (d->offscreenWindow->isSceneGraphInitialized()) {
1635 shouldTriggerUpdate =
false;
1644 if (!d->eventPending && d->updatePending) {
1645 d->updatePending =
false;
1651 if (shouldTriggerUpdate)
1655 d->offscreenWindow->setVisible(
true);
1656 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1657 service->setParentWindow(d->offscreenWindow, window()->windowHandle());
1661void QQuickWidget::hideEvent(QHideEvent *)
1664 if (!d->offscreenWindow->isPersistentSceneGraph())
1665 d->invalidateRenderControl();
1667 d->offscreenWindow->setVisible(
false);
1668 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1669 service->setParentWindow(d->offscreenWindow, d->offscreenWindow);
1673void QQuickWidget::mousePressEvent(QMouseEvent *e)
1676 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
1679 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1680 e->button(), e->buttons(), e->modifiers(), e->source());
1681 mappedEvent.setTimestamp(e->timestamp());
1682 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1683 e->setAccepted(mappedEvent.isAccepted());
1687void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
1690 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
1693 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1694 e->button(), e->buttons(), e->modifiers(), e->source());
1695 mappedEvent.setTimestamp(e->timestamp());
1696 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1697 e->setAccepted(mappedEvent.isAccepted());
1700#if QT_CONFIG(wheelevent)
1702void QQuickWidget::wheelEvent(QWheelEvent *e)
1705 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1706 e->angleDelta().x(), e->angleDelta().y());
1709 QCoreApplication::sendEvent(d->offscreenWindow, e);
1714
1715
1716void QQuickWidget::focusInEvent(QFocusEvent * event)
1720 using FocusTarget = QWindowPrivate::FocusTarget;
1721 const Qt::FocusReason reason = event->reason();
1727 case Qt::TabFocusReason:
1728 case Qt::BacktabFocusReason: {
1729 const bool forward = reason == Qt::FocusReason::TabFocusReason;
1730 const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
1731 QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
1737 d->offscreenWindow->focusInEvent(event);
1741
1742
1743void QQuickWidget::focusOutEvent(QFocusEvent * event)
1746 d->offscreenWindow->focusOutEvent(event);
1752 if (states & Qt::WindowMinimized)
1753 return Qt::WindowMinimized;
1754 if (states & Qt::WindowMaximized)
1755 return Qt::WindowMaximized;
1756 if (states & Qt::WindowFullScreen)
1757 return Qt::WindowFullScreen;
1760 return Qt::WindowNoState;
1765 auto item = qobject_cast<QQuickItem *>(object);
1770 for (
auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
1771 if (e->queries() & query) {
1772 auto value = e->value(query);
1773 if (value.canConvert<QRectF>())
1774 e->setValue(query, item->mapRectToScene(value.toRectF()));
1778 if (e->queries() & Qt::ImCursorPosition) {
1779 auto value = e->value(Qt::ImCursorPosition);
1780 if (value.canConvert<QPointF>())
1781 e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
1786bool QQuickWidget::event(QEvent *e)
1790 switch (e->type()) {
1793 case QEvent::TouchBegin:
1794 case QEvent::TouchEnd:
1795 case QEvent::TouchUpdate:
1796 case QEvent::TouchCancel: {
1798 bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
1799 if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
1804 QPointerEvent *pointerEvent =
static_cast<QPointerEvent *>(e);
1805 auto deliveredPoints = pointerEvent->points();
1806 for (
auto &point : deliveredPoints) {
1807 if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
1808 point.setAccepted(
true);
1814 case QEvent::FocusAboutToChange:
1815 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1817 case QEvent::InputMethod:
1818 return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1819 case QEvent::InputMethodQuery:
1821 bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1826 remapInputMethodQueryEvent(d->offscreenWindow->focusObject(),
static_cast<QInputMethodQueryEvent *>(e));
1830 case QEvent::WindowAboutToChangeInternal:
1832 d->rhi->removeCleanupCallback(
this);
1833 d->invalidateRenderControl();
1834 d->deviceLost =
true;
1838 case QEvent::WindowChangeInternal:
1839 d->handleWindowChange();
1842 case QEvent::ScreenChangeInternal:
1844 QScreen *newScreen = screen();
1845 if (d->offscreenWindow)
1846 d->offscreenWindow->setScreen(newScreen);
1849 case QEvent::DevicePixelRatioChange:
1850 if (d->useSoftwareRenderer || d->outputTexture) {
1853 createFramebufferObject();
1856 if (d->offscreenWindow) {
1857 QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
1858 QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent);
1863 d->updatePosition();
1866 case QEvent::WindowStateChange:
1867 d->offscreenWindow->setWindowState(resolveWindowState(windowState()));
1870 case QEvent::ShortcutOverride:
1871 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1873 case QEvent::Enter: {
1874 QEnterEvent *enterEvent =
static_cast<QEnterEvent *>(e);
1875 QEnterEvent mappedEvent(enterEvent->position(), enterEvent->scenePosition(),
1876 enterEvent->globalPosition());
1877 const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1878 e->setAccepted(mappedEvent.isAccepted());
1885 return QWidget::event(e);
1888#if QT_CONFIG(quick_draganddrop)
1891void QQuickWidget::dragEnterEvent(QDragEnterEvent *e)
1896 d->offscreenWindow->event(e);
1901void QQuickWidget::dragMoveEvent(QDragMoveEvent *e)
1906 d->offscreenWindow->event(e);
1910void QQuickWidget::dragLeaveEvent(QDragLeaveEvent *e)
1913 d->offscreenWindow->event(e);
1917void QQuickWidget::dropEvent(QDropEvent *e)
1920 d->offscreenWindow->event(e);
1928void QQuickWidget::triggerUpdate()
1931 d->updatePending =
true;
1932 if (!d->eventPending) {
1941 const int exhaustDelay = 5;
1942 d->updateTimer.start(exhaustDelay, Qt::PreciseTimer,
this);
1943 d->eventPending =
true;
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958void QQuickWidget::setFormat(
const QSurfaceFormat &format)
1961 QSurfaceFormat currentFormat = d->offscreenWindow->format();
1962 QSurfaceFormat newFormat = format;
1963 newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
1964 newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
1965 newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
1971 d->requestedSamples = newFormat.samples();
1972 newFormat.setSamples(0);
1974 d->offscreenWindow->setFormat(newFormat);
1978
1979
1980
1981
1982
1983
1984QSurfaceFormat QQuickWidget::format()
const
1986 Q_D(
const QQuickWidget);
1987 return d->offscreenWindow->format();
1991
1992
1993
1994
1995QImage QQuickWidget::grabFramebuffer()
const
1997 return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010void QQuickWidget::setClearColor(
const QColor &color)
2013 d->offscreenWindow->setColor(color);
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034QQuickWindow *QQuickWidget::quickWindow()
const
2036 Q_D(
const QQuickWidget);
2037 return d->offscreenWindow;
2041
2042
2043void QQuickWidget::paintEvent(QPaintEvent *event)
2046 if (d->useSoftwareRenderer) {
2047 QPainter painter(
this);
2048 d->updateRegion = d->updateRegion.united(event->region());
2049 if (d->updateRegion.isNull()) {
2051 painter.drawImage(rect(), d->softwareImage);
2053 QTransform transform;
2054 transform.scale(devicePixelRatio(), devicePixelRatio());
2056 QRegion targetRegion;
2057 d->updateRegion.swap(targetRegion);
2058 for (
auto targetRect : targetRegion) {
2059 auto sourceRect = transform.mapRect(QRectF(targetRect));
2060 painter.drawImage(targetRect, d->softwareImage, sourceRect);
2066void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject)
2069 if (QApplication::focusObject() !=
this)
2071 if (QWindow *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel))
2072 emit window->focusObjectChanged(focusObject);
2077#include "moc_qquickwidget_p.cpp"
2079#include "moc_qquickwidget.cpp"