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)
119 Q_D(
const QQuickWidgetOffscreenWindow);
120 if (d->renderControl) {
121 auto *priv =
static_cast<QQuickWidgetRenderControlPrivate *>(
122 QQuickRenderControlPrivate::get(d->renderControl)
124 return QAccessible::queryAccessibleInterface(priv->m_quickWidget);
130 : QQuickRenderControl(*(
new QQuickWidgetRenderControlPrivate(
this, quickWidget)),
nullptr)
136 Q_D(QQuickWidgetRenderControl);
138 *offset = d->m_quickWidget->mapTo(d->m_quickWidget->window(), QPoint());
140 QWindow *result =
nullptr;
141#if QT_CONFIG(graphicsview)
142 QWidgetPrivate *widgetd = QWidgetPrivate::get(d->m_quickWidget);
143 if (widgetd->extra) {
144 if (
auto proxy = widgetd->extra->proxyWidget) {
145 auto scene = proxy->scene();
147 const auto views = scene->views();
148 if (!views.isEmpty()) {
151 auto candidateView = views.first();
152 result = candidateView->window()->windowHandle();
159 result = d->m_quickWidget->window()->windowHandle();
169 offscreenWindow->setScreen(q->screen());
172 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInitialized()), q, SLOT(createFramebufferObject()));
173 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInvalidated()), q, SLOT(destroyFramebufferObject()));
174 QWidget::connect(offscreenWindow, &QQuickWindow::focusObjectChanged, q, &QQuickWidget::propagateFocusObjectChanged);
176#if QT_CONFIG(accessibility)
177 QAccessible::installFactory(&qAccessibleQuickWidgetFactory);
190 renderControl =
new QQuickWidgetRenderControl(q);
191 if (!offscreenWindow)
192 offscreenWindow =
new QQuickWidgetOffscreenWindow(*
new QQuickWidgetOffscreenWindowPrivate(), renderControl);
195 auto sgRendererInterface = offscreenWindow->rendererInterface();
196 if (sgRendererInterface && sgRendererInterface->graphicsApi() == QSGRendererInterface::Software)
207 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering))
208 setRenderToTexture();
210 qWarning(
"QQuickWidget is not supported on this platform.");
215 if (!engine.isNull() && !engine.data()->incubationController())
216 engine.data()->setIncubationController(offscreenWindow->incubationController());
218 q->setMouseTracking(
true);
219 q->setFocusPolicy(Qt::StrongFocus);
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236 q->setAttribute(Qt::WA_AcceptTouchEvents);
239#if QT_CONFIG(quick_draganddrop)
240 q->setAcceptDrops(
true);
243 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
244 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
249 Q_Q(
const QQuickWidget);
250 if (!engine.isNull())
253 engine =
new QQmlEngine(
const_cast<QQuickWidget*>(q));
254 engine.data()->setIncubationController(offscreenWindow->incubationController());
261 rhi->makeThreadLocalNativeContextCurrent();
271 rhi->removeCleanupCallback(q);
282 if (offscreenWindow->isPersistentSceneGraph()
283 && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)
284 && rhiConfig().api() == QPlatformBackingStoreRhiConfig::OpenGL)
295 QScopedPointer<QQuickWindow> oldOffScreenWindow(offscreenWindow);
296 offscreenWindow =
nullptr;
299 renderControl =
new QQuickWidgetRenderControl(q);
302 if (oldOffScreenWindow)
303 offscreenWindow->setColor(oldOffScreenWindow->color());
305 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
306 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
308 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
309 sgItem->setParentItem(offscreenWindow->contentItem());
315 , offscreenWindow(
nullptr)
323 , resizeMode(QQuickWidget::SizeViewToRootObject)
353 q->destroyFramebufferObject();
354 delete offscreenWindow;
356 offscreenRenderer.reset();
364 if (!source.isEmpty()) {
365 component =
new QQmlComponent(engine.data(), source, q);
367 q->continueExecute();
369 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
370 q, SLOT(continueExecute()));
380 component =
new QQmlComponent(engine.data(), uri, typeName, q);
382 q->continueExecute();
384 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
385 q, SLOT(continueExecute()));
390 const QRectF &oldGeometry)
393 if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) {
395 resizetimer.start(0,q);
397 QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
407 q->createFramebufferObject();
411 qWarning(
"QQuickWidget: Attempted to render scene with no rhi");
421 QQuickRenderControlPrivate::FrameStatus frameStatus = QQuickRenderControlPrivate::get(renderControl)->frameStatus;
422 if (frameStatus == QQuickRenderControlPrivate::DeviceLostInBeginFrame) {
429 if (frameStatus != QQuickRenderControlPrivate::RecordingFrame) {
430 qWarning(
"QQuickWidget: Failed to begin recording a frame");
448 if (!offscreenWindow)
450 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
451 auto softwareRenderer =
static_cast<QSGSoftwareRenderer*>(cd->renderer);
452 if (softwareRenderer && !softwareImage.isNull()) {
453 softwareRenderer->setCurrentPaintDevice(&softwareImage);
455 softwareRenderer->markDirty();
460 updateRegion += softwareRenderer->flushRegion();
470 if (!q->isVisible() || fakeHidden)
475#if QT_CONFIG(graphicsview)
476 if (q->window()->graphicsProxyWidget())
477 QWidgetPrivate::nearestGraphicsProxyWidget(q)->update();
481 if (!useSoftwareRenderer)
483 else if (!updateRegion.isEmpty())
484 q->update(updateRegion);
499 QRhiCommandBuffer *cb =
nullptr;
500 rhi->beginOffscreenFrame(&cb);
501 QRhiResourceUpdateBatch *resUpd =
rhi->nextResourceUpdateBatch();
502 QRhiReadbackResult readResult;
503 resUpd->readBackTexture(QRhiReadbackDescription(
outputTexture), &readResult);
504 cb->resourceUpdate(resUpd);
505 rhi->endOffscreenFrame();
506 if (!readResult.data.isEmpty()) {
507 QImage wrapperImage(
reinterpret_cast<
const uchar *>(readResult.data.constData()),
508 readResult.pixelSize.width(), readResult.pixelSize.height(),
509 QImage::Format_RGBA8888_Premultiplied);
510 if (
rhi->isYUpInFramebuffer())
511 return wrapperImage.flipped();
513 return wrapperImage.copy();
518 return offscreenWindow->grabWindow();
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
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
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
667
668
669
672
673
674
675
676QQuickWidget::QQuickWidget(QWidget *parent)
677 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
683
684
685
686
687
688QQuickWidget::QQuickWidget(
const QUrl &source, QWidget *parent)
689 : QQuickWidget(parent)
695
696
697
698
699
700
701QQuickWidget::QQuickWidget(QAnyStringView uri, QAnyStringView typeName, QWidget *parent)
702 : QQuickWidget(parent)
704 loadFromModule(uri, typeName);
708
709
710
711
712
713
714QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
715 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
717 d_func()->init(engine);
721
722
723QQuickWidget::~QQuickWidget()
732 d->rhi->removeCleanupCallback(
this);
743
744
745
746
747
748
749
750
751
754
755
756
757
758
759
760
761
762void QQuickWidget::setSource(
const QUrl& url)
770
771
772
773
774void QQuickWidget::setContent(
const QUrl& url, QQmlComponent *component, QObject* item)
778 d->component = component;
780 if (d->component && d->component->isError()) {
781 const QList<QQmlError> errorList = d->component->errors();
782 for (
const QQmlError &error : errorList) {
783 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
786 emit statusChanged(status());
790 d->setRootObject(item);
791 emit statusChanged(status());
794
795
796
797
798
799
800
801
802
803
804void QQuickWidget::setInitialProperties(
const QVariantMap &initialProperties)
807 d->initialProperties = initialProperties;
811
812
813
814
815
816
817
818
819
820
821
822
823void QQuickWidget::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
827 d->execute(uri, typeName);
831
832
833
834
835QUrl QQuickWidget::source()
const
837 Q_D(
const QQuickWidget);
842
843
844
845QQmlEngine* QQuickWidget::engine()
const
847 Q_D(
const QQuickWidget);
849 return const_cast<QQmlEngine *>(d->engine.data());
853
854
855
856
857
858
859QQmlContext* QQuickWidget::rootContext()
const
861 Q_D(
const QQuickWidget);
863 return d->engine.data()->rootContext();
867
868
869
870
871
872
873
874
875
878
879
880
881
882
883
886
887
888
889
890
891
892
893
894
895
896
897
898
901
902
903
905QQuickWidget::Status QQuickWidget::status()
const
907 Q_D(
const QQuickWidget);
908 if (!d->engine && !d->source.isEmpty())
909 return QQuickWidget::Error;
912 return QQuickWidget::Null;
914 if (d->component->status() == QQmlComponent::Ready && !d->root)
915 return QQuickWidget::Error;
917 return QQuickWidget::Status(d->component->status());
921
922
923
924
925
926QList<QQmlError> QQuickWidget::errors()
const
928 Q_D(
const QQuickWidget);
929 QList<QQmlError> errs;
932 errs = d->component->errors();
934 if (!d->engine && !d->source.isEmpty()) {
936 error.setDescription(QLatin1String(
"QQuickWidget: invalid qml engine."));
939 if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
941 error.setDescription(QLatin1String(
"QQuickWidget: invalid root object."));
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
965void QQuickWidget::setResizeMode(ResizeMode mode)
968 if (d->resizeMode == mode)
972 if (d->resizeMode == SizeViewToRootObject) {
973 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
974 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
978 d->resizeMode = mode;
987 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
988 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
989 p->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
1001 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
1002 QSize newSize = QSize(root->width(), root->height());
1003 if (newSize.isValid()) {
1004 if (newSize != q->size()) {
1006 q->updateGeometry();
1007 }
else if (offscreenWindow->size().isEmpty()) {
1010 offscreenWindow->resize(newSize);
1011 offscreenWindow->contentItem()->setSize(newSize);
1014 }
else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
1015 const bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
1016 const bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
1018 if (needToUpdateWidth && needToUpdateHeight) {
1023 const QSizeF newSize(q->width(), q->height());
1024 offscreenWindow->resize(newSize.toSize());
1025 offscreenWindow->contentItem()->setSize(newSize);
1026 root->setSize(newSize);
1027 }
else if (needToUpdateWidth) {
1028 const int newWidth = q->width();
1029 offscreenWindow->setWidth(newWidth);
1030 offscreenWindow->contentItem()->setWidth(newWidth);
1031 root->setWidth(newWidth);
1032 }
else if (needToUpdateHeight) {
1033 const int newHeight = q->height();
1034 offscreenWindow->setHeight(newHeight);
1035 offscreenWindow->contentItem()->setHeight(newHeight);
1036 root->setHeight(newHeight);
1042
1043
1044
1045
1049 if (offscreenWindow ==
nullptr)
1052 const QPoint &pos = q->mapToGlobal(QPoint(0, 0));
1053 if (offscreenWindow->position() != pos)
1054 offscreenWindow->setPosition(pos);
1059 QSize rootObjectSize(0,0);
1060 int widthCandidate = -1;
1061 int heightCandidate = -1;
1063 widthCandidate = root->width();
1064 heightCandidate = root->height();
1066 if (widthCandidate > 0) {
1067 rootObjectSize.setWidth(widthCandidate);
1069 if (heightCandidate > 0) {
1070 rootObjectSize.setHeight(heightCandidate);
1072 return rootObjectSize;
1079 QString translatedMessage;
1080 QString untranslatedMessage;
1081 QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String(
"QRhi"), &translatedMessage, &untranslatedMessage);
1083 static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError);
1084 const bool signalConnected = q->isSignalConnected(errorSignal);
1085 if (signalConnected)
1086 emit q->sceneGraphError(QQuickWindow::ContextNotAvailable, translatedMessage);
1088#if defined(Q_OS_WIN) && QT_CONFIG(messagebox)
1089 if (!signalConnected && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1090 QMessageBox::critical(q, QCoreApplication::applicationName(), translatedMessage);
1092 if (!signalConnected)
1093 qFatal(
"%s", qPrintable(untranslatedMessage));
1099 case QSGRendererInterface::OpenGL:
1100 return QPlatformBackingStoreRhiConfig::OpenGL;
1101 case QSGRendererInterface::Vulkan:
1102 return QPlatformBackingStoreRhiConfig::Vulkan;
1103 case QSGRendererInterface::Direct3D11:
1104 return QPlatformBackingStoreRhiConfig::D3D11;
1105 case QSGRendererInterface::Direct3D12:
1106 return QPlatformBackingStoreRhiConfig::D3D12;
1107 case QSGRendererInterface::Metal:
1108 return QPlatformBackingStoreRhiConfig::Metal;
1110 return QPlatformBackingStoreRhiConfig::Null;
1121 QRhi *backingStoreRhi = QWidgetPrivate::rhi();
1122 if (backingStoreRhi &&
rhi != backingStoreRhi) {
1126 if (rhi == offscreenRenderer.rhi()) {
1137 const bool onlyNeedsSgInit = rhi && !offscreenWindow->isSceneGraphInitialized();
1139 if (!onlyNeedsSgInit) {
1143 if (QRhi *backingStoreRhi = QWidgetPrivate::rhi()) {
1144 rhi = backingStoreRhi;
1146 rhi->addCleanupCallback(q, [
this](QRhi *rhi) {
1147 if (
this->rhi == rhi) {
1150 this->rhi =
nullptr;
1161 offscreenRenderer.setConfig(rhiConfig());
1162 offscreenRenderer.setFormat(q->format());
1164 if (offscreenRenderer.create())
1165 rhi = offscreenRenderer.rhi();
1170 if (rhi && rhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()))) {
1171 qWarning(
"The top-level window is not using the expected graphics API for composition, "
1172 "'%s' is not compatible with this QQuickWidget",
1173 rhi->backendName());
1179 if (!offscreenWindow->isSceneGraphInitialized()) {
1180 offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi));
1181#if QT_CONFIG(vulkan)
1182 if (QWindow *w = q->window()->windowHandle())
1183 offscreenWindow->setVulkanInstance(w->vulkanInstance());
1184 else if (rhi == offscreenRenderer.rhi())
1185 offscreenWindow->setVulkanInstance(QVulkanDefaultInstance::instance());
1190 qWarning(
"QQuickWidget: Failed to get a QRhi from the top-level widget's window");
1194void QQuickWidget::createFramebufferObject()
1200 if (size().isEmpty())
1206 const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
1207 d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
1208 d->offscreenWindow->contentItem()->setSize(QSizeF(width(), height()));
1210 if (d->useSoftwareRenderer) {
1211 const QSize imageSize = size() * devicePixelRatio();
1212 d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
1213 d->softwareImage.setDevicePixelRatio(devicePixelRatio());
1214 d->forceFullUpdate =
true;
1219 qWarning(
"QQuickWidget: Attempted to create output texture with no QRhi");
1223 int samples = d->requestedSamples;
1224 if (d->rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer))
1225 samples = QSGRhiSupport::chooseSampleCount(samples, d->rhi);
1229 const int minTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMin);
1230 const int maxTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMax);
1232 QSize fboSize = size() * devicePixelRatio();
1233 if (fboSize.width() > maxTexSize || fboSize.height() > maxTexSize) {
1234 qWarning(
"QQuickWidget: Requested backing texture size is %dx%d, but the maximum texture size for the 3D API implementation is %dx%d",
1235 fboSize.width(), fboSize.height(),
1236 maxTexSize, maxTexSize);
1238 fboSize.setWidth(qMin(maxTexSize, qMax(minTexSize, fboSize.width())));
1239 fboSize.setHeight(qMin(maxTexSize, qMax(minTexSize, fboSize.height())));
1242 if (!d->outputTexture) {
1243 d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
1244 if (!d->outputTexture->create()) {
1245 qWarning(
"QQuickWidget: failed to create output texture of size %dx%d",
1246 fboSize.width(), fboSize.height());
1249 if (!d->depthStencil) {
1250 d->depthStencil = d->rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, fboSize, samples);
1251 if (!d->depthStencil->create()) {
1252 qWarning(
"QQuickWidget: failed to create depth/stencil buffer of size %dx%d and sample count %d",
1253 fboSize.width(), fboSize.height(), samples);
1256 if (samples > 1 && !d->msaaBuffer) {
1257 d->msaaBuffer = d->rhi->newRenderBuffer(QRhiRenderBuffer::Color, fboSize, samples);
1258 if (!d->msaaBuffer->create()) {
1259 qWarning(
"QQuickWidget: failed to create multisample renderbuffer of size %dx%d and sample count %d",
1260 fboSize.width(), fboSize.height(), samples);
1264 QRhiTextureRenderTargetDescription rtDesc;
1265 QRhiColorAttachment colorAtt;
1267 colorAtt.setTexture(d->outputTexture);
1269 colorAtt.setRenderBuffer(d->msaaBuffer);
1270 colorAtt.setResolveTexture(d->outputTexture);
1272 rtDesc.setColorAttachments({ colorAtt });
1273 rtDesc.setDepthStencilBuffer(d->depthStencil);
1274 d->rt = d->rhi->newTextureRenderTarget(rtDesc);
1275 d->rtRp = d->rt->newCompatibleRenderPassDescriptor();
1276 d->rt->setRenderPassDescriptor(d->rtRp);
1279 if (d->outputTexture->pixelSize() != fboSize) {
1280 d->outputTexture->setPixelSize(fboSize);
1281 if (!d->outputTexture->create()) {
1282 qWarning(
"QQuickWidget: failed to create resized output texture of size %dx%d",
1283 fboSize.width(), fboSize.height());
1285 d->depthStencil->setPixelSize(fboSize);
1286 if (!d->depthStencil->create()) {
1287 qWarning(
"QQuickWidget: failed to create resized depth/stencil buffer of size %dx%d",
1288 fboSize.width(), fboSize.height());
1290 if (d->msaaBuffer) {
1291 d->msaaBuffer->setPixelSize(fboSize);
1292 if (!d->msaaBuffer->create()) {
1293 qWarning(
"QQuickWidget: failed to create resized multisample renderbuffer of size %dx%d",
1294 fboSize.width(), fboSize.height());
1299 d->offscreenWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(d->rt));
1301 d->renderControl->setSamples(samples);
1306 Q_ASSERT(!d->offscreenWindow->handle());
1309void QQuickWidget::destroyFramebufferObject()
1313 if (d->useSoftwareRenderer) {
1314 d->softwareImage = QImage();
1322 delete d->depthStencil;
1323 d->depthStencil =
nullptr;
1324 delete d->msaaBuffer;
1325 d->msaaBuffer =
nullptr;
1326 delete d->outputTexture;
1327 d->outputTexture =
nullptr;
1330QQuickWidget::ResizeMode QQuickWidget::resizeMode()
const
1332 Q_D(
const QQuickWidget);
1333 return d->resizeMode;
1337
1338
1339void QQuickWidget::continueExecute()
1342 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)),
this, SLOT(continueExecute()));
1344 if (d->component->isError()) {
1345 const QList<QQmlError> errorList = d->component->errors();
1346 for (
const QQmlError &error : errorList) {
1347 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1350 emit statusChanged(status());
1354 std::unique_ptr<QObject> obj(d->initialProperties.empty()
1355 ? d->component->create()
1356 : d->component->createWithInitialProperties(d->initialProperties));
1358 if (d->component->isError()) {
1359 const QList<QQmlError> errorList = d->component->errors();
1360 for (
const QQmlError &error : errorList) {
1361 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1364 emit statusChanged(status());
1370 if (d->source.isEmpty())
1371 d->source = d->component->url();
1373 d->setRootObject(obj.release());
1374 emit statusChanged(status());
1378
1379
1386 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
1388 sgItem->setParentItem(offscreenWindow->contentItem());
1389 }
else if (qobject_cast<QWindow *>(obj)) {
1390 qWarning() <<
"QQuickWidget does not support using windows as a root item." << Qt::endl
1392 <<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
1394 qWarning() <<
"QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
1396 <<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
1397 <<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
1402 initialSize = rootObjectSize();
1403 bool resized = q->testAttribute(Qt::WA_Resized);
1404 if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
1405 initialSize != q->size()) {
1406 q->resize(initialSize);
1421 QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()));
1423 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(offscreenWindow);
1430 const bool debugLayerRequested = wd->graphicsConfig.isDebugLayerEnabled();
1431 config.setDebugLayer(debugLayerRequested);
1442 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
1443 flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending;
1448
1449
1450
1451void QQuickWidget::timerEvent(QTimerEvent* e)
1454 if (!e || e->timerId() == d->resizetimer.timerId()) {
1456 d->resizetimer.stop();
1457 }
else if (e->timerId() == d->updateTimer.timerId()) {
1458 d->eventPending =
false;
1459 d->updateTimer.stop();
1460 if (d->updatePending)
1461 d->renderSceneGraph();
1466
1467
1468
1469QSize QQuickWidget::sizeHint()
const
1471 Q_D(
const QQuickWidget);
1472 QSize rootObjectSize = d->rootObjectSize();
1473 if (rootObjectSize.isEmpty()) {
1476 return rootObjectSize;
1481
1482
1483
1484
1485
1486
1487QSize QQuickWidget::initialSize()
const
1489 Q_D(
const QQuickWidget);
1490 return d->initialSize;
1494
1495
1496
1497
1498
1499QQuickItem *QQuickWidget::rootObject()
const
1501 Q_D(
const QQuickWidget);
1506
1507
1508
1509
1510void QQuickWidget::resizeEvent(QResizeEvent *e)
1513 if (d->resizeMode == SizeRootObjectToView)
1516 if (e->size().isEmpty()) {
1518 d->fakeHidden =
true;
1522 bool needsSync =
false;
1523 if (d->fakeHidden) {
1525 d->fakeHidden =
false;
1530 if (d->useSoftwareRenderer) {
1532 if (d->softwareImage.size() != size() * devicePixelRatio()) {
1533 createFramebufferObject();
1539 if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized())
1541 if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) {
1543 createFramebufferObject();
1549 d->initializeWithRhi();
1553 qWarning(
"QQuickWidget::resizeEvent() no QRhi");
1558 d->render(needsSync);
1562bool QQuickWidget::focusNextPrevChild(
bool next)
1566 const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
1569 auto *currentTarget = da->focusTargetItem();
1570 Q_ASSERT(currentTarget);
1572 auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next,
false);
1575 return QWidget::focusNextPrevChild(next);
1578 const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
1579 QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
1580 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
1581 QCoreApplication::sendEvent(d->offscreenWindow, &event);
1583 QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
1584 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
1585 QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
1587 return event.isAccepted();
1591void QQuickWidget::keyPressEvent(QKeyEvent *e)
1594 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
1597 QCoreApplication::sendEvent(d->offscreenWindow, e);
1601void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
1604 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
1607 QCoreApplication::sendEvent(d->offscreenWindow, e);
1611void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
1614 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->position().x(),
1621 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1622 e->button(), e->buttons(), e->modifiers(), e->source());
1624 mappedEvent.setTimestamp(e->timestamp());
1625 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1626 e->setAccepted(mappedEvent.isAccepted());
1630void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
1633 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1634 e->button(), e->buttons());
1638 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(),
1639 e->button(), e->buttons(), e->modifiers(), e->source());
1640 pressEvent.setTimestamp(e->timestamp());
1641 QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
1642 e->setAccepted(pressEvent.isAccepted());
1643 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1644 e->button(), e->buttons(), e->modifiers(), e->source());
1645 mappedEvent.setTimestamp(e->timestamp());
1646 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1650void QQuickWidget::showEvent(QShowEvent *)
1653 bool shouldTriggerUpdate =
true;
1655 if (!d->useSoftwareRenderer) {
1656 d->initializeWithRhi();
1658 if (d->offscreenWindow->isSceneGraphInitialized()) {
1659 shouldTriggerUpdate =
false;
1668 if (!d->eventPending && d->updatePending) {
1669 d->updatePending =
false;
1675 if (shouldTriggerUpdate)
1679 d->offscreenWindow->setVisible(
true);
1680 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1681 service->setParentWindow(d->offscreenWindow, window()->windowHandle());
1685void QQuickWidget::hideEvent(QHideEvent *)
1688 if (!d->offscreenWindow->isPersistentSceneGraph())
1689 d->invalidateRenderControl();
1691 d->offscreenWindow->setVisible(
false);
1692 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1693 service->setParentWindow(d->offscreenWindow, d->offscreenWindow);
1697void QQuickWidget::mousePressEvent(QMouseEvent *e)
1700 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
1703 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1704 e->button(), e->buttons(), e->modifiers(), e->source());
1705 mappedEvent.setTimestamp(e->timestamp());
1706 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1707 e->setAccepted(mappedEvent.isAccepted());
1711void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
1714 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
1717 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1718 e->button(), e->buttons(), e->modifiers(), e->source());
1719 mappedEvent.setTimestamp(e->timestamp());
1720 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1721 e->setAccepted(mappedEvent.isAccepted());
1724#if QT_CONFIG(wheelevent)
1726void QQuickWidget::wheelEvent(QWheelEvent *e)
1729 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1730 e->angleDelta().x(), e->angleDelta().y());
1733 QCoreApplication::sendEvent(d->offscreenWindow, e);
1738
1739
1740void QQuickWidget::focusInEvent(QFocusEvent * event)
1744 using FocusTarget = QWindowPrivate::FocusTarget;
1745 const Qt::FocusReason reason = event->reason();
1751 case Qt::TabFocusReason:
1752 case Qt::BacktabFocusReason: {
1753 const bool forward = reason == Qt::FocusReason::TabFocusReason;
1754 const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
1755 QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
1761 d->offscreenWindow->focusInEvent(event);
1765
1766
1767void QQuickWidget::focusOutEvent(QFocusEvent * event)
1770 d->offscreenWindow->focusOutEvent(event);
1776 if (states & Qt::WindowMinimized)
1777 return Qt::WindowMinimized;
1778 if (states & Qt::WindowMaximized)
1779 return Qt::WindowMaximized;
1780 if (states & Qt::WindowFullScreen)
1781 return Qt::WindowFullScreen;
1784 return Qt::WindowNoState;
1789 auto item = qobject_cast<QQuickItem *>(object);
1794 for (
auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
1795 if (e->queries() & query) {
1796 auto value = e->value(query);
1797 if (value.canConvert<QRectF>())
1798 e->setValue(query, item->mapRectToScene(value.toRectF()));
1802 if (e->queries() & Qt::ImCursorPosition) {
1803 auto value = e->value(Qt::ImCursorPosition);
1804 if (value.canConvert<QPointF>())
1805 e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
1810bool QQuickWidget::event(QEvent *e)
1814 switch (e->type()) {
1817 case QEvent::TouchBegin:
1818 case QEvent::TouchEnd:
1819 case QEvent::TouchUpdate:
1820 case QEvent::TouchCancel: {
1822 bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
1823 if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
1828 QPointerEvent *pointerEvent =
static_cast<QPointerEvent *>(e);
1829 auto deliveredPoints = pointerEvent->points();
1830 for (
auto &point : deliveredPoints) {
1831 if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
1832 point.setAccepted(
true);
1838 case QEvent::FocusAboutToChange:
1839 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1841 case QEvent::InputMethod:
1842 return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1843 case QEvent::InputMethodQuery:
1845 bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1850 remapInputMethodQueryEvent(d->offscreenWindow->focusObject(),
static_cast<QInputMethodQueryEvent *>(e));
1854 case QEvent::WindowAboutToChangeInternal:
1855 d->handleWindowAboutToChange();
1858 case QEvent::WindowChangeInternal:
1859 d->handleWindowChange();
1862 case QEvent::ScreenChangeInternal:
1864 QScreen *newScreen = screen();
1865 if (d->offscreenWindow)
1866 d->offscreenWindow->setScreen(newScreen);
1869 case QEvent::DevicePixelRatioChange:
1870 if (d->useSoftwareRenderer || d->outputTexture) {
1873 createFramebufferObject();
1876 if (d->offscreenWindow) {
1877 QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
1878 QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent);
1883 d->updatePosition();
1886 case QEvent::WindowStateChange:
1887 d->offscreenWindow->setWindowState(resolveWindowState(windowState()));
1890 case QEvent::ShortcutOverride:
1891 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1893 case QEvent::Enter: {
1894 QEnterEvent *enterEvent =
static_cast<QEnterEvent *>(e);
1895 QEnterEvent mappedEvent(enterEvent->position(), enterEvent->scenePosition(),
1896 enterEvent->globalPosition());
1897 const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1898 e->setAccepted(mappedEvent.isAccepted());
1905 return QWidget::event(e);
1908#if QT_CONFIG(quick_draganddrop)
1911void QQuickWidget::dragEnterEvent(QDragEnterEvent *e)
1916 d->offscreenWindow->event(e);
1921void QQuickWidget::dragMoveEvent(QDragMoveEvent *e)
1926 d->offscreenWindow->event(e);
1930void QQuickWidget::dragLeaveEvent(QDragLeaveEvent *e)
1933 d->offscreenWindow->event(e);
1937void QQuickWidget::dropEvent(QDropEvent *e)
1940 d->offscreenWindow->event(e);
1948void QQuickWidget::triggerUpdate()
1951 d->updatePending =
true;
1952 if (!d->eventPending) {
1961 const int exhaustDelay = 5;
1962 d->updateTimer.start(exhaustDelay, Qt::PreciseTimer,
this);
1963 d->eventPending =
true;
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978void QQuickWidget::setFormat(
const QSurfaceFormat &format)
1981 QSurfaceFormat currentFormat = d->offscreenWindow->format();
1982 QSurfaceFormat newFormat = format;
1983 newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
1984 newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
1985 newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
1991 d->requestedSamples = newFormat.samples();
1992 newFormat.setSamples(0);
1994 d->offscreenWindow->setFormat(newFormat);
1998
1999
2000
2001
2002
2003
2004QSurfaceFormat QQuickWidget::format()
const
2006 Q_D(
const QQuickWidget);
2007 return d->offscreenWindow->format();
2011
2012
2013
2014
2015QImage QQuickWidget::grabFramebuffer()
const
2017 return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030void QQuickWidget::setClearColor(
const QColor &color)
2033 d->offscreenWindow->setColor(color);
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054QQuickWindow *QQuickWidget::quickWindow()
const
2056 Q_D(
const QQuickWidget);
2057 return d->offscreenWindow;
2061
2062
2063void QQuickWidget::paintEvent(QPaintEvent *event)
2066 if (d->useSoftwareRenderer) {
2067 QPainter painter(
this);
2068 d->updateRegion = d->updateRegion.united(event->region());
2069 if (d->updateRegion.isNull()) {
2071 painter.drawImage(rect(), d->softwareImage);
2073 QTransform transform;
2074 transform.scale(devicePixelRatio(), devicePixelRatio());
2076 QRegion targetRegion;
2077 d->updateRegion.swap(targetRegion);
2078 for (
auto targetRect : targetRegion) {
2079 auto sourceRect = transform.mapRect(QRectF(targetRect));
2080 painter.drawImage(targetRect, d->softwareImage, sourceRect);
2086void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject)
2089 if (QApplication::focusObject() !=
this)
2091 if (QWindow *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel))
2092 emit window->focusObjectChanged(focusObject);
2097#include "moc_qquickwidget_p.cpp"
2099#include "moc_qquickwidget.cpp"