1 | // Copyright (C) 2020 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qquickwindow.h" |
5 | #include "qquickwindow_p.h" |
6 | |
7 | #include "qquickitem.h" |
8 | #include "qquickitem_p.h" |
9 | #include "qquickevents_p_p.h" |
10 | #include "qquickgraphicsdevice_p.h" |
11 | #include "qquickwindowcontainer_p.h" |
12 | |
13 | #include <QtQuick/private/qsgrenderer_p.h> |
14 | #include <QtQuick/private/qsgplaintexture_p.h> |
15 | #include <QtQuick/private/qquickpointerhandler_p.h> |
16 | #include <QtQuick/private/qquickpointerhandler_p_p.h> |
17 | #include <private/qsgrenderloop_p.h> |
18 | #include <private/qsgrhisupport_p.h> |
19 | #include <private/qquickrendercontrol_p.h> |
20 | #include <private/qquickanimatorcontroller_p.h> |
21 | #include <private/qquickprofiler_p.h> |
22 | #include <private/qquicktextinterface_p.h> |
23 | |
24 | #include <private/qguiapplication_p.h> |
25 | |
26 | #include <private/qabstractanimation_p.h> |
27 | |
28 | #include <QtGui/qpainter.h> |
29 | #include <QtGui/qevent.h> |
30 | #include <QtGui/qmatrix4x4.h> |
31 | #include <QtGui/private/qevent_p.h> |
32 | #include <QtGui/private/qpointingdevice_p.h> |
33 | #include <QtCore/qvarlengtharray.h> |
34 | #include <QtCore/qabstractanimation.h> |
35 | #include <QtCore/QLibraryInfo> |
36 | #include <QtCore/QRunnable> |
37 | #include <QtQml/qqmlincubator.h> |
38 | #include <QtQml/qqmlinfo.h> |
39 | #include <QtQml/private/qqmlmetatype_p.h> |
40 | |
41 | #include <QtQuick/private/qquickpixmap_p.h> |
42 | |
43 | #include <private/qqmldebugserviceinterfaces_p.h> |
44 | #include <private/qqmldebugconnector_p.h> |
45 | #include <private/qsgdefaultrendercontext_p.h> |
46 | #include <private/qsgsoftwarerenderer_p.h> |
47 | #if QT_CONFIG(opengl) |
48 | #include <private/qopengl_p.h> |
49 | #include <QOpenGLContext> |
50 | #endif |
51 | #ifndef QT_NO_DEBUG_STREAM |
52 | #include <private/qdebug_p.h> |
53 | #endif |
54 | #include <QtCore/qpointer.h> |
55 | |
56 | #include <rhi/qrhi.h> |
57 | |
58 | #include <utility> |
59 | #include <mutex> |
60 | |
61 | QT_BEGIN_NAMESPACE |
62 | |
63 | Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace) |
64 | Q_DECLARE_LOGGING_CATEGORY(lcMouse) |
65 | Q_DECLARE_LOGGING_CATEGORY(lcTouch) |
66 | Q_DECLARE_LOGGING_CATEGORY(lcPtr) |
67 | Q_LOGGING_CATEGORY(lcDirty, "qt.quick.dirty") |
68 | Q_LOGGING_CATEGORY(lcQuickWindow, "qt.quick.window") |
69 | Q_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient") |
70 | |
71 | bool QQuickWindowPrivate::defaultAlphaBuffer = false; |
72 | |
73 | #if defined(QT_QUICK_DEFAULT_TEXT_RENDER_TYPE) |
74 | QQuickWindow::TextRenderType QQuickWindowPrivate::textRenderType = QQuickWindow::QT_QUICK_DEFAULT_TEXT_RENDER_TYPE; |
75 | #else |
76 | QQuickWindow::TextRenderType QQuickWindowPrivate::textRenderType = QQuickWindow::QtTextRendering; |
77 | #endif |
78 | |
79 | class QQuickWindowIncubationController : public QObject, public QQmlIncubationController |
80 | { |
81 | Q_OBJECT |
82 | |
83 | public: |
84 | QQuickWindowIncubationController(QSGRenderLoop *loop) |
85 | : m_renderLoop(loop), m_timer(0) |
86 | { |
87 | // Allow incubation for 1/3 of a frame. |
88 | m_incubation_time = qMax(a: 1, b: int(1000 / QGuiApplication::primaryScreen()->refreshRate()) / 3); |
89 | |
90 | QAnimationDriver *animationDriver = m_renderLoop->animationDriver(); |
91 | if (animationDriver) { |
92 | connect(sender: animationDriver, signal: &QAnimationDriver::stopped, context: this, slot: &QQuickWindowIncubationController::animationStopped); |
93 | connect(sender: m_renderLoop, signal: &QSGRenderLoop::timeToIncubate, context: this, slot: &QQuickWindowIncubationController::incubate); |
94 | } |
95 | } |
96 | |
97 | protected: |
98 | void timerEvent(QTimerEvent *) override |
99 | { |
100 | killTimer(id: m_timer); |
101 | m_timer = 0; |
102 | incubate(); |
103 | } |
104 | |
105 | void incubateAgain() { |
106 | if (m_timer == 0) { |
107 | // Wait for a while before processing the next batch. Using a |
108 | // timer to avoid starvation of system events. |
109 | m_timer = startTimer(interval: m_incubation_time); |
110 | } |
111 | } |
112 | |
113 | public slots: |
114 | void incubate() { |
115 | if (m_renderLoop && incubatingObjectCount()) { |
116 | if (m_renderLoop->interleaveIncubation()) { |
117 | incubateFor(msecs: m_incubation_time); |
118 | } else { |
119 | incubateFor(msecs: m_incubation_time * 2); |
120 | if (incubatingObjectCount()) |
121 | incubateAgain(); |
122 | } |
123 | } |
124 | } |
125 | |
126 | void animationStopped() { incubate(); } |
127 | |
128 | protected: |
129 | void incubatingObjectCountChanged(int count) override |
130 | { |
131 | if (count && m_renderLoop && !m_renderLoop->interleaveIncubation()) |
132 | incubateAgain(); |
133 | } |
134 | |
135 | private: |
136 | QPointer<QSGRenderLoop> m_renderLoop; |
137 | int m_incubation_time; |
138 | int m_timer; |
139 | }; |
140 | |
141 | #if QT_CONFIG(accessibility) |
142 | /*! |
143 | Returns an accessibility interface for this window, or 0 if such an |
144 | interface cannot be created. |
145 | */ |
146 | QAccessibleInterface *QQuickWindow::accessibleRoot() const |
147 | { |
148 | return QAccessible::queryAccessibleInterface(const_cast<QQuickWindow*>(this)); |
149 | } |
150 | #endif |
151 | |
152 | |
153 | /* |
154 | Focus behavior |
155 | ============== |
156 | |
157 | Prior to being added to a valid window items can set and clear focus with no |
158 | effect. Only once items are added to a window (by way of having a parent set that |
159 | already belongs to a window) do the focus rules apply. Focus goes back to |
160 | having no effect if an item is removed from a window. |
161 | |
162 | When an item is moved into a new focus scope (either being added to a window |
163 | for the first time, or having its parent changed), if the focus scope already has |
164 | a scope focused item that takes precedence over the item being added. Otherwise, |
165 | the focus of the added tree is used. In the case of a tree of items being |
166 | added to a window for the first time, which may have a conflicted focus state (two |
167 | or more items in one scope having focus set), the same rule is applied item by item - |
168 | thus the first item that has focus will get it (assuming the scope doesn't already |
169 | have a scope focused item), and the other items will have their focus cleared. |
170 | */ |
171 | |
172 | QQuickRootItem::QQuickRootItem() |
173 | { |
174 | // child items with ItemObservesViewport can treat the window's content item |
175 | // as the ultimate viewport: avoid populating SG nodes that fall outside |
176 | setFlag(flag: ItemIsViewport); |
177 | } |
178 | |
179 | /*! \reimp */ |
180 | void QQuickWindow::exposeEvent(QExposeEvent *) |
181 | { |
182 | Q_D(QQuickWindow); |
183 | if (d->windowManager) |
184 | d->windowManager->exposureChanged(window: this); |
185 | } |
186 | |
187 | /*! \reimp */ |
188 | void QQuickWindow::resizeEvent(QResizeEvent *ev) |
189 | { |
190 | Q_D(QQuickWindow); |
191 | if (d->contentItem) |
192 | d->contentItem->setSize(ev->size()); |
193 | if (d->windowManager) |
194 | d->windowManager->resize(this); |
195 | } |
196 | |
197 | /*! \reimp */ |
198 | void QQuickWindow::showEvent(QShowEvent *) |
199 | { |
200 | Q_D(QQuickWindow); |
201 | if (d->windowManager) |
202 | d->windowManager->show(window: this); |
203 | } |
204 | |
205 | /*! \reimp */ |
206 | void QQuickWindow::hideEvent(QHideEvent *) |
207 | { |
208 | Q_D(QQuickWindow); |
209 | if (auto da = d->deliveryAgentPrivate()) |
210 | da->handleWindowHidden(win: this); |
211 | if (d->windowManager) |
212 | d->windowManager->hide(window: this); |
213 | } |
214 | |
215 | /*! \reimp */ |
216 | void QQuickWindow::closeEvent(QCloseEvent *e) |
217 | { |
218 | QQuickCloseEvent qev; |
219 | qev.setAccepted(e->isAccepted()); |
220 | emit closing(close: &qev); |
221 | e->setAccepted(qev.isAccepted()); |
222 | } |
223 | |
224 | /*! \reimp */ |
225 | void QQuickWindow::focusOutEvent(QFocusEvent *ev) |
226 | { |
227 | Q_D(QQuickWindow); |
228 | if (d->contentItem) |
229 | d->contentItem->setFocus(focus: false, reason: ev->reason()); |
230 | } |
231 | |
232 | /*! \reimp */ |
233 | void QQuickWindow::focusInEvent(QFocusEvent *ev) |
234 | { |
235 | Q_D(QQuickWindow); |
236 | if (d->inDestructor) |
237 | return; |
238 | if (d->contentItem) |
239 | d->contentItem->setFocus(focus: true, reason: ev->reason()); |
240 | if (auto da = d->deliveryAgentPrivate()) |
241 | da->updateFocusItemTransform(); |
242 | } |
243 | |
244 | #if QT_CONFIG(im) |
245 | static bool transformDirtyOnItemOrAncestor(const QQuickItem *item) |
246 | { |
247 | while (item) { |
248 | if (QQuickItemPrivate::get(item)->dirtyAttributes & ( |
249 | QQuickItemPrivate::TransformOrigin | |
250 | QQuickItemPrivate::Transform | |
251 | QQuickItemPrivate::BasicTransform | |
252 | QQuickItemPrivate::Position | |
253 | QQuickItemPrivate::Size | |
254 | QQuickItemPrivate::ParentChanged | |
255 | QQuickItemPrivate::Clip)) { |
256 | return true; |
257 | } |
258 | item = item->parentItem(); |
259 | } |
260 | return false; |
261 | } |
262 | #endif |
263 | |
264 | /*! |
265 | * \internal |
266 | |
267 | A "polish loop" can occur inside QQuickWindowPrivate::polishItems(). It is when an item calls |
268 | polish() on an(other?) item from updatePolish(). If this anomaly happens repeatedly and without |
269 | interruption (of a well-behaved updatePolish() that doesn't call polish()), it is a strong |
270 | indication that we are heading towards an infinite polish loop. A polish loop is not a bug in |
271 | Qt Quick - it is a bug caused by ill-behaved items put in the scene. |
272 | |
273 | We can detect this sequence of polish loops easily, since the |
274 | QQuickWindowPrivate::itemsToPolish is basically a stack: polish() will push to it, and |
275 | polishItems() will pop from it. |
276 | Therefore if updatePolish() calls polish(), the immediate next item polishItems() processes is |
277 | the item that was polished by the previous call to updatePolish(). |
278 | We therefore just need to count the number of polish loops we detected in _sequence_. |
279 | */ |
280 | struct PolishLoopDetector |
281 | { |
282 | PolishLoopDetector(const QVector<QQuickItem*> &itemsToPolish) |
283 | : itemsToPolish(itemsToPolish) |
284 | { |
285 | } |
286 | |
287 | /* |
288 | * returns true when it detected a likely infinite loop |
289 | * (suggests it should abort the polish loop) |
290 | **/ |
291 | bool check(QQuickItem *item, int itemsRemainingBeforeUpdatePolish) |
292 | { |
293 | if (itemsToPolish.size() > itemsRemainingBeforeUpdatePolish) { |
294 | // Detected potential polish loop. |
295 | ++numPolishLoopsInSequence; |
296 | if (numPolishLoopsInSequence == 10000) { |
297 | // We have looped 10,000 times without actually reducing the list of items to |
298 | // polish, give up for now. |
299 | // This is not a fix, just a remedy so that the application can be somewhat |
300 | // responsive. |
301 | numPolishLoopsInSequence = 0; |
302 | return true; |
303 | } |
304 | if (numPolishLoopsInSequence >= 1000 && numPolishLoopsInSequence < 1005) { |
305 | // Start to warn about polish loop after 1000 consecutive polish loops |
306 | // Show the 5 next items involved in the polish loop. |
307 | // (most likely they will be the same 5 items...) |
308 | QQuickItem *guiltyItem = itemsToPolish.last(); |
309 | qmlWarning(me: item) << "possible QQuickItem::polish() loop"; |
310 | |
311 | auto typeAndObjectName = [](QQuickItem *item) { |
312 | QString typeName = QQmlMetaType::prettyTypeName(object: item); |
313 | QString objName = item->objectName(); |
314 | if (!objName.isNull()) |
315 | return QLatin1String("%1(%2)").arg(args&: typeName, args&: objName); |
316 | return typeName; |
317 | }; |
318 | |
319 | qmlWarning(me: guiltyItem) << typeAndObjectName(guiltyItem) |
320 | << " called polish() inside updatePolish() of "<< typeAndObjectName(item); |
321 | } |
322 | } else { |
323 | numPolishLoopsInSequence = 0; |
324 | } |
325 | return false; |
326 | } |
327 | const QVector<QQuickItem*> &itemsToPolish; // Just a ref to the one in polishItems() |
328 | int numPolishLoopsInSequence = 0; |
329 | }; |
330 | |
331 | void QQuickWindowPrivate::polishItems() |
332 | { |
333 | // An item can trigger polish on another item, or itself for that matter, |
334 | // during its updatePolish() call. Because of this, we cannot simply |
335 | // iterate through the set, we must continue pulling items out until it |
336 | // is empty. |
337 | // In the case where polish is called from updatePolish() either directly |
338 | // or indirectly, we use a PolishLoopDetector to determine if a warning should |
339 | // be printed to the user. |
340 | |
341 | PolishLoopDetector polishLoopDetector(itemsToPolish); |
342 | while (!itemsToPolish.isEmpty()) { |
343 | QQuickItem *item = itemsToPolish.takeLast(); |
344 | QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); |
345 | itemPrivate->polishScheduled = false; |
346 | const int itemsRemaining = itemsToPolish.size(); |
347 | itemPrivate->updatePolish(); |
348 | item->updatePolish(); |
349 | if (polishLoopDetector.check(item, itemsRemainingBeforeUpdatePolish: itemsRemaining) == true) |
350 | break; |
351 | } |
352 | |
353 | #if QT_CONFIG(im) |
354 | if (QQuickItem *focusItem = q_func()->activeFocusItem()) { |
355 | // If the current focus item, or any of its anchestors, has changed location |
356 | // inside the window, we need inform IM about it. This to ensure that overlays |
357 | // such as selection handles will be updated. |
358 | const bool isActiveFocusItem = (focusItem == QGuiApplication::focusObject()); |
359 | const bool hasImEnabled = focusItem->inputMethodQuery(query: Qt::ImEnabled).toBool(); |
360 | if (isActiveFocusItem && hasImEnabled && transformDirtyOnItemOrAncestor(item: focusItem)) |
361 | deliveryAgentPrivate()->updateFocusItemTransform(); |
362 | } |
363 | #endif |
364 | |
365 | if (needsChildWindowStackingOrderUpdate) { |
366 | updateChildWindowStackingOrder(); |
367 | needsChildWindowStackingOrderUpdate = false; |
368 | } |
369 | } |
370 | |
371 | /*! |
372 | * Schedules the window to render another frame. |
373 | * |
374 | * Calling QQuickWindow::update() differs from QQuickItem::update() in that |
375 | * it always triggers a repaint, regardless of changes in the underlying |
376 | * scene graph or not. |
377 | */ |
378 | void QQuickWindow::update() |
379 | { |
380 | Q_D(QQuickWindow); |
381 | if (d->windowManager) |
382 | d->windowManager->update(window: this); |
383 | else if (d->renderControl) |
384 | QQuickRenderControlPrivate::get(renderControl: d->renderControl)->update(); |
385 | } |
386 | |
387 | static void updatePixelRatioHelper(QQuickItem *item, float pixelRatio) |
388 | { |
389 | if (item->flags() & QQuickItem::ItemHasContents) { |
390 | QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); |
391 | itemPrivate->itemChange(QQuickItem::ItemDevicePixelRatioHasChanged, pixelRatio); |
392 | } |
393 | |
394 | QList <QQuickItem *> items = item->childItems(); |
395 | for (int i = 0; i < items.size(); ++i) |
396 | updatePixelRatioHelper(item: items.at(i), pixelRatio); |
397 | } |
398 | |
399 | void QQuickWindow::physicalDpiChanged() |
400 | { |
401 | Q_D(QQuickWindow); |
402 | const qreal newPixelRatio = effectiveDevicePixelRatio(); |
403 | if (qFuzzyCompare(p1: newPixelRatio, p2: d->lastReportedItemDevicePixelRatio)) |
404 | return; |
405 | d->lastReportedItemDevicePixelRatio = newPixelRatio; |
406 | if (d->contentItem) |
407 | updatePixelRatioHelper(item: d->contentItem, pixelRatio: newPixelRatio); |
408 | d->forcePolish(); |
409 | } |
410 | |
411 | void QQuickWindow::handleFontDatabaseChanged() |
412 | { |
413 | Q_D(QQuickWindow); |
414 | d->pendingFontUpdate = true; |
415 | } |
416 | |
417 | void forcePolishHelper(QQuickItem *item) |
418 | { |
419 | if (item->flags() & QQuickItem::ItemHasContents) { |
420 | item->polish(); |
421 | } |
422 | |
423 | QList <QQuickItem *> items = item->childItems(); |
424 | for (int i=0; i<items.size(); ++i) |
425 | forcePolishHelper(item: items.at(i)); |
426 | } |
427 | |
428 | void QQuickWindow::handleScreenChanged(QScreen *screen) |
429 | { |
430 | Q_D(QQuickWindow); |
431 | Q_UNUSED(screen); |
432 | d->forcePolish(); |
433 | } |
434 | |
435 | /*! |
436 | Schedules polish events on all items in the scene. |
437 | */ |
438 | void QQuickWindowPrivate::forcePolish() |
439 | { |
440 | Q_Q(QQuickWindow); |
441 | if (!q->screen()) |
442 | return; |
443 | forcePolishHelper(item: contentItem); |
444 | } |
445 | |
446 | void forceUpdate(QQuickItem *item) |
447 | { |
448 | if (item->flags() & QQuickItem::ItemHasContents) |
449 | item->update(); |
450 | QQuickItemPrivate::get(item)->dirty(QQuickItemPrivate::ChildrenUpdateMask); |
451 | |
452 | QList <QQuickItem *> items = item->childItems(); |
453 | for (int i=0; i<items.size(); ++i) |
454 | forceUpdate(item: items.at(i)); |
455 | } |
456 | |
457 | void QQuickWindowRenderTarget::reset(QRhi *rhi, ResetFlags flags) |
458 | { |
459 | if (rhi) { |
460 | if (rt.owns) |
461 | delete rt.renderTarget; |
462 | |
463 | delete res.texture; |
464 | delete res.renderBuffer; |
465 | delete res.rpDesc; |
466 | } |
467 | |
468 | rt = {}; |
469 | res = {}; |
470 | |
471 | if (!flags.testFlag(flag: ResetFlag::KeepImplicitBuffers)) |
472 | implicitBuffers.reset(rhi); |
473 | |
474 | if (sw.owns) |
475 | delete sw.paintDevice; |
476 | |
477 | sw = {}; |
478 | } |
479 | |
480 | void QQuickWindowRenderTarget::ImplicitBuffers::reset(QRhi *rhi) |
481 | { |
482 | if (rhi) { |
483 | delete depthStencil; |
484 | delete depthStencilTexture; |
485 | delete multisampleTexture; |
486 | } |
487 | *this = {}; |
488 | } |
489 | |
490 | void QQuickWindowPrivate::invalidateFontData(QQuickItem *item) |
491 | { |
492 | QQuickTextInterface *textItem = qobject_cast<QQuickTextInterface *>(object: item); |
493 | if (textItem != nullptr) |
494 | textItem->invalidate(); |
495 | |
496 | QList<QQuickItem *> children = item->childItems(); |
497 | for (QQuickItem *child : children) |
498 | invalidateFontData(item: child); |
499 | } |
500 | |
501 | void QQuickWindowPrivate::ensureCustomRenderTarget() |
502 | { |
503 | // resolve() can be expensive when importing an existing native texture, so |
504 | // it is important to only do it when the QQuickRenderTarget was really changed. |
505 | if (!redirect.renderTargetDirty) |
506 | return; |
507 | |
508 | redirect.renderTargetDirty = false; |
509 | |
510 | redirect.rt.reset(rhi, flags: QQuickWindowRenderTarget::ResetFlag::KeepImplicitBuffers); |
511 | |
512 | if (!QQuickRenderTargetPrivate::get(rt: &customRenderTarget)->resolve(rhi, dst: &redirect.rt)) { |
513 | qWarning(msg: "Failed to set up render target redirection for QQuickWindow"); |
514 | redirect.rt.reset(rhi); |
515 | } |
516 | } |
517 | |
518 | void QQuickWindowPrivate::setCustomCommandBuffer(QRhiCommandBuffer *cb) |
519 | { |
520 | // ownership not transferred |
521 | redirect.commandBuffer = cb; |
522 | } |
523 | |
524 | void QQuickWindowPrivate::syncSceneGraph() |
525 | { |
526 | Q_Q(QQuickWindow); |
527 | |
528 | const bool wasRtDirty = redirect.renderTargetDirty; |
529 | ensureCustomRenderTarget(); |
530 | |
531 | QRhiCommandBuffer *cb = nullptr; |
532 | if (rhi) { |
533 | if (redirect.commandBuffer) |
534 | cb = redirect.commandBuffer; |
535 | else |
536 | cb = swapchain->currentFrameCommandBuffer(); |
537 | } |
538 | context->prepareSync(devicePixelRatio: q->effectiveDevicePixelRatio(), cb, config: graphicsConfig); |
539 | |
540 | animationController->beforeNodeSync(); |
541 | |
542 | emit q->beforeSynchronizing(); |
543 | runAndClearJobs(jobs: &beforeSynchronizingJobs); |
544 | |
545 | if (pendingFontUpdate) { |
546 | QFont::cleanup(); |
547 | invalidateFontData(item: contentItem); |
548 | } |
549 | |
550 | if (Q_UNLIKELY(!renderer)) { |
551 | forceUpdate(item: contentItem); |
552 | |
553 | QSGRootNode *rootNode = new QSGRootNode; |
554 | rootNode->appendChildNode(node: QQuickItemPrivate::get(item: contentItem)->itemNode()); |
555 | const bool useDepth = graphicsConfig.isDepthBufferEnabledFor2D(); |
556 | const QSGRendererInterface::RenderMode renderMode = useDepth ? QSGRendererInterface::RenderMode2D |
557 | : QSGRendererInterface::RenderMode2DNoDepthBuffer; |
558 | renderer = context->createRenderer(renderMode); |
559 | renderer->setRootNode(rootNode); |
560 | } else if (Q_UNLIKELY(wasRtDirty) |
561 | && q->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) { |
562 | auto softwareRenderer = static_cast<QSGSoftwareRenderer *>(renderer); |
563 | softwareRenderer->markDirty(); |
564 | } |
565 | |
566 | updateDirtyNodes(); |
567 | |
568 | animationController->afterNodeSync(); |
569 | |
570 | renderer->setClearColor(clearColor); |
571 | |
572 | renderer->setVisualizationMode(visualizationMode); |
573 | |
574 | if (pendingFontUpdate) { |
575 | context->invalidateGlyphCaches(); |
576 | pendingFontUpdate = false; |
577 | } |
578 | |
579 | emit q->afterSynchronizing(); |
580 | runAndClearJobs(jobs: &afterSynchronizingJobs); |
581 | } |
582 | |
583 | void QQuickWindowPrivate::emitBeforeRenderPassRecording(void *ud) |
584 | { |
585 | QQuickWindow *w = reinterpret_cast<QQuickWindow *>(ud); |
586 | emit w->beforeRenderPassRecording(); |
587 | } |
588 | |
589 | void QQuickWindowPrivate::emitAfterRenderPassRecording(void *ud) |
590 | { |
591 | QQuickWindow *w = reinterpret_cast<QQuickWindow *>(ud); |
592 | emit w->afterRenderPassRecording(); |
593 | } |
594 | |
595 | int QQuickWindowPrivate::multiViewCount() |
596 | { |
597 | if (rhi) { |
598 | ensureCustomRenderTarget(); |
599 | if (redirect.rt.rt.renderTarget) |
600 | return redirect.rt.rt.multiViewCount; |
601 | } |
602 | |
603 | // Note that on QRhi level 0 and 1 are often used interchangeably, as both mean |
604 | // no-multiview. Here in Qt Quick let's always use 1 as the default |
605 | // (no-multiview), so that higher layers (effects, materials) do not need to |
606 | // handle both 0 and 1, only 1. |
607 | return 1; |
608 | } |
609 | |
610 | QRhiRenderTarget *QQuickWindowPrivate::activeCustomRhiRenderTarget() |
611 | { |
612 | if (rhi) { |
613 | ensureCustomRenderTarget(); |
614 | return redirect.rt.rt.renderTarget; |
615 | } |
616 | return nullptr; |
617 | } |
618 | |
619 | void QQuickWindowPrivate::renderSceneGraph() |
620 | { |
621 | Q_Q(QQuickWindow); |
622 | if (!renderer) |
623 | return; |
624 | |
625 | ensureCustomRenderTarget(); |
626 | |
627 | QSGRenderTarget sgRenderTarget; |
628 | if (rhi) { |
629 | QRhiRenderTarget *rt; |
630 | QRhiRenderPassDescriptor *rp; |
631 | QRhiCommandBuffer *cb; |
632 | if (redirect.rt.rt.renderTarget) { |
633 | rt = redirect.rt.rt.renderTarget; |
634 | rp = rt->renderPassDescriptor(); |
635 | if (!rp) { |
636 | qWarning(msg: "Custom render target is set but no renderpass descriptor has been provided."); |
637 | return; |
638 | } |
639 | cb = redirect.commandBuffer; |
640 | if (!cb) { |
641 | qWarning(msg: "Custom render target is set but no command buffer has been provided."); |
642 | return; |
643 | } |
644 | } else { |
645 | if (!swapchain) { |
646 | qWarning(msg: "QQuickWindow: No render target (neither swapchain nor custom target was provided)"); |
647 | return; |
648 | } |
649 | rt = swapchain->currentFrameRenderTarget(); |
650 | rp = rpDescForSwapchain; |
651 | cb = swapchain->currentFrameCommandBuffer(); |
652 | } |
653 | sgRenderTarget = QSGRenderTarget(rt, rp, cb); |
654 | sgRenderTarget.multiViewCount = multiViewCount(); |
655 | } else { |
656 | sgRenderTarget = QSGRenderTarget(redirect.rt.sw.paintDevice); |
657 | } |
658 | |
659 | context->beginNextFrame(renderer, |
660 | renderTarget: sgRenderTarget, |
661 | mainPassRecordingStart: emitBeforeRenderPassRecording, |
662 | mainPassRecordingEnd: emitAfterRenderPassRecording, |
663 | callbackUserData: q); |
664 | |
665 | animationController->advance(); |
666 | emit q->beforeRendering(); |
667 | runAndClearJobs(jobs: &beforeRenderingJobs); |
668 | |
669 | const qreal devicePixelRatio = q->effectiveDevicePixelRatio(); |
670 | QSize pixelSize; |
671 | if (redirect.rt.rt.renderTarget) |
672 | pixelSize = redirect.rt.rt.renderTarget->pixelSize(); |
673 | else if (redirect.rt.sw.paintDevice) |
674 | pixelSize = QSize(redirect.rt.sw.paintDevice->width(), redirect.rt.sw.paintDevice->height()); |
675 | else if (rhi) |
676 | pixelSize = swapchain->currentPixelSize(); |
677 | else // software or other backend |
678 | pixelSize = q->size() * devicePixelRatio; |
679 | |
680 | renderer->setDevicePixelRatio(devicePixelRatio); |
681 | renderer->setDeviceRect(QRect(QPoint(0, 0), pixelSize)); |
682 | renderer->setViewportRect(QRect(QPoint(0, 0), pixelSize)); |
683 | |
684 | QSGAbstractRenderer::MatrixTransformFlags matrixFlags; |
685 | bool flipY = rhi ? !rhi->isYUpInNDC() : false; |
686 | if (!customRenderTarget.isNull() && customRenderTarget.mirrorVertically()) |
687 | flipY = !flipY; |
688 | if (flipY) |
689 | matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY; |
690 | |
691 | const QRectF rect(QPointF(0, 0), pixelSize / devicePixelRatio); |
692 | renderer->setProjectionMatrixToRect(rect, flags: matrixFlags, nativeNDCFlipY: rhi && !rhi->isYUpInNDC()); |
693 | |
694 | context->renderNextFrame(renderer); |
695 | |
696 | emit q->afterRendering(); |
697 | runAndClearJobs(jobs: &afterRenderingJobs); |
698 | |
699 | context->endNextFrame(renderer); |
700 | |
701 | if (renderer && renderer->hasVisualizationModeWithContinuousUpdate()) { |
702 | // For the overdraw visualizer. This update is not urgent so avoid a |
703 | // direct update() call, this is only here to keep the overdraw |
704 | // visualization box rotating even when the scene is static. |
705 | QCoreApplication::postEvent(receiver: q, event: new QEvent(QEvent::Type(FullUpdateRequest))); |
706 | } |
707 | } |
708 | |
709 | QQuickWindowPrivate::QQuickWindowPrivate() |
710 | : contentItem(nullptr) |
711 | , dirtyItemList(nullptr) |
712 | , lastReportedItemDevicePixelRatio(0) |
713 | , context(nullptr) |
714 | , renderer(nullptr) |
715 | , windowManager(nullptr) |
716 | , renderControl(nullptr) |
717 | , clearColor(Qt::white) |
718 | , persistentGraphics(true) |
719 | , persistentSceneGraph(true) |
720 | , inDestructor(false) |
721 | , incubationController(nullptr) |
722 | , hasActiveSwapchain(false) |
723 | , hasRenderableSwapchain(false) |
724 | , swapchainJustBecameRenderable(false) |
725 | , updatesEnabled(true) |
726 | { |
727 | } |
728 | |
729 | QQuickWindowPrivate::~QQuickWindowPrivate() |
730 | { |
731 | inDestructor = true; |
732 | redirect.rt.reset(rhi); |
733 | if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>()) |
734 | service->removeWindow(q_func()); |
735 | deliveryAgent = nullptr; |
736 | } |
737 | |
738 | void QQuickWindowPrivate::setPalette(QQuickPalette* palette) |
739 | { |
740 | if (windowPaletteRef == palette) |
741 | return; |
742 | |
743 | if (windowPaletteRef) |
744 | disconnect(sender: windowPaletteRef, signal: &QQuickPalette::changed, receiverPrivate: this, slot: &QQuickWindowPrivate::updateWindowPalette); |
745 | windowPaletteRef = palette; |
746 | updateWindowPalette(); |
747 | if (windowPaletteRef) |
748 | connect(sender: windowPaletteRef, signal: &QQuickPalette::changed, receiverPrivate: this, slot: &QQuickWindowPrivate::updateWindowPalette); |
749 | } |
750 | |
751 | void QQuickWindowPrivate::updateWindowPalette() |
752 | { |
753 | QQuickPaletteProviderPrivateBase::setPalette(windowPaletteRef); |
754 | } |
755 | |
756 | void QQuickWindowPrivate::updateChildrenPalettes(const QPalette &parentPalette) |
757 | { |
758 | Q_Q(QQuickWindow); |
759 | if (auto root = q->contentItem()) { |
760 | for (auto &&child: root->childItems()) { |
761 | QQuickItemPrivate::get(item: child)->inheritPalette(parentPalette); |
762 | } |
763 | } |
764 | } |
765 | |
766 | void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control) |
767 | { |
768 | q_ptr = c; |
769 | |
770 | |
771 | Q_Q(QQuickWindow); |
772 | |
773 | contentItem = new QQuickRootItem; |
774 | contentItem->setObjectName(q->objectName()); |
775 | QQml_setParent_noEvent(object: contentItem, parent: c); |
776 | QQmlEngine::setObjectOwnership(contentItem, QQmlEngine::CppOwnership); |
777 | QQuickItemPrivate *contentItemPrivate = QQuickItemPrivate::get(item: contentItem); |
778 | contentItemPrivate->window = q; |
779 | contentItemPrivate->windowRefCount = 1; |
780 | contentItemPrivate->flags |= QQuickItem::ItemIsFocusScope; |
781 | contentItem->setSize(q->size()); |
782 | deliveryAgent = new QQuickDeliveryAgent(contentItem); |
783 | |
784 | visualizationMode = qgetenv(varName: "QSG_VISUALIZE"); |
785 | renderControl = control; |
786 | if (renderControl) |
787 | QQuickRenderControlPrivate::get(renderControl)->window = q; |
788 | |
789 | if (!renderControl) |
790 | windowManager = QSGRenderLoop::instance(); |
791 | |
792 | Q_ASSERT(windowManager || renderControl); |
793 | |
794 | QObject::connect(sender: static_cast<QGuiApplication *>(QGuiApplication::instance()), |
795 | signal: &QGuiApplication::fontDatabaseChanged, |
796 | context: q, |
797 | slot: &QQuickWindow::handleFontDatabaseChanged); |
798 | |
799 | if (q->screen()) { |
800 | lastReportedItemDevicePixelRatio = q->effectiveDevicePixelRatio(); |
801 | } |
802 | |
803 | QSGContext *sg; |
804 | if (renderControl) { |
805 | QQuickRenderControlPrivate *renderControlPriv = QQuickRenderControlPrivate::get(renderControl); |
806 | sg = renderControlPriv->sg; |
807 | context = renderControlPriv->rc; |
808 | } else { |
809 | windowManager->addWindow(win: q); |
810 | sg = windowManager->sceneGraphContext(); |
811 | context = windowManager->createRenderContext(sg); |
812 | } |
813 | |
814 | q->setSurfaceType(windowManager ? windowManager->windowSurfaceType() : QSurface::OpenGLSurface); |
815 | q->setFormat(sg->defaultSurfaceFormat()); |
816 | // When using Vulkan, associating a scenegraph-managed QVulkanInstance with |
817 | // the window (but only when not using renderControl) is deferred to |
818 | // QSGRhiSupport::createRhi(). This allows applications to set up their own |
819 | // QVulkanInstance and set that on the window, if they wish to. |
820 | |
821 | animationController.reset(other: new QQuickAnimatorController(q)); |
822 | |
823 | QObject::connect(sender: context, signal: &QSGRenderContext::initialized, context: q, slot: &QQuickWindow::sceneGraphInitialized, type: Qt::DirectConnection); |
824 | QObject::connect(sender: context, signal: &QSGRenderContext::invalidated, context: q, slot: &QQuickWindow::sceneGraphInvalidated, type: Qt::DirectConnection); |
825 | QObject::connect(sender: context, signal: &QSGRenderContext::invalidated, context: q, slot: &QQuickWindow::cleanupSceneGraph, type: Qt::DirectConnection); |
826 | |
827 | QObject::connect(sender: q, signal: &QQuickWindow::focusObjectChanged, context: q, slot: &QQuickWindow::activeFocusItemChanged); |
828 | QObject::connect(sender: q, signal: &QQuickWindow::screenChanged, context: q, slot: &QQuickWindow::handleScreenChanged); |
829 | QObject::connect(qApp, signal: &QGuiApplication::applicationStateChanged, context: q, slot: &QQuickWindow::handleApplicationStateChanged); |
830 | QObject::connect(sender: q, signal: &QQuickWindow::frameSwapped, context: q, slot: &QQuickWindow::runJobsAfterSwap, type: Qt::DirectConnection); |
831 | |
832 | if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>()) |
833 | service->addWindow(q); |
834 | } |
835 | |
836 | void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state) |
837 | { |
838 | Q_D(QQuickWindow); |
839 | if (state != Qt::ApplicationActive && d->contentItem) { |
840 | auto da = d->deliveryAgentPrivate(); |
841 | Q_ASSERT(da); |
842 | da->handleWindowDeactivate(win: this); |
843 | } |
844 | } |
845 | |
846 | /*! |
847 | \property QQuickWindow::data |
848 | \internal |
849 | */ |
850 | |
851 | QQmlListProperty<QObject> QQuickWindowPrivate::data() |
852 | { |
853 | QQmlListProperty<QObject> ret; |
854 | |
855 | ret.object = q_func(); |
856 | ret.append = QQuickWindowPrivate::data_append; |
857 | ret.count = QQuickWindowPrivate::data_count; |
858 | ret.at = QQuickWindowPrivate::data_at; |
859 | ret.clear = QQuickWindowPrivate::data_clear; |
860 | // replace is not supported by QQuickItem. Don't synthesize it. |
861 | ret.removeLast = QQuickWindowPrivate::data_removeLast; |
862 | |
863 | return ret; |
864 | } |
865 | |
866 | void QQuickWindowPrivate::dirtyItem(QQuickItem *item) |
867 | { |
868 | Q_Q(QQuickWindow); |
869 | |
870 | QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); |
871 | if (itemPriv->dirtyAttributes & QQuickItemPrivate::ChildrenStackingChanged) |
872 | needsChildWindowStackingOrderUpdate = true; |
873 | |
874 | q->maybeUpdate(); |
875 | } |
876 | |
877 | /*! |
878 | \deprecated Use QPointerEvent::exclusiveGrabber(). |
879 | Returns the item which currently has the mouse grab. |
880 | */ |
881 | QQuickItem *QQuickWindow::mouseGrabberItem() const |
882 | { |
883 | Q_D(const QQuickWindow); |
884 | auto da = const_cast<QQuickWindowPrivate *>(d)->deliveryAgentPrivate(); |
885 | Q_ASSERT(da); |
886 | // The normal use case is to call this function while an event is being delivered; |
887 | // but if the caller knows about the event, it should call QPointerEvent::exclusiveGrabber() instead. |
888 | if (auto epd = da->mousePointData()) |
889 | return qmlobject_cast<QQuickItem *>(object: epd->exclusiveGrabber); |
890 | |
891 | if (Q_LIKELY(d->deliveryAgentPrivate()->eventsInDelivery.isEmpty())) |
892 | // mousePointData() checked that already: it's one reason epd can be null |
893 | qCDebug(lcMouse, "mouse grabber ambiguous: no event is currently being delivered"); |
894 | // If no event is being delivered, we can return "the mouse" grabber, |
895 | // but in general there could be more than one mouse, could be only a touchscreen etc. |
896 | // That's why this function is obsolete. |
897 | return qmlobject_cast<QQuickItem *>(object: QPointingDevicePrivate::get(q: QPointingDevice::primaryPointingDevice())-> |
898 | firstPointExclusiveGrabber()); |
899 | } |
900 | |
901 | void QQuickWindowPrivate::cleanup(QSGNode *n) |
902 | { |
903 | Q_Q(QQuickWindow); |
904 | |
905 | Q_ASSERT(!cleanupNodeList.contains(n)); |
906 | cleanupNodeList.append(t: n); |
907 | q->maybeUpdate(); |
908 | } |
909 | |
910 | /*! |
911 | \qmltype Window |
912 | \nativetype QQuickWindow |
913 | \inqmlmodule QtQuick |
914 | \ingroup qtquick-visual |
915 | \brief Creates a new top-level window. |
916 | |
917 | The Window object creates a new top-level window for a Qt Quick scene. It automatically sets up the |
918 | window for use with \c {QtQuick} graphical types. |
919 | |
920 | A Window can be declared inside an Item or inside another Window, in which |
921 | case the inner Window will automatically become "transient for" the outer |
922 | Window, with the outer Window as its \l transientParent. Most platforms will |
923 | show the Window centered upon the outer window in this case, and there may be |
924 | other platform-dependent behaviors, depending also on the \l flags. If the nested |
925 | window is intended to be a dialog in your application, you should also set \l flags |
926 | to \c Qt.Dialog, because some window managers will not provide the centering behavior |
927 | without that flag. |
928 | |
929 | You can also declare multiple windows inside a top-level \l QtObject, in which |
930 | case the windows will have no transient relationship. |
931 | |
932 | Alternatively you can set or bind \l x and \l y to position the Window |
933 | explicitly on the screen. |
934 | |
935 | When the user attempts to close a window, the \l closing signal will be |
936 | emitted. You can force the window to stay open (for example to prompt the |
937 | user to save changes) by writing an \c onClosing handler that sets |
938 | \c {close.accepted = false} unless it's safe to close the window (for example, |
939 | because there are no more unsaved changes). |
940 | |
941 | \code |
942 | onClosing: (close) => { |
943 | if (document.changed) { |
944 | close.accepted = false |
945 | confirmExitPopup.open() |
946 | } |
947 | } |
948 | |
949 | // The confirmExitPopup allows user to save or discard the document, |
950 | // or to cancel the closing. |
951 | \endcode |
952 | |
953 | \section1 Styling |
954 | |
955 | As with all visual types in Qt Quick, Window supports |
956 | \l {palette}{palettes}. However, as with types like \l Text, Window does |
957 | not use palettes by default. For example, to change the background color |
958 | of the window when the operating system's theme changes, the \l color must |
959 | be set: |
960 | |
961 | \snippet qml/windowPalette.qml declaration-and-color |
962 | \codeline |
963 | \snippet qml/windowPalette.qml text-item |
964 | \snippet qml/windowPalette.qml closing-brace |
965 | |
966 | Use \l {ApplicationWindow} (and \l {Label}) from \l {Qt Quick Controls} |
967 | instead of Window to get automatic styling. |
968 | */ |
969 | |
970 | /*! |
971 | \class QQuickWindow |
972 | \since 5.0 |
973 | |
974 | \inmodule QtQuick |
975 | |
976 | \brief The QQuickWindow class provides the window for displaying a graphical QML scene. |
977 | |
978 | QQuickWindow provides the graphical scene management needed to interact with and display |
979 | a scene of QQuickItems. |
980 | |
981 | A QQuickWindow always has a single invisible root item. To add items to this window, |
982 | reparent the items to the root item or to an existing item in the scene. |
983 | |
984 | For easily displaying a scene from a QML file, see \l{QQuickView}. |
985 | |
986 | \section1 Rendering |
987 | |
988 | QQuickWindow uses a scene graph to represent what needs to be rendered. |
989 | This scene graph is disconnected from the QML scene and potentially lives in |
990 | another thread, depending on the platform implementation. Since the |
991 | rendering scene graph lives independently from the QML scene, it can also be |
992 | completely released without affecting the state of the QML scene. |
993 | |
994 | The sceneGraphInitialized() signal is emitted on the rendering thread before |
995 | the QML scene is rendered to the screen for the first time. If the rendering |
996 | scene graph has been released, the signal will be emitted again before the |
997 | next frame is rendered. A visible, on-screen QQuickWindow is driven |
998 | internally by a \c{render loop}, of which there are multiple implementations |
999 | provided in the scene graph. For details on the scene graph rendering |
1000 | process, see \l{Qt Quick Scene Graph}. |
1001 | |
1002 | By default, a QQuickWindow renders using an accelerated 3D graphics API, |
1003 | such as OpenGL or Vulkan. See \l{Scene Graph Adaptations} for a detailed |
1004 | overview of scene graph backends and the supported graphics APIs. |
1005 | |
1006 | \warning It is crucial that graphics operations and interaction with the |
1007 | scene graph happens exclusively on the rendering thread, primarily during |
1008 | the updatePaintNode() phase. |
1009 | |
1010 | \warning As many of the signals related to rendering are emitted from the |
1011 | rendering thread, connections should be made using Qt::DirectConnection. |
1012 | |
1013 | \section2 Integration with Accelerated 3D Graphics APIs |
1014 | |
1015 | It is possible to integrate OpenGL, Vulkan, Metal, or Direct3D 11 calls |
1016 | directly into the QQuickWindow, as long as the QQuickWindow and the |
1017 | underlying scene graph is rendering using the same API. To access native |
1018 | graphics objects, such as device or context object handles, use |
1019 | QSGRendererInterface. An instance of QSGRendererInterface is queriable from |
1020 | QQuickWindow by calling rendererInterface(). The enablers for this |
1021 | integration are the beforeRendering(), beforeRenderPassRecording(), |
1022 | afterRenderPassRecording(), and related signals. These allow rendering |
1023 | underlays or overlays. Alternatively, QNativeInterface::QSGOpenGLTexture, |
1024 | QNativeInterface::QSGVulkanTexture, and other similar classes allow |
1025 | wrapping an existing native texture or image object in a QSGTexture that |
1026 | can then be used with the scene graph. |
1027 | |
1028 | \section2 Rendering without Acceleration |
1029 | |
1030 | A limited, pure software based rendering path is available as well. With the |
1031 | \c software backend, a number of Qt Quick features are not available, QML |
1032 | items relying on these will not be rendered at all. At the same time, this |
1033 | allows QQuickWindow to be functional even on systems where there is no 3D |
1034 | graphics API available at all. See \l{Qt Quick Software Adaptation} for more |
1035 | details. |
1036 | |
1037 | \section2 Redirected Rendering |
1038 | |
1039 | A QQuickWindow is not necessarily backed by a native window on screen. The |
1040 | rendering can be redirected to target a custom render target, such as a |
1041 | given native texture. This is achieved in combination with the |
1042 | QQuickRenderControl class, and functions such as setRenderTarget(), |
1043 | setGraphicsDevice(), and setGraphicsConfiguration(). |
1044 | |
1045 | In this case, the QQuickWindow represents the scene, and provides the |
1046 | intrastructure for rendering a frame. It will not be backed by a render |
1047 | loop and a native window. Instead, in this case the application drives |
1048 | rendering, effectively substituting for the render loops. This allows |
1049 | generating image sequences, rendering into textures for use in external 3D |
1050 | engines, or rendering Qt Quick content within a VR environment. |
1051 | |
1052 | \section2 Resource Management |
1053 | |
1054 | QML will try to cache images and scene graph nodes to improve performance, |
1055 | but in some low-memory scenarios it might be required to aggressively |
1056 | release these resources. The releaseResources() function can be used to |
1057 | force the clean up of certain resources, especially resource that are cached |
1058 | and can be recreated later when needed again. |
1059 | |
1060 | Additionally, calling releaseResources() may result in releasing the entire |
1061 | scene graph and the associated graphics resources. The |
1062 | sceneGraphInvalidated() signal will be emitted when this happens. This |
1063 | behavior is controlled by the setPersistentGraphics() and |
1064 | setPersistentSceneGraph() functions. |
1065 | |
1066 | \note All classes with QSG prefix should be used solely on the scene graph's |
1067 | rendering thread. See \l {Scene Graph and Rendering} for more information. |
1068 | |
1069 | \section2 Exposure and Visibility |
1070 | |
1071 | When a QQuickWindow instance is deliberately hidden with hide() or |
1072 | setVisible(false), it will stop rendering and its scene graph and graphics |
1073 | context might be released as well. This depends on the settings configured |
1074 | by setPersistentGraphics() and setPersistentSceneGraph(). The behavior in |
1075 | this respect is identical to explicitly calling the releaseResources() |
1076 | function. A window can become not exposed, in other words non-renderable, by |
1077 | other means as well. This depends on the platform and windowing system. For |
1078 | example, on Windows minimizing a window makes it stop rendering. On \macos |
1079 | fully obscuring a window by other windows on top triggers the same. On |
1080 | Linux/X11, the behavior is dependent on the window manager. |
1081 | |
1082 | \section2 OpenGL Context and Surface Formats |
1083 | |
1084 | While it is possible to specify a QSurfaceFormat for every QQuickWindow by |
1085 | calling the member function setFormat(), windows may also be created from |
1086 | QML by using the Window and ApplicationWindow elements. In this case there |
1087 | is no C++ code involved in the creation of the window instance, yet |
1088 | applications may still wish to set certain surface format values, for |
1089 | example to request a given OpenGL version or profile. Such applications can |
1090 | call the static function QSurfaceFormat::setDefaultFormat() at startup. The |
1091 | specified format will be used for all Quick windows created afterwards. |
1092 | |
1093 | \section2 Vulkan Instance |
1094 | |
1095 | When using Vulkan, a QQuickWindow is automatically associated with a |
1096 | QVulkanInstance that is created and managed internally by the scene graph. |
1097 | This way most applications do not need to worry about having a \c |
1098 | VkInstance available since it all happens automatically. In advanced cases |
1099 | an application may wish to create its own QVulkanInstance, in order to |
1100 | configure it in a specific way. That is possible as well. Calling |
1101 | \l{QWindow::setVulkanInstance()}{setVulkanInstance()} on the QQuickWindow |
1102 | right after construction, before making it visible, leads to using the |
1103 | application-supplied QVulkanInstance (and the underlying \c VkInstance). |
1104 | When redirecting via QQuickRenderControl, there is no QVulkanInstance |
1105 | provided automatically, but rather the application is expected to provide |
1106 | its own and associate it with the QQuickWindow. |
1107 | |
1108 | \section2 Graphics Contexts and Devices |
1109 | |
1110 | When the scene graph is initialized, which typically happens when the |
1111 | window becomes exposed or, in case of redirected rendering, initialization |
1112 | is performed \l{QQuickRenderControl::initialize()}{via |
1113 | QQuickRenderControl}, the context or device objects necessary for rendering |
1114 | are created automatically. This includes OpenGL contexts, Direct3D devices |
1115 | and device contexts, Vulkan and Metal devices. These are also queriable by |
1116 | application code afterwards via |
1117 | \l{QSGRendererInterface::getResource()}{QSGRendererInterface}. When using |
1118 | the \c basic render loop, which performs all rendering on the GUI thread, |
1119 | the same context or device is used with all visible QQuickWindows. The \c |
1120 | threaded render loop uses a dedicated context or device object for each |
1121 | rendering thread, and so for each QQuickWindow. With some graphics APIs, |
1122 | there is a degree of customizability provided via |
1123 | setGraphicsConfiguration(). This makes it possible, for example, to specify |
1124 | the list of Vulkan extensions to enable on the \c VkDevice. Alternatively, |
1125 | it is also possible to provide a set of existing context or device objects |
1126 | for use by the QQuickWindow, instead of letting it construct its own. This |
1127 | is achieved through setGraphicsDevice(). |
1128 | |
1129 | \sa QQuickView, QQuickRenderControl, QQuickRenderTarget, |
1130 | QQuickGraphicsDevice, QQuickGraphicsConfiguration, QSGRendererInterface |
1131 | */ |
1132 | |
1133 | /*! |
1134 | Constructs a window for displaying a QML scene with parent window \a parent. |
1135 | */ |
1136 | QQuickWindow::QQuickWindow(QWindow *parent) |
1137 | : QQuickWindow(*new QQuickWindowPrivate, parent) |
1138 | { |
1139 | } |
1140 | |
1141 | |
1142 | |
1143 | /*! |
1144 | \internal |
1145 | */ |
1146 | QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent) |
1147 | : QWindow(dd, parent) |
1148 | { |
1149 | Q_D(QQuickWindow); |
1150 | d->init(c: this); |
1151 | } |
1152 | |
1153 | /*! |
1154 | Constructs a window for displaying a QML scene, whose rendering will |
1155 | be controlled by the \a control object. |
1156 | Please refer to QQuickRenderControl's documentation for more information. |
1157 | |
1158 | \since 5.4 |
1159 | */ |
1160 | QQuickWindow::QQuickWindow(QQuickRenderControl *control) |
1161 | : QWindow(*(new QQuickWindowPrivate), nullptr) |
1162 | { |
1163 | Q_D(QQuickWindow); |
1164 | d->init(c: this, control); |
1165 | } |
1166 | |
1167 | /*! |
1168 | \internal |
1169 | */ |
1170 | QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control) |
1171 | : QWindow(dd, nullptr) |
1172 | { |
1173 | Q_D(QQuickWindow); |
1174 | d->init(c: this, control); |
1175 | } |
1176 | |
1177 | /*! |
1178 | Destroys the window. |
1179 | */ |
1180 | QQuickWindow::~QQuickWindow() |
1181 | { |
1182 | Q_D(QQuickWindow); |
1183 | d->inDestructor = true; |
1184 | if (d->renderControl) { |
1185 | QQuickRenderControlPrivate::get(renderControl: d->renderControl)->windowDestroyed(); |
1186 | } else if (d->windowManager) { |
1187 | d->windowManager->removeWindow(win: this); |
1188 | d->windowManager->windowDestroyed(window: this); |
1189 | } |
1190 | |
1191 | delete d->incubationController; d->incubationController = nullptr; |
1192 | QQuickRootItem *root = d->contentItem; |
1193 | d->contentItem = nullptr; |
1194 | root->setParent(nullptr); // avoid QChildEvent delivery during deletion |
1195 | delete root; |
1196 | d->deliveryAgent = nullptr; // avoid forwarding events there during destruction |
1197 | |
1198 | |
1199 | { |
1200 | const std::lock_guard locker(d->renderJobMutex); |
1201 | qDeleteAll(c: std::exchange(obj&: d->beforeSynchronizingJobs, new_val: {})); |
1202 | qDeleteAll(c: std::exchange(obj&: d->afterSynchronizingJobs, new_val: {})); |
1203 | qDeleteAll(c: std::exchange(obj&: d->beforeRenderingJobs, new_val: {})); |
1204 | qDeleteAll(c: std::exchange(obj&: d->afterRenderingJobs, new_val: {}));; |
1205 | qDeleteAll(c: std::exchange(obj&: d->afterSwapJobs, new_val: {})); |
1206 | } |
1207 | |
1208 | // It is important that the pixmap cache is cleaned up during shutdown. |
1209 | // Besides playing nice, this also solves a practical problem that |
1210 | // QQuickTextureFactory implementations in other libraries need |
1211 | // have their destructors loaded while they the library is still |
1212 | // loaded into memory. |
1213 | QQuickPixmap::purgeCache(); |
1214 | } |
1215 | |
1216 | #if QT_CONFIG(quick_shadereffect) |
1217 | void qtquick_shadereffect_purge_gui_thread_shader_cache(); |
1218 | #endif |
1219 | |
1220 | /*! |
1221 | This function tries to release redundant resources currently held by the QML scene. |
1222 | |
1223 | Calling this function requests the scene graph to release cached graphics |
1224 | resources, such as graphics pipeline objects, shader programs, or image |
1225 | data. |
1226 | |
1227 | Additionally, depending on the render loop in use, this function may also |
1228 | result in the scene graph and all window-related rendering resources to be |
1229 | released. If this happens, the sceneGraphInvalidated() signal will be |
1230 | emitted, allowing users to clean up their own graphics resources. The |
1231 | setPersistentGraphics() and setPersistentSceneGraph() functions can be used |
1232 | to prevent this from happening, if handling the cleanup is not feasible in |
1233 | the application, at the cost of higher memory usage. |
1234 | |
1235 | \note The releasing of cached graphics resources, such as graphics |
1236 | pipelines or shader programs is not dependent on the persistency hints. The |
1237 | releasing of those will happen regardless of the values of the persistent |
1238 | graphics and scenegraph hints. |
1239 | |
1240 | \note This function is not related to the QQuickItem::releaseResources() |
1241 | virtual function. |
1242 | |
1243 | \sa sceneGraphInvalidated(), setPersistentGraphics(), setPersistentSceneGraph() |
1244 | */ |
1245 | |
1246 | void QQuickWindow::releaseResources() |
1247 | { |
1248 | Q_D(QQuickWindow); |
1249 | if (d->windowManager) |
1250 | d->windowManager->releaseResources(window: this); |
1251 | QQuickPixmap::purgeCache(); |
1252 | #if QT_CONFIG(quick_shadereffect) |
1253 | qtquick_shadereffect_purge_gui_thread_shader_cache(); |
1254 | #endif |
1255 | } |
1256 | |
1257 | |
1258 | |
1259 | /*! |
1260 | Sets whether the graphics resources (graphics device or context, |
1261 | swapchain, buffers, textures) should be preserved, and cannot be |
1262 | released until the last window is deleted, to \a persistent. The |
1263 | default value is true. |
1264 | |
1265 | When calling releaseResources(), or when the window gets hidden (more |
1266 | specifically, not renderable), some render loops have the possibility |
1267 | to release all, not just the cached, graphics resources. This can free |
1268 | up memory temporarily, but it also means the rendering engine will have |
1269 | to do a full, potentially costly reinitialization of the resources when |
1270 | the window needs to render again. |
1271 | |
1272 | \note The rules for when a window is not renderable are platform and |
1273 | window manager specific. |
1274 | |
1275 | \note All graphics resources are released when the last QQuickWindow is |
1276 | deleted, regardless of this setting. |
1277 | |
1278 | \note This is a hint, and is not guaranteed that it is taken into account. |
1279 | |
1280 | \note This hint does not apply to cached resources, that are relatively |
1281 | cheap to drop and then recreate later. Therefore, calling releaseResources() |
1282 | will typically lead to releasing those regardless of the value of this hint. |
1283 | |
1284 | \sa setPersistentSceneGraph(), sceneGraphInitialized(), sceneGraphInvalidated(), releaseResources() |
1285 | */ |
1286 | |
1287 | void QQuickWindow::setPersistentGraphics(bool persistent) |
1288 | { |
1289 | Q_D(QQuickWindow); |
1290 | d->persistentGraphics = persistent; |
1291 | } |
1292 | |
1293 | |
1294 | |
1295 | /*! |
1296 | Returns whether essential graphics resources can be released during the |
1297 | lifetime of the QQuickWindow. |
1298 | |
1299 | \note This is a hint, and is not guaranteed that it is taken into account. |
1300 | |
1301 | \sa setPersistentGraphics() |
1302 | */ |
1303 | |
1304 | bool QQuickWindow::isPersistentGraphics() const |
1305 | { |
1306 | Q_D(const QQuickWindow); |
1307 | return d->persistentGraphics; |
1308 | } |
1309 | |
1310 | |
1311 | |
1312 | /*! |
1313 | Sets whether the scene graph nodes and resources are \a persistent. |
1314 | Persistent means the nodes and resources cannot be released. |
1315 | The default value is \c true. |
1316 | |
1317 | When calling releaseResources(), when the window gets hidden (more |
1318 | specifically, not renderable), some render loops have the possibility |
1319 | to release the scene graph nodes and related graphics resources. This |
1320 | frees up memory temporarily, but will also mean the scene graph has to |
1321 | be rebuilt when the window renders next time. |
1322 | |
1323 | \note The rules for when a window is not renderable are platform and |
1324 | window manager specific. |
1325 | |
1326 | \note The scene graph nodes and resources are always released when the |
1327 | last QQuickWindow is deleted, regardless of this setting. |
1328 | |
1329 | \note This is a hint, and is not guaranteed that it is taken into account. |
1330 | |
1331 | \sa setPersistentGraphics(), sceneGraphInvalidated(), sceneGraphInitialized(), releaseResources() |
1332 | */ |
1333 | |
1334 | void QQuickWindow::setPersistentSceneGraph(bool persistent) |
1335 | { |
1336 | Q_D(QQuickWindow); |
1337 | d->persistentSceneGraph = persistent; |
1338 | } |
1339 | |
1340 | |
1341 | |
1342 | /*! |
1343 | Returns whether the scene graph nodes and resources can be |
1344 | released during the lifetime of this QQuickWindow. |
1345 | |
1346 | \note This is a hint. When and how this happens is implementation |
1347 | specific. |
1348 | */ |
1349 | |
1350 | bool QQuickWindow::isPersistentSceneGraph() const |
1351 | { |
1352 | Q_D(const QQuickWindow); |
1353 | return d->persistentSceneGraph; |
1354 | } |
1355 | |
1356 | /*! |
1357 | \qmlattachedproperty Item Window::contentItem |
1358 | \since 5.4 |
1359 | |
1360 | This attached property holds the invisible root item of the scene or |
1361 | \c null if the item is not in a window. The Window attached property |
1362 | can be attached to any Item. |
1363 | */ |
1364 | |
1365 | /*! |
1366 | \property QQuickWindow::contentItem |
1367 | \brief The invisible root item of the scene. |
1368 | |
1369 | A QQuickWindow always has a single invisible root item containing all of its content. |
1370 | To add items to this window, reparent the items to the contentItem or to an existing |
1371 | item in the scene. |
1372 | */ |
1373 | QQuickItem *QQuickWindow::contentItem() const |
1374 | { |
1375 | Q_D(const QQuickWindow); |
1376 | |
1377 | return d->contentItem; |
1378 | } |
1379 | |
1380 | /*! |
1381 | \property QQuickWindow::activeFocusItem |
1382 | |
1383 | \brief The item which currently has active focus or \c null if there is |
1384 | no item with active focus. |
1385 | |
1386 | \sa QQuickItem::forceActiveFocus(), {Keyboard Focus in Qt Quick} |
1387 | */ |
1388 | QQuickItem *QQuickWindow::activeFocusItem() const |
1389 | { |
1390 | Q_D(const QQuickWindow); |
1391 | auto da = d->deliveryAgentPrivate(); |
1392 | Q_ASSERT(da); |
1393 | return da->activeFocusItem; |
1394 | } |
1395 | |
1396 | /*! |
1397 | \internal |
1398 | \reimp |
1399 | */ |
1400 | QObject *QQuickWindow::focusObject() const |
1401 | { |
1402 | Q_D(const QQuickWindow); |
1403 | auto da = d->deliveryAgentPrivate(); |
1404 | Q_ASSERT(da); |
1405 | if (!d->inDestructor && da->activeFocusItem) |
1406 | return da->activeFocusItem; |
1407 | return const_cast<QQuickWindow*>(this); |
1408 | } |
1409 | |
1410 | /*! \reimp */ |
1411 | bool QQuickWindow::event(QEvent *event) |
1412 | { |
1413 | Q_D(QQuickWindow); |
1414 | |
1415 | // bypass QWindow::event dispatching of input events: deliveryAgent takes care of it |
1416 | QQuickDeliveryAgent *da = d->deliveryAgent; |
1417 | if (event->isPointerEvent()) { |
1418 | /* |
1419 | We can't bypass the virtual functions like mousePressEvent() tabletEvent() etc., |
1420 | for the sake of code that subclasses QQuickWindow and overrides them, even though |
1421 | we no longer need them as entry points for Qt Quick event delivery. |
1422 | So dispatch to them now, ahead of normal delivery, and stop them from calling |
1423 | back into this function if they were called from here (avoid recursion). |
1424 | It could also be that user code expects them to work as entry points, too; |
1425 | in that case, windowEventDispatch _won't_ be set, so the event comes here and |
1426 | we'll dispatch it further below. |
1427 | */ |
1428 | if (d->windowEventDispatch) |
1429 | return false; |
1430 | { |
1431 | const bool wasAccepted = event->isAccepted(); |
1432 | QBoolBlocker windowEventDispatchGuard(d->windowEventDispatch, true); |
1433 | qCDebug(lcPtr) << "dispatching to window functions in case of override"<< event; |
1434 | QWindow::event(event); |
1435 | if (event->isAccepted() && !wasAccepted) |
1436 | return true; |
1437 | } |
1438 | /* |
1439 | QQuickWindow does not override touchEvent(). If the application has a subclass |
1440 | of QQuickWindow which allows the event to remain accepted, it means they want |
1441 | to stop propagation here, so return early (below). But otherwise we will call |
1442 | QWindow::touchEvent(), which will ignore(); in that case, we need to continue |
1443 | with the usual delivery below, so we need to undo the ignore(). |
1444 | */ |
1445 | auto pe = static_cast<QPointerEvent *>(event); |
1446 | if (QQuickDeliveryAgentPrivate::isTouchEvent(ev: pe)) |
1447 | event->accept(); |
1448 | // end of dispatch to user-overridden virtual window functions |
1449 | |
1450 | /* |
1451 | When delivering update and release events to existing grabbers, |
1452 | use the subscene delivery agent, if any. A possible scenario: |
1453 | 1) Two touchpoints pressed on the main window: QQuickWindowPrivate::deliveryAgent delivers to QQuick3DViewport, |
1454 | which does picking and finds two subscenes ("root" Items mapped onto two different 3D objects) to deliver it to. |
1455 | 2) The QTouchEvent is split up so that each subscene sees points relevant to it. |
1456 | 3) During delivery to either subscene, an item in the subscene grabs. |
1457 | 4) The user moves finger(s) generating a move event: the correct grabber item needs to get the update |
1458 | via the same subscene delivery agent from which it got the press, so that the coord transform will be done properly. |
1459 | 5) Likewise with the touchpoint releases. |
1460 | With single-point events (mouse, or only one finger) it's simplified: there can only be one subscene of interest; |
1461 | for (pt : pe->points()) would only iterate once, so we might as well skip that logic. |
1462 | */ |
1463 | if (pe->pointCount()) { |
1464 | const bool synthMouse = QQuickDeliveryAgentPrivate::isSynthMouse(ev: pe); |
1465 | if (QQuickDeliveryAgentPrivate::subsceneAgentsExist) { |
1466 | bool ret = false; |
1467 | // Split up the multi-point event according to the relevant QQuickDeliveryAgent that should deliver to each existing grabber |
1468 | // but send ungrabbed points to d->deliveryAgent() |
1469 | QFlatMap<QQuickDeliveryAgent*, QList<QEventPoint>> deliveryAgentsNeedingPoints; |
1470 | QEventPoint::States eventStates; |
1471 | |
1472 | auto insert = [&](QQuickDeliveryAgent *ptda, const QEventPoint &pt) { |
1473 | if (pt.state() == QEventPoint::Pressed && !synthMouse) |
1474 | pe->clearPassiveGrabbers(point: pt); |
1475 | auto &ptList = deliveryAgentsNeedingPoints[ptda]; |
1476 | auto idEquals = [](auto id) { return [id] (const auto &e) { return e.id() == id; }; }; |
1477 | if (std::none_of(first: ptList.cbegin(), last: ptList.cend(), pred: idEquals(pt.id()))) |
1478 | ptList.append(t: pt); |
1479 | }; |
1480 | |
1481 | for (const auto &pt : pe->points()) { |
1482 | eventStates |= pt.state(); |
1483 | auto epd = QPointingDevicePrivate::get(q: const_cast<QPointingDevice*>(pe->pointingDevice()))->queryPointById(id: pt.id()); |
1484 | Q_ASSERT(epd); |
1485 | bool foundAgent = false; |
1486 | if (!epd->exclusiveGrabber.isNull() && !epd->exclusiveGrabberContext.isNull()) { |
1487 | if (auto ptda = qobject_cast<QQuickDeliveryAgent *>(object: epd->exclusiveGrabberContext.data())) { |
1488 | insert(ptda, pt); |
1489 | qCDebug(lcPtr) << pe->type() << "point"<< pt.id() << pt.state() |
1490 | << "@"<< pt.scenePosition() << "will be re-delivered via known grabbing agent"<< ptda << "to"<< epd->exclusiveGrabber.data(); |
1491 | foundAgent = true; |
1492 | } |
1493 | } |
1494 | for (auto pgda : epd->passiveGrabbersContext) { |
1495 | if (auto ptda = qobject_cast<QQuickDeliveryAgent *>(object: pgda.data())) { |
1496 | insert(ptda, pt); |
1497 | qCDebug(lcPtr) << pe->type() << "point"<< pt.id() << pt.state() |
1498 | << "@"<< pt.scenePosition() << "will be re-delivered via known passive-grabbing agent"<< ptda; |
1499 | foundAgent = true; |
1500 | } |
1501 | } |
1502 | // fallback: if we didn't find remembered/known grabber agent(s), expect the root DA to handle it |
1503 | if (!foundAgent) |
1504 | insert(da, pt); |
1505 | } |
1506 | for (auto daAndPoints : deliveryAgentsNeedingPoints) { |
1507 | if (pe->pointCount() > 1) { |
1508 | Q_ASSERT(QQuickDeliveryAgentPrivate::isTouchEvent(pe)); |
1509 | // if all points have the same state, set the event type accordingly |
1510 | QEvent::Type eventType = pe->type(); |
1511 | switch (eventStates) { |
1512 | case QEventPoint::State::Pressed: |
1513 | eventType = QEvent::TouchBegin; |
1514 | break; |
1515 | case QEventPoint::State::Released: |
1516 | eventType = QEvent::TouchEnd; |
1517 | break; |
1518 | default: |
1519 | eventType = QEvent::TouchUpdate; |
1520 | break; |
1521 | } |
1522 | // Make a new touch event for the subscene, the same way QQuickItemPrivate::localizedTouchEvent() does it |
1523 | QMutableTouchEvent te(eventType, pe->pointingDevice(), pe->modifiers(), daAndPoints.second); |
1524 | te.setTimestamp(pe->timestamp()); |
1525 | te.accept(); |
1526 | qCDebug(lcTouch) << daAndPoints.first << "shall now receive"<< &te; |
1527 | ret = daAndPoints.first->event(ev: &te) || ret; |
1528 | } else { |
1529 | qCDebug(lcPtr) << daAndPoints.first << "shall now receive"<< pe; |
1530 | ret = daAndPoints.first->event(ev: pe) || ret; |
1531 | } |
1532 | } |
1533 | |
1534 | if (ret) |
1535 | return true; |
1536 | } else if (!synthMouse) { |
1537 | // clear passive grabbers unless it's a system synth-mouse event |
1538 | // QTBUG-104890: Windows sends synth mouse events (which should be ignored) after touch events |
1539 | for (const auto &pt : pe->points()) { |
1540 | if (pt.state() == QEventPoint::Pressed) |
1541 | pe->clearPassiveGrabbers(point: pt); |
1542 | } |
1543 | } |
1544 | } |
1545 | |
1546 | // If it has no points, it's probably a TouchCancel, and DeliveryAgent needs to handle it. |
1547 | // If we didn't handle it in the block above, handle it now. |
1548 | // TODO should we deliver to all DAs at once then, since we don't know which one should get it? |
1549 | // or fix QTBUG-90851 so that the event always has points? |
1550 | bool ret = (da && da->event(ev: event)); |
1551 | |
1552 | d->deliveryAgentPrivate()->clearGrabbers(pointerEvent: pe); |
1553 | |
1554 | if (ret) |
1555 | return true; |
1556 | } else if (event->isInputEvent()) { |
1557 | if (da && da->event(ev: event)) |
1558 | return true; |
1559 | } |
1560 | |
1561 | switch (event->type()) { |
1562 | // a few more types that are not QInputEvents, but QQuickDeliveryAgent needs to handle them anyway |
1563 | case QEvent::FocusAboutToChange: |
1564 | case QEvent::Enter: |
1565 | case QEvent::Leave: |
1566 | case QEvent::InputMethod: |
1567 | case QEvent::InputMethodQuery: |
1568 | #if QT_CONFIG(quick_draganddrop) |
1569 | case QEvent::DragEnter: |
1570 | case QEvent::DragLeave: |
1571 | case QEvent::DragMove: |
1572 | case QEvent::Drop: |
1573 | #endif |
1574 | if (d->inDestructor) |
1575 | return false; |
1576 | if (da && da->event(ev: event)) |
1577 | return true; |
1578 | break; |
1579 | case QEvent::LanguageChange: |
1580 | case QEvent::LocaleChange: |
1581 | if (d->contentItem) |
1582 | QCoreApplication::sendEvent(receiver: d->contentItem, event); |
1583 | break; |
1584 | case QEvent::UpdateRequest: |
1585 | if (d->windowManager) |
1586 | d->windowManager->handleUpdateRequest(this); |
1587 | break; |
1588 | case QEvent::PlatformSurface: |
1589 | if ((static_cast<QPlatformSurfaceEvent *>(event))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) { |
1590 | // Ensure that the rendering thread is notified before |
1591 | // the QPlatformWindow is destroyed. |
1592 | if (d->windowManager) |
1593 | d->windowManager->hide(window: this); |
1594 | } |
1595 | break; |
1596 | case QEvent::WindowDeactivate: |
1597 | if (auto da = d->deliveryAgentPrivate()) |
1598 | da->handleWindowDeactivate(win: this); |
1599 | Q_FALLTHROUGH(); |
1600 | case QEvent::WindowActivate: |
1601 | if (d->contentItem) |
1602 | QCoreApplication::sendEvent(receiver: d->contentItem, event); |
1603 | break; |
1604 | case QEvent::ApplicationPaletteChange: |
1605 | d->inheritPalette(parentPalette: QGuiApplication::palette()); |
1606 | if (d->contentItem) |
1607 | QCoreApplication::sendEvent(receiver: d->contentItem, event); |
1608 | break; |
1609 | case QEvent::DevicePixelRatioChange: |
1610 | physicalDpiChanged(); |
1611 | break; |
1612 | case QEvent::ChildWindowAdded: { |
1613 | auto *childEvent = static_cast<QChildWindowEvent*>(event); |
1614 | auto *childWindow = childEvent->child(); |
1615 | qCDebug(lcQuickWindow) << "Child window"<< childWindow << "added to"<< this; |
1616 | if (childWindow->handle()) { |
1617 | // The reparenting has already resulted in the native window |
1618 | // being added to its parent, on top of all other windows. We need |
1619 | // to do a synchronous re-stacking of the windows here, to avoid |
1620 | // leaving the window in the wrong position while waiting for the |
1621 | // asynchronous callback to QQuickWindow::polishItems(). |
1622 | d->updateChildWindowStackingOrder(); |
1623 | } else { |
1624 | qCDebug(lcQuickWindow) << "No platform window yet." |
1625 | << "Deferring child window stacking until surface creation"; |
1626 | } |
1627 | break; |
1628 | } |
1629 | default: |
1630 | break; |
1631 | } |
1632 | |
1633 | if (event->type() == QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)) |
1634 | update(); |
1635 | else if (event->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure)) |
1636 | d->windowManager->handleContextCreationFailure(window: this); |
1637 | |
1638 | if (event->isPointerEvent()) |
1639 | return true; |
1640 | else |
1641 | return QWindow::event(event); |
1642 | } |
1643 | |
1644 | void QQuickWindowPrivate::updateChildWindowStackingOrder(QQuickItem *item) |
1645 | { |
1646 | Q_Q(QQuickWindow); |
1647 | |
1648 | if (!item) { |
1649 | qCDebug(lcQuickWindow) << "Updating child window stacking order for"<< q; |
1650 | item = contentItem; |
1651 | } |
1652 | auto *itemPrivate = QQuickItemPrivate::get(item); |
1653 | const auto paintOrderChildItems = itemPrivate->paintOrderChildItems(); |
1654 | for (auto *child : paintOrderChildItems) { |
1655 | if (auto *windowContainer = qobject_cast<QQuickWindowContainer*>(object: child)) { |
1656 | auto *window = windowContainer->containedWindow(); |
1657 | if (!window) { |
1658 | qCDebug(lcQuickWindow) << windowContainer << "has no contained window yet"; |
1659 | continue; |
1660 | } |
1661 | if (window->parent() != q) { |
1662 | qCDebug(lcQuickWindow) << window << "is not yet child of this window"; |
1663 | continue; |
1664 | } |
1665 | qCDebug(lcQuickWindow) << "Raising"<< window << "owned by"<< windowContainer; |
1666 | window->raise(); |
1667 | } |
1668 | |
1669 | updateChildWindowStackingOrder(item: child); |
1670 | } |
1671 | } |
1672 | |
1673 | /*! \reimp */ |
1674 | void QQuickWindow::keyPressEvent(QKeyEvent *e) |
1675 | { |
1676 | Q_D(QQuickWindow); |
1677 | if (d->windowEventDispatch) |
1678 | return; |
1679 | auto da = d->deliveryAgentPrivate(); |
1680 | Q_ASSERT(da); |
1681 | da->deliverKeyEvent(e); |
1682 | } |
1683 | |
1684 | /*! \reimp */ |
1685 | void QQuickWindow::keyReleaseEvent(QKeyEvent *e) |
1686 | { |
1687 | Q_D(QQuickWindow); |
1688 | if (d->windowEventDispatch) |
1689 | return; |
1690 | auto da = d->deliveryAgentPrivate(); |
1691 | Q_ASSERT(da); |
1692 | da->deliverKeyEvent(e); |
1693 | } |
1694 | |
1695 | #if QT_CONFIG(wheelevent) |
1696 | /*! \reimp */ |
1697 | void QQuickWindow::wheelEvent(QWheelEvent *event) |
1698 | { |
1699 | Q_D(QQuickWindow); |
1700 | if (d->windowEventDispatch) |
1701 | return; |
1702 | auto da = d->deliveryAgentPrivate(); |
1703 | Q_ASSERT(da); |
1704 | da->deliverSinglePointEventUntilAccepted(event); |
1705 | } |
1706 | #endif // wheelevent |
1707 | |
1708 | #if QT_CONFIG(tabletevent) |
1709 | /*! \reimp */ |
1710 | void QQuickWindow::tabletEvent(QTabletEvent *event) |
1711 | { |
1712 | Q_D(QQuickWindow); |
1713 | if (d->windowEventDispatch) |
1714 | return; |
1715 | auto da = d->deliveryAgentPrivate(); |
1716 | Q_ASSERT(da); |
1717 | da->deliverPointerEvent(event); |
1718 | } |
1719 | #endif // tabletevent |
1720 | |
1721 | /*! \reimp */ |
1722 | void QQuickWindow::mousePressEvent(QMouseEvent *event) |
1723 | { |
1724 | Q_D(QQuickWindow); |
1725 | if (d->windowEventDispatch) |
1726 | return; |
1727 | auto da = d->deliveryAgentPrivate(); |
1728 | Q_ASSERT(da); |
1729 | da->handleMouseEvent(event); |
1730 | } |
1731 | /*! \reimp */ |
1732 | void QQuickWindow::mouseMoveEvent(QMouseEvent *event) |
1733 | { |
1734 | Q_D(QQuickWindow); |
1735 | if (d->windowEventDispatch) |
1736 | return; |
1737 | auto da = d->deliveryAgentPrivate(); |
1738 | Q_ASSERT(da); |
1739 | da->handleMouseEvent(event); |
1740 | } |
1741 | /*! \reimp */ |
1742 | void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event) |
1743 | { |
1744 | Q_D(QQuickWindow); |
1745 | if (d->windowEventDispatch) |
1746 | return; |
1747 | auto da = d->deliveryAgentPrivate(); |
1748 | Q_ASSERT(da); |
1749 | da->handleMouseEvent(event); |
1750 | } |
1751 | /*! \reimp */ |
1752 | void QQuickWindow::mouseReleaseEvent(QMouseEvent *event) |
1753 | { |
1754 | Q_D(QQuickWindow); |
1755 | if (d->windowEventDispatch) |
1756 | return; |
1757 | auto da = d->deliveryAgentPrivate(); |
1758 | Q_ASSERT(da); |
1759 | da->handleMouseEvent(event); |
1760 | } |
1761 | |
1762 | #if QT_CONFIG(cursor) |
1763 | void QQuickWindowPrivate::updateCursor(const QPointF &scenePos, QQuickItem *rootItem) |
1764 | { |
1765 | Q_Q(QQuickWindow); |
1766 | if (!rootItem) |
1767 | rootItem = contentItem; |
1768 | auto cursorItemAndHandler = findCursorItemAndHandler(item: rootItem, scenePos); |
1769 | if (cursorItem != cursorItemAndHandler.first || cursorHandler != cursorItemAndHandler.second || |
1770 | (cursorItemAndHandler.second && QQuickPointerHandlerPrivate::get(q: cursorItemAndHandler.second)->cursorDirty)) { |
1771 | QWindow *renderWindow = QQuickRenderControl::renderWindowFor(win: q); |
1772 | QWindow *window = renderWindow ? renderWindow : q; |
1773 | cursorItem = cursorItemAndHandler.first; |
1774 | cursorHandler = cursorItemAndHandler.second; |
1775 | if (cursorHandler) |
1776 | QQuickPointerHandlerPrivate::get(q: cursorItemAndHandler.second)->cursorDirty = false; |
1777 | if (cursorItem) { |
1778 | const auto cursor = QQuickItemPrivate::get(item: cursorItem)->effectiveCursor(handler: cursorHandler); |
1779 | qCDebug(lcHoverTrace) << "setting cursor"<< cursor << "from"<< cursorHandler << "or"<< cursorItem; |
1780 | window->setCursor(cursor); |
1781 | } else { |
1782 | qCDebug(lcHoverTrace) << "unsetting cursor"; |
1783 | window->unsetCursor(); |
1784 | } |
1785 | } |
1786 | } |
1787 | |
1788 | QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAndHandler(QQuickItem *item, const QPointF &scenePos) const |
1789 | { |
1790 | QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); |
1791 | if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) { |
1792 | QPointF p = item->mapFromScene(point: scenePos); |
1793 | if (!item->contains(point: p)) |
1794 | return {nullptr, nullptr}; |
1795 | } |
1796 | |
1797 | if (itemPrivate->subtreeCursorEnabled) { |
1798 | QList<QQuickItem *> children = itemPrivate->paintOrderChildItems(); |
1799 | for (int ii = children.size() - 1; ii >= 0; --ii) { |
1800 | QQuickItem *child = children.at(i: ii); |
1801 | if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(item: child)->culled) |
1802 | continue; |
1803 | auto ret = findCursorItemAndHandler(item: child, scenePos); |
1804 | if (ret.first) |
1805 | return ret; |
1806 | } |
1807 | if (itemPrivate->hasCursorHandler) { |
1808 | if (auto handler = itemPrivate->effectiveCursorHandler()) { |
1809 | if (handler->parentContains(scenePosition: scenePos)) |
1810 | return {item, handler}; |
1811 | } |
1812 | } |
1813 | if (itemPrivate->hasCursor) { |
1814 | QPointF p = item->mapFromScene(point: scenePos); |
1815 | if (item->contains(point: p)) |
1816 | return {item, nullptr}; |
1817 | } |
1818 | } |
1819 | |
1820 | return {nullptr, nullptr}; |
1821 | } |
1822 | #endif |
1823 | |
1824 | void QQuickWindowPrivate::clearFocusObject() |
1825 | { |
1826 | if (auto da = deliveryAgentPrivate()) |
1827 | da->clearFocusObject(); |
1828 | } |
1829 | |
1830 | void QQuickWindowPrivate::setFocusToTarget(FocusTarget target, Qt::FocusReason reason) |
1831 | { |
1832 | if (!contentItem) |
1833 | return; |
1834 | |
1835 | QQuickItem *newFocusItem = nullptr; |
1836 | switch (target) { |
1837 | case FocusTarget::First: |
1838 | case FocusTarget::Last: { |
1839 | const bool forward = (target == FocusTarget::First); |
1840 | newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(item: contentItem, forward); |
1841 | if (newFocusItem) { |
1842 | const auto *itemPriv = QQuickItemPrivate::get(item: newFocusItem); |
1843 | if (itemPriv->subFocusItem && itemPriv->flags & QQuickItem::ItemIsFocusScope) |
1844 | clearFocusInScope(scope: newFocusItem, item: itemPriv->subFocusItem, reason); |
1845 | } |
1846 | break; |
1847 | } |
1848 | case FocusTarget::Next: |
1849 | case FocusTarget::Prev: { |
1850 | const auto da = deliveryAgentPrivate(); |
1851 | Q_ASSERT(da); |
1852 | QQuickItem *focusItem = da->focusTargetItem() ? da->focusTargetItem() : contentItem; |
1853 | bool forward = (target == FocusTarget::Next); |
1854 | newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(item: focusItem, forward); |
1855 | break; |
1856 | } |
1857 | default: |
1858 | break; |
1859 | } |
1860 | |
1861 | if (newFocusItem) |
1862 | newFocusItem->forceActiveFocus(reason); |
1863 | } |
1864 | |
1865 | /*! |
1866 | \qmlproperty list<QtObject> Window::data |
1867 | \qmldefault |
1868 | |
1869 | The data property allows you to freely mix visual children, resources |
1870 | and other Windows in a Window. |
1871 | |
1872 | If you assign another Window to the data list, the nested window will |
1873 | become "transient for" the outer Window. |
1874 | |
1875 | If you assign an \l Item to the data list, it becomes a child of the |
1876 | Window's \l contentItem, so that it appears inside the window. The item's |
1877 | parent will be the window's contentItem, which is the root of the Item |
1878 | ownership tree within that Window. |
1879 | |
1880 | If you assign any other object type, it is added as a resource. |
1881 | |
1882 | It should not generally be necessary to refer to the \c data property, |
1883 | as it is the default property for Window and thus all child items are |
1884 | automatically assigned to this property. |
1885 | |
1886 | \sa QWindow::transientParent() |
1887 | */ |
1888 | |
1889 | void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObject *o) |
1890 | { |
1891 | if (!o) |
1892 | return; |
1893 | QQuickWindow *that = static_cast<QQuickWindow *>(property->object); |
1894 | QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(item: that->contentItem())->data(); |
1895 | itemProperty.append(&itemProperty, o); |
1896 | } |
1897 | |
1898 | qsizetype QQuickWindowPrivate::data_count(QQmlListProperty<QObject> *property) |
1899 | { |
1900 | QQuickWindow *win = static_cast<QQuickWindow*>(property->object); |
1901 | if (!win || !win->contentItem() || !QQuickItemPrivate::get(item: win->contentItem())->data().count) |
1902 | return 0; |
1903 | QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(item: win->contentItem())->data(); |
1904 | return itemProperty.count(&itemProperty); |
1905 | } |
1906 | |
1907 | QObject *QQuickWindowPrivate::data_at(QQmlListProperty<QObject> *property, qsizetype i) |
1908 | { |
1909 | QQuickWindow *win = static_cast<QQuickWindow*>(property->object); |
1910 | QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(item: win->contentItem())->data(); |
1911 | return itemProperty.at(&itemProperty, i); |
1912 | } |
1913 | |
1914 | void QQuickWindowPrivate::data_clear(QQmlListProperty<QObject> *property) |
1915 | { |
1916 | QQuickWindow *win = static_cast<QQuickWindow*>(property->object); |
1917 | QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(item: win->contentItem())->data(); |
1918 | itemProperty.clear(&itemProperty); |
1919 | } |
1920 | |
1921 | void QQuickWindowPrivate::data_removeLast(QQmlListProperty<QObject> *property) |
1922 | { |
1923 | QQuickWindow *win = static_cast<QQuickWindow*>(property->object); |
1924 | QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(item: win->contentItem())->data(); |
1925 | itemProperty.removeLast(&itemProperty); |
1926 | } |
1927 | |
1928 | bool QQuickWindowPrivate::isRenderable() const |
1929 | { |
1930 | Q_Q(const QQuickWindow); |
1931 | return ((q->isExposed() && q->isVisible())) && q->geometry().isValid(); |
1932 | } |
1933 | |
1934 | void QQuickWindowPrivate::rhiCreationFailureMessage(const QString &backendName, |
1935 | QString *translatedMessage, |
1936 | QString *untranslatedMessage) |
1937 | { |
1938 | const char msg[] = QT_TRANSLATE_NOOP("QQuickWindow", |
1939 | "Failed to initialize graphics backend for %1."); |
1940 | *translatedMessage = QQuickWindow::tr(s: msg).arg(a: backendName); |
1941 | *untranslatedMessage = QString::fromLatin1(ba: msg).arg(a: backendName); |
1942 | } |
1943 | |
1944 | void QQuickWindowPrivate::cleanupNodes() |
1945 | { |
1946 | qDeleteAll(c: std::exchange(obj&: cleanupNodeList, new_val: {})); |
1947 | } |
1948 | |
1949 | void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item) |
1950 | { |
1951 | QQuickItemPrivate *p = QQuickItemPrivate::get(item); |
1952 | if (p->itemNodeInstance) { |
1953 | delete p->itemNodeInstance; |
1954 | p->itemNodeInstance = nullptr; |
1955 | |
1956 | if (p->extra.isAllocated()) { |
1957 | p->extra->opacityNode = nullptr; |
1958 | p->extra->clipNode = nullptr; |
1959 | p->extra->rootNode = nullptr; |
1960 | } |
1961 | |
1962 | p->paintNode = nullptr; |
1963 | |
1964 | p->dirty(QQuickItemPrivate::Window); |
1965 | } |
1966 | |
1967 | // Qt 7: Make invalidateSceneGraph a virtual member of QQuickItem |
1968 | if (p->flags & QQuickItem::ItemHasContents) { |
1969 | const QMetaObject *mo = item->metaObject(); |
1970 | int index = mo->indexOfSlot(slot: "invalidateSceneGraph()"); |
1971 | if (index >= 0) { |
1972 | const QMetaMethod &method = mo->method(index); |
1973 | // Skip functions named invalidateSceneGraph() in QML items. |
1974 | if (strstr(haystack: method.enclosingMetaObject()->className(), needle: "_QML_") == nullptr) |
1975 | method.invoke(obj: item, c: Qt::DirectConnection); |
1976 | } |
1977 | } |
1978 | |
1979 | for (int ii = 0; ii < p->childItems.size(); ++ii) |
1980 | cleanupNodesOnShutdown(item: p->childItems.at(i: ii)); |
1981 | } |
1982 | |
1983 | // This must be called from the render thread, with the main thread frozen |
1984 | void QQuickWindowPrivate::cleanupNodesOnShutdown() |
1985 | { |
1986 | Q_Q(QQuickWindow); |
1987 | cleanupNodes(); |
1988 | cleanupNodesOnShutdown(item: contentItem); |
1989 | for (QSet<QQuickItem *>::const_iterator it = parentlessItems.begin(), cend = parentlessItems.end(); it != cend; ++it) |
1990 | cleanupNodesOnShutdown(item: *it); |
1991 | animationController->windowNodesDestroyed(); |
1992 | q->cleanupSceneGraph(); |
1993 | } |
1994 | |
1995 | void QQuickWindowPrivate::updateDirtyNodes() |
1996 | { |
1997 | qCDebug(lcDirty) << "QQuickWindowPrivate::updateDirtyNodes():"; |
1998 | |
1999 | cleanupNodes(); |
2000 | |
2001 | QQuickItem *updateList = dirtyItemList; |
2002 | dirtyItemList = nullptr; |
2003 | if (updateList) QQuickItemPrivate::get(item: updateList)->prevDirtyItem = &updateList; |
2004 | |
2005 | while (updateList) { |
2006 | QQuickItem *item = updateList; |
2007 | QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); |
2008 | itemPriv->removeFromDirtyList(); |
2009 | |
2010 | qCDebug(lcDirty) << " QSGNode:"<< item << qPrintable(itemPriv->dirtyToString()); |
2011 | updateDirtyNode(item); |
2012 | } |
2013 | } |
2014 | |
2015 | static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d) |
2016 | { |
2017 | const QList<QQuickItem *> childItems = d->paintOrderChildItems(); |
2018 | QQuickItem *before = nullptr; |
2019 | for (int i=0; i<childItems.size(); ++i) { |
2020 | QQuickItemPrivate *dd = QQuickItemPrivate::get(item: childItems.at(i)); |
2021 | // Perform the same check as the in fetchNextNode below. |
2022 | if (dd->z() < 0 && (dd->explicitVisible || (dd->extra.isAllocated() && dd->extra->effectRefCount))) |
2023 | before = childItems.at(i); |
2024 | else |
2025 | break; |
2026 | } |
2027 | return Q_UNLIKELY(before) ? QQuickItemPrivate::get(item: before)->itemNode() : nullptr; |
2028 | } |
2029 | |
2030 | static QSGNode *fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &returnedPaintNode) |
2031 | { |
2032 | QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems(); |
2033 | |
2034 | for (; ii < orderedChildren.size() && orderedChildren.at(i: ii)->z() < 0; ++ii) { |
2035 | QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(item: orderedChildren.at(i: ii)); |
2036 | if (!childPrivate->explicitVisible && |
2037 | (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) |
2038 | continue; |
2039 | |
2040 | ii++; |
2041 | return childPrivate->itemNode(); |
2042 | } |
2043 | |
2044 | if (itemPriv->paintNode && !returnedPaintNode) { |
2045 | returnedPaintNode = true; |
2046 | return itemPriv->paintNode; |
2047 | } |
2048 | |
2049 | for (; ii < orderedChildren.size(); ++ii) { |
2050 | QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(item: orderedChildren.at(i: ii)); |
2051 | if (!childPrivate->explicitVisible && |
2052 | (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) |
2053 | continue; |
2054 | |
2055 | ii++; |
2056 | return childPrivate->itemNode(); |
2057 | } |
2058 | |
2059 | return nullptr; |
2060 | } |
2061 | |
2062 | void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) |
2063 | { |
2064 | QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); |
2065 | quint32 dirty = itemPriv->dirtyAttributes; |
2066 | itemPriv->dirtyAttributes = 0; |
2067 | |
2068 | if ((dirty & QQuickItemPrivate::TransformUpdateMask) || |
2069 | (dirty & QQuickItemPrivate::Size && itemPriv->origin() != QQuickItem::TopLeft && |
2070 | (itemPriv->scale() != 1. || itemPriv->rotation() != 0.))) { |
2071 | |
2072 | QMatrix4x4 matrix; |
2073 | |
2074 | if (itemPriv->x != 0. || itemPriv->y != 0.) |
2075 | matrix.translate(x: itemPriv->x, y: itemPriv->y); |
2076 | |
2077 | for (int ii = itemPriv->transforms.size() - 1; ii >= 0; --ii) |
2078 | itemPriv->transforms.at(i: ii)->applyTo(matrix: &matrix); |
2079 | |
2080 | if (itemPriv->scale() != 1. || itemPriv->rotation() != 0.) { |
2081 | QPointF origin = item->transformOriginPoint(); |
2082 | matrix.translate(x: origin.x(), y: origin.y()); |
2083 | if (itemPriv->scale() != 1.) |
2084 | matrix.scale(x: itemPriv->scale(), y: itemPriv->scale()); |
2085 | if (itemPriv->rotation() != 0.) |
2086 | matrix.rotate(angle: itemPriv->rotation(), x: 0, y: 0, z: 1); |
2087 | matrix.translate(x: -origin.x(), y: -origin.y()); |
2088 | } |
2089 | |
2090 | itemPriv->itemNode()->setMatrix(matrix); |
2091 | } |
2092 | |
2093 | const bool clipEffectivelyChanged = dirty & (QQuickItemPrivate::Clip | QQuickItemPrivate::Window); |
2094 | if (clipEffectivelyChanged) { |
2095 | QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *)itemPriv->opacityNode() |
2096 | : (QSGNode *)itemPriv->itemNode(); |
2097 | QSGNode *child = itemPriv->rootNode(); |
2098 | |
2099 | if (bool initializeClipNode = item->clip() && itemPriv->clipNode() == nullptr; |
2100 | initializeClipNode) { |
2101 | QQuickDefaultClipNode *clip = new QQuickDefaultClipNode(item->clipRect()); |
2102 | itemPriv->extra.value().clipNode = clip; |
2103 | clip->update(); |
2104 | |
2105 | if (!child) { |
2106 | parent->reparentChildNodesTo(newParent: clip); |
2107 | parent->appendChildNode(node: clip); |
2108 | } else { |
2109 | parent->removeChildNode(node: child); |
2110 | clip->appendChildNode(node: child); |
2111 | parent->appendChildNode(node: clip); |
2112 | } |
2113 | |
2114 | } else if (bool updateClipNode = item->clip() && itemPriv->clipNode() != nullptr; |
2115 | updateClipNode) { |
2116 | QQuickDefaultClipNode *clip = itemPriv->clipNode(); |
2117 | clip->setClipRect(item->clipRect()); |
2118 | clip->update(); |
2119 | } else if (bool removeClipNode = !item->clip() && itemPriv->clipNode() != nullptr; |
2120 | removeClipNode) { |
2121 | QQuickDefaultClipNode *clip = itemPriv->clipNode(); |
2122 | parent->removeChildNode(node: clip); |
2123 | if (child) { |
2124 | clip->removeChildNode(node: child); |
2125 | parent->appendChildNode(node: child); |
2126 | } else { |
2127 | clip->reparentChildNodesTo(newParent: parent); |
2128 | } |
2129 | |
2130 | delete itemPriv->clipNode(); |
2131 | itemPriv->extra->clipNode = nullptr; |
2132 | } |
2133 | } |
2134 | |
2135 | const int effectRefCount = itemPriv->extra.isAllocated() ? itemPriv->extra->effectRefCount : 0; |
2136 | const bool effectRefEffectivelyChanged = |
2137 | (dirty & (QQuickItemPrivate::EffectReference | QQuickItemPrivate::Window)) |
2138 | && ((effectRefCount == 0) != (itemPriv->rootNode() == nullptr)); |
2139 | if (effectRefEffectivelyChanged) { |
2140 | if (dirty & QQuickItemPrivate::ChildrenUpdateMask) |
2141 | itemPriv->childContainerNode()->removeAllChildNodes(); |
2142 | |
2143 | QSGNode *parent = itemPriv->clipNode(); |
2144 | if (!parent) |
2145 | parent = itemPriv->opacityNode(); |
2146 | if (!parent) |
2147 | parent = itemPriv->itemNode(); |
2148 | |
2149 | if (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount) { |
2150 | Q_ASSERT(itemPriv->rootNode() == nullptr); |
2151 | QSGRootNode *root = new QSGRootNode(); |
2152 | itemPriv->extra->rootNode = root; |
2153 | parent->reparentChildNodesTo(newParent: root); |
2154 | parent->appendChildNode(node: root); |
2155 | } else { |
2156 | Q_ASSERT(itemPriv->rootNode() != nullptr); |
2157 | QSGRootNode *root = itemPriv->rootNode(); |
2158 | parent->removeChildNode(node: root); |
2159 | root->reparentChildNodesTo(newParent: parent); |
2160 | delete itemPriv->rootNode(); |
2161 | itemPriv->extra->rootNode = nullptr; |
2162 | } |
2163 | } |
2164 | |
2165 | if (dirty & QQuickItemPrivate::ChildrenUpdateMask) { |
2166 | int ii = 0; |
2167 | bool fetchedPaintNode = false; |
2168 | QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems(); |
2169 | int desiredNodesSize = orderedChildren.size() + (itemPriv->paintNode ? 1 : 0); |
2170 | |
2171 | // now start making current state match the promised land of |
2172 | // desiredNodes. in the case of our current state matching desiredNodes |
2173 | // (though why would we get ChildrenUpdateMask with no changes?) then we |
2174 | // should make no changes at all. |
2175 | |
2176 | // how many nodes did we process, when examining changes |
2177 | int desiredNodesProcessed = 0; |
2178 | |
2179 | // currentNode is how far, in our present tree, we have processed. we |
2180 | // make use of this later on to trim the current child list if the |
2181 | // desired list is shorter. |
2182 | QSGNode *groupNode = itemPriv->childContainerNode(); |
2183 | QSGNode *currentNode = groupNode->firstChild(); |
2184 | QSGNode *desiredNode = nullptr; |
2185 | |
2186 | while (currentNode && (desiredNode = fetchNextNode(itemPriv, ii, returnedPaintNode&: fetchedPaintNode))) { |
2187 | if (currentNode != desiredNode) { |
2188 | // uh oh... reality and our utopic paradise are diverging! |
2189 | // we need to reconcile this... |
2190 | if (currentNode->nextSibling() == desiredNode) { |
2191 | // nice and simple: a node was removed, and the next in line is correct. |
2192 | groupNode->removeChildNode(node: currentNode); |
2193 | } else { |
2194 | // a node needs to be added.. |
2195 | // remove it from any pre-existing parent, and push it before currentNode, |
2196 | // so it's in the correct place... |
2197 | if (desiredNode->parent()) { |
2198 | desiredNode->parent()->removeChildNode(node: desiredNode); |
2199 | } |
2200 | groupNode->insertChildNodeBefore(node: desiredNode, before: currentNode); |
2201 | } |
2202 | |
2203 | // continue iteration at the correct point, now desiredNode is in place... |
2204 | currentNode = desiredNode; |
2205 | } |
2206 | |
2207 | currentNode = currentNode->nextSibling(); |
2208 | desiredNodesProcessed++; |
2209 | } |
2210 | |
2211 | // if we didn't process as many nodes as in the new list, then we have |
2212 | // more nodes at the end of desiredNodes to append to our list. |
2213 | // this will be the case when adding new nodes, for instance. |
2214 | if (desiredNodesProcessed < desiredNodesSize) { |
2215 | while ((desiredNode = fetchNextNode(itemPriv, ii, returnedPaintNode&: fetchedPaintNode))) { |
2216 | if (desiredNode->parent()) |
2217 | desiredNode->parent()->removeChildNode(node: desiredNode); |
2218 | groupNode->appendChildNode(node: desiredNode); |
2219 | } |
2220 | } else if (currentNode) { |
2221 | // on the other hand, if we processed less than our current node |
2222 | // tree, then nodes have been _removed_ from the scene, and we need |
2223 | // to take care of that here. |
2224 | while (currentNode) { |
2225 | QSGNode *node = currentNode->nextSibling(); |
2226 | groupNode->removeChildNode(node: currentNode); |
2227 | currentNode = node; |
2228 | } |
2229 | } |
2230 | } |
2231 | |
2232 | if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) { |
2233 | itemPriv->clipNode()->setRect(item->clipRect()); |
2234 | itemPriv->clipNode()->update(); |
2235 | } |
2236 | |
2237 | if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible |
2238 | | QQuickItemPrivate::HideReference | QQuickItemPrivate::Window)) |
2239 | { |
2240 | qreal opacity = itemPriv->explicitVisible && (!itemPriv->extra.isAllocated() || itemPriv->extra->hideRefCount == 0) |
2241 | ? itemPriv->opacity() : qreal(0); |
2242 | |
2243 | if (opacity != 1 && !itemPriv->opacityNode()) { |
2244 | QSGOpacityNode *node = new QSGOpacityNode; |
2245 | itemPriv->extra.value().opacityNode = node; |
2246 | |
2247 | QSGNode *parent = itemPriv->itemNode(); |
2248 | QSGNode *child = itemPriv->clipNode(); |
2249 | if (!child) |
2250 | child = itemPriv->rootNode(); |
2251 | |
2252 | if (child) { |
2253 | parent->removeChildNode(node: child); |
2254 | node->appendChildNode(node: child); |
2255 | parent->appendChildNode(node); |
2256 | } else { |
2257 | parent->reparentChildNodesTo(newParent: node); |
2258 | parent->appendChildNode(node); |
2259 | } |
2260 | } |
2261 | if (itemPriv->opacityNode()) |
2262 | itemPriv->opacityNode()->setOpacity(opacity); |
2263 | } |
2264 | |
2265 | if (dirty & QQuickItemPrivate::ContentUpdateMask) { |
2266 | |
2267 | if (itemPriv->flags & QQuickItem::ItemHasContents) { |
2268 | updatePaintNodeData.transformNode = itemPriv->itemNode(); |
2269 | itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData); |
2270 | |
2271 | Q_ASSERT(itemPriv->paintNode == nullptr || |
2272 | itemPriv->paintNode->parent() == nullptr || |
2273 | itemPriv->paintNode->parent() == itemPriv->childContainerNode()); |
2274 | |
2275 | if (itemPriv->paintNode && itemPriv->paintNode->parent() == nullptr) { |
2276 | QSGNode *before = qquickitem_before_paintNode(d: itemPriv); |
2277 | if (before && before->parent()) { |
2278 | Q_ASSERT(before->parent() == itemPriv->childContainerNode()); |
2279 | itemPriv->childContainerNode()->insertChildNodeAfter(node: itemPriv->paintNode, after: before); |
2280 | } else { |
2281 | itemPriv->childContainerNode()->prependChildNode(node: itemPriv->paintNode); |
2282 | } |
2283 | } |
2284 | } else if (itemPriv->paintNode) { |
2285 | delete itemPriv->paintNode; |
2286 | itemPriv->paintNode = nullptr; |
2287 | } |
2288 | } |
2289 | |
2290 | #ifndef QT_NO_DEBUG |
2291 | // Check consistency. |
2292 | |
2293 | QList<QSGNode *> nodes; |
2294 | nodes << itemPriv->itemNodeInstance |
2295 | << itemPriv->opacityNode() |
2296 | << itemPriv->clipNode() |
2297 | << itemPriv->rootNode() |
2298 | << itemPriv->paintNode; |
2299 | nodes.removeAll(t: nullptr); |
2300 | |
2301 | Q_ASSERT(nodes.constFirst() == itemPriv->itemNodeInstance); |
2302 | for (int i=1; i<nodes.size(); ++i) { |
2303 | QSGNode *n = nodes.at(i); |
2304 | // Failing this means we messed up reparenting |
2305 | Q_ASSERT(n->parent() == nodes.at(i-1)); |
2306 | // Only the paintNode and the one who is childContainer may have more than one child. |
2307 | Q_ASSERT(n == itemPriv->paintNode || n == itemPriv->childContainerNode() || n->childCount() == 1); |
2308 | } |
2309 | #endif |
2310 | |
2311 | } |
2312 | |
2313 | bool QQuickWindowPrivate::emitError(QQuickWindow::SceneGraphError error, const QString &msg) |
2314 | { |
2315 | Q_Q(QQuickWindow); |
2316 | static const QMetaMethod errorSignal = QMetaMethod::fromSignal(signal: &QQuickWindow::sceneGraphError); |
2317 | if (q->isSignalConnected(signal: errorSignal)) { |
2318 | emit q->sceneGraphError(error, message: msg); |
2319 | return true; |
2320 | } |
2321 | return false; |
2322 | } |
2323 | |
2324 | void QQuickWindow::maybeUpdate() |
2325 | { |
2326 | Q_D(QQuickWindow); |
2327 | if (d->renderControl) |
2328 | QQuickRenderControlPrivate::get(renderControl: d->renderControl)->maybeUpdate(); |
2329 | else if (d->windowManager) |
2330 | d->windowManager->maybeUpdate(window: this); |
2331 | } |
2332 | |
2333 | void QQuickWindow::cleanupSceneGraph() |
2334 | { |
2335 | Q_D(QQuickWindow); |
2336 | if (!d->renderer) |
2337 | return; |
2338 | |
2339 | delete d->renderer->rootNode(); |
2340 | delete d->renderer; |
2341 | d->renderer = nullptr; |
2342 | |
2343 | d->runAndClearJobs(jobs: &d->beforeSynchronizingJobs); |
2344 | d->runAndClearJobs(jobs: &d->afterSynchronizingJobs); |
2345 | d->runAndClearJobs(jobs: &d->beforeRenderingJobs); |
2346 | d->runAndClearJobs(jobs: &d->afterRenderingJobs); |
2347 | d->runAndClearJobs(jobs: &d->afterSwapJobs); |
2348 | } |
2349 | |
2350 | QOpenGLContext *QQuickWindowPrivate::openglContext() |
2351 | { |
2352 | #if QT_CONFIG(opengl) |
2353 | if (context && context->isValid()) { |
2354 | QSGRendererInterface *rif = context->sceneGraphContext()->rendererInterface(renderContext: context); |
2355 | if (rif) { |
2356 | Q_Q(QQuickWindow); |
2357 | return reinterpret_cast<QOpenGLContext *>(rif->getResource(window: q, resource: QSGRendererInterface::OpenGLContextResource)); |
2358 | } |
2359 | } |
2360 | #endif |
2361 | return nullptr; |
2362 | } |
2363 | |
2364 | /*! |
2365 | Returns true if the scene graph has been initialized; otherwise returns false. |
2366 | */ |
2367 | bool QQuickWindow::isSceneGraphInitialized() const |
2368 | { |
2369 | Q_D(const QQuickWindow); |
2370 | return d->context != nullptr && d->context->isValid(); |
2371 | } |
2372 | |
2373 | /*! |
2374 | \fn void QQuickWindow::frameSwapped() |
2375 | |
2376 | This signal is emitted when a frame has been queued for presenting. With |
2377 | vertical synchronization enabled the signal is emitted at most once per |
2378 | vsync interval in a continuously animating scene. |
2379 | |
2380 | This signal will be emitted from the scene graph rendering thread. |
2381 | */ |
2382 | |
2383 | /*! |
2384 | \qmlsignal QtQuick::Window::frameSwapped() |
2385 | |
2386 | This signal is emitted when a frame has been queued for presenting. With |
2387 | vertical synchronization enabled the signal is emitted at most once per |
2388 | vsync interval in a continuously animating scene. |
2389 | */ |
2390 | |
2391 | /*! |
2392 | \fn void QQuickWindow::sceneGraphInitialized() |
2393 | |
2394 | This signal is emitted when the scene graph has been initialized. |
2395 | |
2396 | This signal will be emitted from the scene graph rendering thread. |
2397 | */ |
2398 | |
2399 | /*! |
2400 | \qmlsignal QtQuick::Window::sceneGraphInitialized() |
2401 | \internal |
2402 | */ |
2403 | |
2404 | /*! |
2405 | \fn void QQuickWindow::sceneGraphInvalidated() |
2406 | |
2407 | This signal is emitted when the scene graph has been invalidated. |
2408 | |
2409 | This signal implies that the graphics rendering context used |
2410 | has been invalidated and all user resources tied to that context |
2411 | should be released. |
2412 | |
2413 | When rendering with OpenGL, the QOpenGLContext of this window will |
2414 | be bound when this function is called. The only exception is if |
2415 | the native OpenGL has been destroyed outside Qt's control, for |
2416 | instance through EGL_CONTEXT_LOST. |
2417 | |
2418 | This signal will be emitted from the scene graph rendering thread. |
2419 | */ |
2420 | |
2421 | /*! |
2422 | \qmlsignal QtQuick::Window::sceneGraphInvalidated() |
2423 | \internal |
2424 | */ |
2425 | |
2426 | /*! |
2427 | \fn void QQuickWindow::sceneGraphError(SceneGraphError error, const QString &message) |
2428 | |
2429 | This signal is emitted when an \a error occurred during scene graph initialization. |
2430 | |
2431 | Applications should connect to this signal if they wish to handle errors, |
2432 | like graphics context creation failures, in a custom way. When no slot is |
2433 | connected to the signal, the behavior will be different: Quick will print |
2434 | the \a message, or show a message box, and terminate the application. |
2435 | |
2436 | This signal will be emitted from the GUI thread. |
2437 | |
2438 | \since 5.3 |
2439 | */ |
2440 | |
2441 | /*! |
2442 | \qmlsignal QtQuick::Window::sceneGraphError(SceneGraphError error, QString message) |
2443 | |
2444 | This signal is emitted when an \a error occurred during scene graph initialization. |
2445 | |
2446 | You can implement onSceneGraphError(error, message) to handle errors, |
2447 | such as graphics context creation failures, in a custom way. |
2448 | If no handler is connected to this signal, Quick will print the \a message, |
2449 | or show a message box, and terminate the application. |
2450 | |
2451 | \since 5.3 |
2452 | */ |
2453 | |
2454 | /*! |
2455 | \class QQuickCloseEvent |
2456 | \internal |
2457 | \since 5.1 |
2458 | |
2459 | \inmodule QtQuick |
2460 | |
2461 | \brief Notification that a \l QQuickWindow is about to be closed |
2462 | */ |
2463 | /*! |
2464 | \qmltype CloseEvent |
2465 | \nativetype QQuickCloseEvent |
2466 | \inqmlmodule QtQuick |
2467 | \ingroup qtquick-visual |
2468 | \brief Notification that a \l Window is about to be closed. |
2469 | \since 5.1 |
2470 | |
2471 | Notification that a window is about to be closed by the windowing system |
2472 | (e.g. the user clicked the title bar close button). The CloseEvent contains |
2473 | an accepted property which can be set to false to abort closing the window. |
2474 | */ |
2475 | |
2476 | /*! |
2477 | \qmlproperty bool CloseEvent::accepted |
2478 | |
2479 | This property indicates whether the application will allow the user to |
2480 | close the window. It is true by default. |
2481 | */ |
2482 | |
2483 | /*! |
2484 | \internal |
2485 | \fn void QQuickWindow::closing(QQuickCloseEvent *close) |
2486 | \since 5.1 |
2487 | |
2488 | This signal is emitted when the window receives the event \a close from |
2489 | the windowing system. |
2490 | |
2491 | On \macOs, Qt will create a menu item \c Quit if there is no menu item |
2492 | whose text is "quit" or "exit". This menu item calls the \c QCoreApplication::quit |
2493 | signal, not the \c QQuickWindow::closing() signal. |
2494 | |
2495 | \sa {QMenuBar as a Global Menu Bar} |
2496 | */ |
2497 | |
2498 | /*! |
2499 | \qmlsignal QtQuick::Window::closing(CloseEvent close) |
2500 | \since 5.1 |
2501 | |
2502 | This signal is emitted when the user tries to close the window. |
2503 | |
2504 | This signal includes a \a close parameter. The \c {close.accepted} |
2505 | property is true by default so that the window is allowed to close; but you |
2506 | can implement an \c onClosing handler and set \c {close.accepted = false} if |
2507 | you need to do something else before the window can be closed. |
2508 | */ |
2509 | |
2510 | /*! |
2511 | Sets the render target for this window to be \a target. |
2512 | |
2513 | A QQuickRenderTarget serves as an opaque handle for a renderable native |
2514 | object, most commonly a 2D texture, and associated metadata, such as the |
2515 | size in pixels. |
2516 | |
2517 | A default constructed QQuickRenderTarget means no redirection. A valid |
2518 | \a target, created via one of the static QQuickRenderTarget factory functions, |
2519 | on the other hand, enables redirection of the rendering of the Qt Quick |
2520 | scene: it will no longer target the color buffers for the surface |
2521 | associated with the window, but rather the textures or other graphics |
2522 | objects specified in \a target. |
2523 | |
2524 | For example, assuming the scenegraph is using Vulkan to render, one can |
2525 | redirect its output into a \c VkImage. For graphics APIs like Vulkan, the |
2526 | image layout must be provided as well. QQuickRenderTarget instances are |
2527 | implicitly shared and are copyable and can be passed by value. They do not |
2528 | own the associated native objects (such as, the VkImage in the example), |
2529 | however. |
2530 | |
2531 | \badcode |
2532 | QQuickRenderTarget rt = QQuickRenderTarget::fromVulkanImage(vulkanImage, VK_IMAGE_LAYOUT_PREINITIALIZED, pixelSize); |
2533 | quickWindow->setRenderTarget(rt); |
2534 | \endcode |
2535 | |
2536 | This function is very often used in combination with QQuickRenderControl |
2537 | and an invisible QQuickWindow, in order to render Qt Quick content into a |
2538 | texture, without creating an on-screen native window for this QQuickWindow. |
2539 | |
2540 | When the desired target, or associated data, such as the size, changes, |
2541 | call this function with a new QQuickRenderTarget. Constructing |
2542 | QQuickRenderTarget instances and calling this function is cheap, but be |
2543 | aware that setting a new \a target with a different native object or other |
2544 | data may lead to potentially expensive initialization steps when the |
2545 | scenegraph is about to render the next frame. Therefore change the target |
2546 | only when necessary. |
2547 | |
2548 | \note The window does not take ownership of any native objects referenced |
2549 | in \a target. |
2550 | |
2551 | \note It is the caller's responsibility to ensure the native objects |
2552 | referred to in \a target are valid for the scenegraph renderer too. For |
2553 | instance, with Vulkan, Metal, and Direct3D this implies that the texture or |
2554 | image is created on the same graphics device that is used by the scenegraph |
2555 | internally. Therefore, when texture objects created on an already existing |
2556 | device or context are involved, this function is often used in combination |
2557 | with setGraphicsDevice(). |
2558 | |
2559 | \note With graphics APIs where relevant, the application must pay attention |
2560 | to image layout transitions performed by the scenegraph. For example, once |
2561 | a VkImage is associated with the scenegraph by calling this function, its |
2562 | layout will transition to \c VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL when |
2563 | rendering a frame. |
2564 | |
2565 | \warning This function can only be called from the thread doing the |
2566 | rendering. |
2567 | |
2568 | \since 6.0 |
2569 | |
2570 | \sa QQuickRenderControl, setGraphicsDevice(), setGraphicsApi() |
2571 | */ |
2572 | void QQuickWindow::setRenderTarget(const QQuickRenderTarget &target) |
2573 | { |
2574 | Q_D(QQuickWindow); |
2575 | if (target != d->customRenderTarget) { |
2576 | d->customRenderTarget = target; |
2577 | d->redirect.renderTargetDirty = true; |
2578 | } |
2579 | } |
2580 | |
2581 | /*! |
2582 | \return the QQuickRenderTarget passed to setRenderTarget(), or a default |
2583 | constructed one otherwise |
2584 | |
2585 | \since 6.0 |
2586 | |
2587 | \sa setRenderTarget() |
2588 | */ |
2589 | QQuickRenderTarget QQuickWindow::renderTarget() const |
2590 | { |
2591 | Q_D(const QQuickWindow); |
2592 | return d->customRenderTarget; |
2593 | } |
2594 | |
2595 | #ifdef Q_OS_WEBOS |
2596 | class GrabWindowForProtectedContent : public QRunnable |
2597 | { |
2598 | public: |
2599 | GrabWindowForProtectedContent(QQuickWindow *window, QImage *image, QWaitCondition *condition) |
2600 | : m_window(window) |
2601 | , m_image(image) |
2602 | , m_condition(condition) |
2603 | { |
2604 | } |
2605 | |
2606 | bool checkGrabbable() |
2607 | { |
2608 | if (!m_window) |
2609 | return false; |
2610 | if (!m_image) |
2611 | return false; |
2612 | if (!QQuickWindowPrivate::get(m_window)) |
2613 | return false; |
2614 | |
2615 | return true; |
2616 | } |
2617 | |
2618 | void run() override |
2619 | { |
2620 | if (!checkGrabbable()) |
2621 | return; |
2622 | |
2623 | *m_image = QSGRhiSupport::instance()->grabOffscreenForProtectedContent(m_window); |
2624 | if (m_condition) |
2625 | m_condition->wakeOne(); |
2626 | return; |
2627 | } |
2628 | |
2629 | private: |
2630 | QQuickWindow *m_window; |
2631 | QImage *m_image; |
2632 | QWaitCondition *m_condition; |
2633 | |
2634 | }; |
2635 | #endif |
2636 | |
2637 | /*! |
2638 | Grabs the contents of the window and returns it as an image. |
2639 | |
2640 | It is possible to call the grabWindow() function when the window is not |
2641 | visible. This requires that the window is \l{QWindow::create()} {created} |
2642 | and has a valid size and that no other QQuickWindow instances are rendering |
2643 | in the same process. |
2644 | |
2645 | \note When using this window in combination with QQuickRenderControl, the |
2646 | result of this function is an empty image, unless the \c software backend |
2647 | is in use. This is because when redirecting the output to an |
2648 | application-managed graphics resource (such as, a texture) by using |
2649 | QQuickRenderControl and setRenderTarget(), the application is better suited |
2650 | for managing and executing an eventual read back operation, since it is in |
2651 | full control of the resource to begin with. |
2652 | |
2653 | \warning Calling this function will cause performance problems. |
2654 | |
2655 | \warning This function can only be called from the GUI thread. |
2656 | */ |
2657 | QImage QQuickWindow::grabWindow() |
2658 | { |
2659 | Q_D(QQuickWindow); |
2660 | |
2661 | if (!d->isRenderable() && !d->renderControl) { |
2662 | // backends like software can grab regardless of the window state |
2663 | if (d->windowManager && (d->windowManager->flags() & QSGRenderLoop::SupportsGrabWithoutExpose)) |
2664 | return d->windowManager->grab(window: this); |
2665 | |
2666 | if (!isSceneGraphInitialized()) { |
2667 | // We do not have rendering up and running. Forget the render loop, |
2668 | // do a frame completely offscreen and synchronously into a |
2669 | // texture. This can be *very* slow due to all the device/context |
2670 | // and resource initialization but the documentation warns for it, |
2671 | // and is still important for some use cases. |
2672 | Q_ASSERT(!d->rhi); |
2673 | return QSGRhiSupport::instance()->grabOffscreen(window: this); |
2674 | } |
2675 | } |
2676 | |
2677 | #ifdef Q_OS_WEBOS |
2678 | if (requestedFormat().testOption(QSurfaceFormat::ProtectedContent)) { |
2679 | QImage image; |
2680 | QMutex mutex; |
2681 | QWaitCondition condition; |
2682 | mutex.lock(); |
2683 | GrabWindowForProtectedContent *job = new GrabWindowForProtectedContent(this, &image, &condition); |
2684 | if (!job) { |
2685 | qWarning("QQuickWindow::grabWindow: Failed to create a job for capturing protected content"); |
2686 | mutex.unlock(); |
2687 | return QImage(); |
2688 | } |
2689 | scheduleRenderJob(job, QQuickWindow::NoStage); |
2690 | condition.wait(&mutex); |
2691 | mutex.unlock(); |
2692 | return image; |
2693 | } |
2694 | #endif |
2695 | // The common case: we have an exposed window with an initialized |
2696 | // scenegraph, meaning we can request grabbing via the render loop, or we |
2697 | // are not targeting the window, in which case the request is to be |
2698 | // forwarded to the rendercontrol. |
2699 | if (d->renderControl) |
2700 | return QQuickRenderControlPrivate::get(renderControl: d->renderControl)->grab(); |
2701 | else if (d->windowManager) |
2702 | return d->windowManager->grab(window: this); |
2703 | |
2704 | return QImage(); |
2705 | } |
2706 | |
2707 | /*! |
2708 | Returns an incubation controller that splices incubation between frames |
2709 | for this window. QQuickView automatically installs this controller for you, |
2710 | otherwise you will need to install it yourself using \l{QQmlEngine::setIncubationController()}. |
2711 | |
2712 | The controller is owned by the window and will be destroyed when the window |
2713 | is deleted. |
2714 | */ |
2715 | QQmlIncubationController *QQuickWindow::incubationController() const |
2716 | { |
2717 | Q_D(const QQuickWindow); |
2718 | |
2719 | if (!d->windowManager) |
2720 | return nullptr; // TODO: make sure that this is safe |
2721 | |
2722 | if (!d->incubationController) |
2723 | d->incubationController = new QQuickWindowIncubationController(d->windowManager); |
2724 | return d->incubationController; |
2725 | } |
2726 | |
2727 | |
2728 | |
2729 | /*! |
2730 | \enum QQuickWindow::CreateTextureOption |
2731 | |
2732 | The CreateTextureOption enums are used to customize a texture is wrapped. |
2733 | |
2734 | \value TextureHasAlphaChannel The texture has an alpha channel and should |
2735 | be drawn using blending. |
2736 | |
2737 | \value TextureHasMipmaps The texture has mipmaps and can be drawn with |
2738 | mipmapping enabled. |
2739 | |
2740 | \value TextureOwnsGLTexture As of Qt 6.0, this flag is not used in practice |
2741 | and is ignored. Native graphics resource ownership is not transferable to |
2742 | the wrapping QSGTexture, because Qt Quick may not have the necessary details |
2743 | on how such an object and the associated memory should be freed. |
2744 | |
2745 | \value TextureCanUseAtlas The image can be uploaded into a texture atlas. |
2746 | |
2747 | \value TextureIsOpaque The texture will return false for |
2748 | QSGTexture::hasAlphaChannel() and will not be blended. This flag was added |
2749 | in Qt 5.6. |
2750 | |
2751 | */ |
2752 | |
2753 | /*! |
2754 | \enum QQuickWindow::SceneGraphError |
2755 | |
2756 | This enum describes the error in a sceneGraphError() signal. |
2757 | |
2758 | \value ContextNotAvailable graphics context creation failed. This typically means that |
2759 | no suitable OpenGL implementation was found, for example because no graphics drivers |
2760 | are installed and so no OpenGL 2 support is present. On mobile and embedded boards |
2761 | that use OpenGL ES such an error is likely to indicate issues in the windowing system |
2762 | integration and possibly an incorrect configuration of Qt. |
2763 | |
2764 | \since 5.3 |
2765 | */ |
2766 | |
2767 | /*! |
2768 | \enum QQuickWindow::TextRenderType |
2769 | \since 5.10 |
2770 | |
2771 | This enum describes the default render type of text-like elements in Qt |
2772 | Quick (\l Text, \l TextInput, etc.). |
2773 | |
2774 | Select NativeTextRendering if you prefer text to look native on the target |
2775 | platform and do not require advanced features such as transformation of the |
2776 | text. Using such features in combination with the NativeTextRendering |
2777 | render type will lend poor and sometimes pixelated results. |
2778 | |
2779 | Both \c QtTextRendering and \c CurveTextRendering are hardware-accelerated techniques. |
2780 | \c QtTextRendering is the faster of the two, but uses more memory and will exhibit rendering |
2781 | artifacts at large sizes. \c CurveTextRendering should be considered as an alternative in cases |
2782 | where \c QtTextRendering does not give good visual results or where reducing graphics memory |
2783 | consumption is a priority. |
2784 | |
2785 | \value QtTextRendering Use Qt's own rasterization algorithm. |
2786 | \value NativeTextRendering Use the operating system's native rasterizer for text. |
2787 | \value CurveTextRendering Text is rendered using a curve rasterizer running directly on |
2788 | the graphics hardware. (Introduced in Qt 6.7.0.) |
2789 | */ |
2790 | |
2791 | /*! |
2792 | \fn void QQuickWindow::beforeSynchronizing() |
2793 | |
2794 | This signal is emitted before the scene graph is synchronized with the QML state. |
2795 | |
2796 | Even though the signal is emitted from the scene graph rendering thread, |
2797 | the GUI thread is guaranteed to be blocked, like it is in |
2798 | QQuickItem::updatePaintNode(). Therefore, it is safe to access GUI thread |
2799 | thread data in a slot or lambda that is connected with |
2800 | Qt::DirectConnection. |
2801 | |
2802 | This signal can be used to do any preparation required before calls to |
2803 | QQuickItem::updatePaintNode(). |
2804 | |
2805 | When using OpenGL, the QOpenGLContext used for rendering by the scene graph |
2806 | will be bound at this point. |
2807 | |
2808 | \warning This signal is emitted from the scene graph rendering thread. If your |
2809 | slot function needs to finish before execution continues, you must make sure that |
2810 | the connection is direct (see Qt::ConnectionType). |
2811 | |
2812 | \warning When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific |
2813 | states and leaving these enabled or set to non-default values when returning |
2814 | from the connected slot can interfere with the scene graph's rendering. |
2815 | */ |
2816 | |
2817 | /*! |
2818 | \qmlsignal QtQuick::Window::beforeSynchronizing() |
2819 | \internal |
2820 | */ |
2821 | |
2822 | /*! |
2823 | \fn void QQuickWindow::afterSynchronizing() |
2824 | |
2825 | This signal is emitted after the scene graph is synchronized with the QML state. |
2826 | |
2827 | This signal can be used to do preparation required after calls to |
2828 | QQuickItem::updatePaintNode(), while the GUI thread is still locked. |
2829 | |
2830 | When using OpenGL, the QOpenGLContext used for rendering by the scene graph |
2831 | will be bound at this point. |
2832 | |
2833 | \warning This signal is emitted from the scene graph rendering thread. If your |
2834 | slot function needs to finish before execution continues, you must make sure that |
2835 | the connection is direct (see Qt::ConnectionType). |
2836 | |
2837 | \warning When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific |
2838 | states and leaving these enabled or set to non-default values when returning |
2839 | from the connected slot can interfere with the scene graph's rendering. |
2840 | |
2841 | \since 5.3 |
2842 | */ |
2843 | |
2844 | /*! |
2845 | \qmlsignal QtQuick::Window::afterSynchronizing() |
2846 | \internal |
2847 | \since 5.3 |
2848 | */ |
2849 | |
2850 | /*! |
2851 | \fn void QQuickWindow::beforeRendering() |
2852 | |
2853 | This signal is emitted after the preparations for the frame have been done, |
2854 | meaning there is a command buffer in recording mode, where applicable. If |
2855 | desired, the slot function connected to this signal can query native |
2856 | resources like the command before via QSGRendererInterface. Note however |
2857 | that the recording of the main render pass is not yet started at this point |
2858 | and it is not possible to add commands within that pass. Starting a pass |
2859 | means clearing the color, depth, and stencil buffers so it is not possible |
2860 | to achieve an underlay type of rendering by just connecting to this |
2861 | signal. Rather, connect to beforeRenderPassRecording(). However, connecting |
2862 | to this signal is still important if the recording of copy type of commands |
2863 | is desired since those cannot be enqueued within a render pass. |
2864 | |
2865 | \warning This signal is emitted from the scene graph rendering thread. If your |
2866 | slot function needs to finish before execution continues, you must make sure that |
2867 | the connection is direct (see Qt::ConnectionType). |
2868 | |
2869 | \note When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific |
2870 | states and leaving these enabled or set to non-default values when |
2871 | returning from the connected slot can interfere with the scene graph's |
2872 | rendering. The QOpenGLContext used for rendering by the scene graph will be |
2873 | bound when the signal is emitted. |
2874 | |
2875 | \sa rendererInterface(), {Scene Graph - RHI Under QML}, {Scene Graph - |
2876 | OpenGL Under QML}, {Scene Graph - Metal Under QML}, {Scene Graph - Vulkan |
2877 | Under QML}, {Scene Graph - Direct3D 11 Under QML} |
2878 | */ |
2879 | |
2880 | /*! |
2881 | \qmlsignal QtQuick::Window::beforeRendering() |
2882 | \internal |
2883 | */ |
2884 | |
2885 | /*! |
2886 | \fn void QQuickWindow::afterRendering() |
2887 | |
2888 | The signal is emitted after scene graph has added its commands to the |
2889 | command buffer, which is not yet submitted to the graphics queue. If |
2890 | desired, the slot function connected to this signal can query native |
2891 | resources, like the command buffer, before via QSGRendererInterface. Note |
2892 | however that the render pass (or passes) are already recorded at this point |
2893 | and it is not possible to add more commands within the scenegraph's |
2894 | pass. Instead, use afterRenderPassRecording() for that. This signal has |
2895 | therefore limited use in Qt 6, unlike in Qt 5. Rather, it is the combination |
2896 | of beforeRendering() and beforeRenderPassRecording(), or beforeRendering() |
2897 | and afterRenderPassRecording(), that is typically used to achieve under- or |
2898 | overlaying of the custom rendering. |
2899 | |
2900 | \warning This signal is emitted from the scene graph rendering thread. If your |
2901 | slot function needs to finish before execution continues, you must make sure that |
2902 | the connection is direct (see Qt::ConnectionType). |
2903 | |
2904 | \note When using OpenGL, be aware that setting OpenGL 3.x or 4.x specific |
2905 | states and leaving these enabled or set to non-default values when |
2906 | returning from the connected slot can interfere with the scene graph's |
2907 | rendering. The QOpenGLContext used for rendering by the scene graph will be |
2908 | bound when the signal is emitted. |
2909 | |
2910 | \sa rendererInterface(), {Scene Graph - RHI Under QML}, {Scene Graph - |
2911 | OpenGL Under QML}, {Scene Graph - Metal Under QML}, {Scene Graph - Vulkan |
2912 | Under QML}, {Scene Graph - Direct3D 11 Under QML} |
2913 | */ |
2914 | |
2915 | /*! |
2916 | \qmlsignal QtQuick::Window::afterRendering() |
2917 | \internal |
2918 | */ |
2919 | |
2920 | /*! |
2921 | \fn void QQuickWindow::beforeRenderPassRecording() |
2922 | |
2923 | This signal is emitted before the scenegraph starts recording commands for |
2924 | the main render pass. (Layers have their own passes and are fully recorded |
2925 | by the time this signal is emitted.) The render pass is already active on |
2926 | the command buffer when the signal is emitted. |
2927 | |
2928 | This signal is emitted later than beforeRendering() and it guarantees that |
2929 | not just the frame, but also the recording of the scenegraph's main render |
2930 | pass is active. This allows inserting commands without having to generate an |
2931 | entire, separate render pass (which would typically clear the attached |
2932 | images). The native graphics objects can be queried via |
2933 | QSGRendererInterface. |
2934 | |
2935 | \note Resource updates (uploads, copies) typically cannot be enqueued from |
2936 | within a render pass. Therefore, more complex user rendering will need to |
2937 | connect to both beforeRendering() and this signal. |
2938 | |
2939 | \warning This signal is emitted from the scene graph rendering thread. If your |
2940 | slot function needs to finish before execution continues, you must make sure that |
2941 | the connection is direct (see Qt::ConnectionType). |
2942 | |
2943 | \sa rendererInterface() |
2944 | |
2945 | \since 5.14 |
2946 | |
2947 | \sa {Scene Graph - RHI Under QML} |
2948 | */ |
2949 | |
2950 | /*! |
2951 | \qmlsignal QtQuick::Window::beforeRenderPassRecording() |
2952 | \internal |
2953 | \since 5.14 |
2954 | */ |
2955 | |
2956 | /*! |
2957 | \fn void QQuickWindow::afterRenderPassRecording() |
2958 | |
2959 | This signal is emitted after the scenegraph has recorded the commands for |
2960 | its main render pass, but the pass is not yet finalized on the command |
2961 | buffer. |
2962 | |
2963 | This signal is emitted earlier than afterRendering(), and it guarantees that |
2964 | not just the frame but also the recording of the scenegraph's main render |
2965 | pass is still active. This allows inserting commands without having to |
2966 | generate an entire, separate render pass (which would typically clear the |
2967 | attached images). The native graphics objects can be queried via |
2968 | QSGRendererInterface. |
2969 | |
2970 | \note Resource updates (uploads, copies) typically cannot be enqueued from |
2971 | within a render pass. Therefore, more complex user rendering will need to |
2972 | connect to both beforeRendering() and this signal. |
2973 | |
2974 | \warning This signal is emitted from the scene graph rendering thread. If your |
2975 | slot function needs to finish before execution continues, you must make sure that |
2976 | the connection is direct (see Qt::ConnectionType). |
2977 | |
2978 | \sa rendererInterface() |
2979 | |
2980 | \since 5.14 |
2981 | |
2982 | \sa {Scene Graph - RHI Under QML} |
2983 | */ |
2984 | |
2985 | /*! |
2986 | \fn void QQuickWindow::beforeFrameBegin() |
2987 | |
2988 | This signal is emitted before the scene graph starts preparing the frame. |
2989 | This precedes signals like beforeSynchronizing() or beforeRendering(). It is |
2990 | the earliest signal that is emitted by the scene graph rendering thread |
2991 | when starting to prepare a new frame. |
2992 | |
2993 | This signal is relevant for lower level graphics frameworks that need to |
2994 | execute certain operations, such as resource cleanup, at a stage where Qt |
2995 | Quick has not initiated the recording of a new frame via the underlying |
2996 | rendering hardware interface APIs. |
2997 | |
2998 | \warning This signal is emitted from the scene graph rendering thread. If your |
2999 | slot function needs to finish before execution continues, you must make sure that |
3000 | the connection is direct (see Qt::ConnectionType). |
3001 | |
3002 | \since 6.0 |
3003 | |
3004 | \sa afterFrameEnd(), rendererInterface() |
3005 | */ |
3006 | |
3007 | /*! |
3008 | \qmlsignal QtQuick::Window::beforeFrameBegin() |
3009 | \internal |
3010 | */ |
3011 | |
3012 | /*! |
3013 | \fn void QQuickWindow::afterFrameEnd() |
3014 | |
3015 | This signal is emitted when the scene graph has submitted a frame. This is |
3016 | emitted after all other related signals, such as afterRendering(). It is |
3017 | the last signal that is emitted by the scene graph rendering thread when |
3018 | rendering a frame. |
3019 | |
3020 | \note Unlike frameSwapped(), this signal is guaranteed to be emitted also |
3021 | when the Qt Quick output is redirected via QQuickRenderControl. |
3022 | |
3023 | \warning This signal is emitted from the scene graph rendering thread. If your |
3024 | slot function needs to finish before execution continues, you must make sure that |
3025 | the connection is direct (see Qt::ConnectionType). |
3026 | |
3027 | \since 6.0 |
3028 | |
3029 | \sa beforeFrameBegin(), rendererInterface() |
3030 | */ |
3031 | |
3032 | /*! |
3033 | \qmlsignal QtQuick::Window::afterFrameEnd() |
3034 | \internal |
3035 | */ |
3036 | |
3037 | /*! |
3038 | \qmlsignal QtQuick::Window::afterRenderPassRecording() |
3039 | \internal |
3040 | \since 5.14 |
3041 | */ |
3042 | |
3043 | /*! |
3044 | \fn void QQuickWindow::afterAnimating() |
3045 | |
3046 | This signal is emitted on the GUI thread before requesting the render thread to |
3047 | perform the synchronization of the scene graph. |
3048 | |
3049 | Unlike the other similar signals, this one is emitted on the GUI thread |
3050 | instead of the render thread. It can be used to synchronize external |
3051 | animation systems with the QML content. At the same time this means that |
3052 | this signal is not suitable for triggering graphics operations. |
3053 | |
3054 | \since 5.3 |
3055 | */ |
3056 | |
3057 | /*! |
3058 | \qmlsignal QtQuick::Window::afterAnimating() |
3059 | |
3060 | This signal is emitted on the GUI thread before requesting the render thread to |
3061 | perform the synchronization of the scene graph. |
3062 | |
3063 | You can implement onAfterAnimating to do additional processing after each animation step. |
3064 | |
3065 | \since 5.3 |
3066 | */ |
3067 | |
3068 | /*! |
3069 | \fn void QQuickWindow::sceneGraphAboutToStop() |
3070 | |
3071 | This signal is emitted on the render thread when the scene graph is |
3072 | about to stop rendering. This happens usually because the window |
3073 | has been hidden. |
3074 | |
3075 | Applications may use this signal to release resources, but should be |
3076 | prepared to reinstantiated them again fast. The scene graph and the |
3077 | graphics context are not released at this time. |
3078 | |
3079 | \warning This signal is emitted from the scene graph rendering thread. If your |
3080 | slot function needs to finish before execution continues, you must make sure that |
3081 | the connection is direct (see Qt::ConnectionType). |
3082 | |
3083 | \warning Make very sure that a signal handler for sceneGraphAboutToStop() leaves the |
3084 | graphics context in the same state as it was when the signal handler was entered. |
3085 | Failing to do so can result in the scene not rendering properly. |
3086 | |
3087 | \sa sceneGraphInvalidated() |
3088 | \since 5.3 |
3089 | */ |
3090 | |
3091 | /*! |
3092 | \qmlsignal QtQuick::Window::sceneGraphAboutToStop() |
3093 | \internal |
3094 | \since 5.3 |
3095 | */ |
3096 | |
3097 | /*! |
3098 | \overload |
3099 | */ |
3100 | |
3101 | QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const |
3102 | { |
3103 | return createTextureFromImage(image, options: {}); |
3104 | } |
3105 | |
3106 | |
3107 | /*! |
3108 | Creates a new QSGTexture from the supplied \a image. If the image has an |
3109 | alpha channel, the corresponding texture will have an alpha channel. |
3110 | |
3111 | The caller of the function is responsible for deleting the returned texture. |
3112 | The underlying native texture object is then destroyed together with the |
3113 | QSGTexture. |
3114 | |
3115 | When \a options contains TextureCanUseAtlas, the engine may put the image |
3116 | into a texture atlas. Textures in an atlas need to rely on |
3117 | QSGTexture::normalizedTextureSubRect() for their geometry and will not |
3118 | support QSGTexture::Repeat. Other values from CreateTextureOption are |
3119 | ignored. |
3120 | |
3121 | When \a options contains TextureIsOpaque, the engine will create an RGB |
3122 | texture which returns false for QSGTexture::hasAlphaChannel(). Opaque |
3123 | textures will in most cases be faster to render. When this flag is not set, |
3124 | the texture will have an alpha channel based on the image's format. |
3125 | |
3126 | When \a options contains TextureHasMipmaps, the engine will create a texture |
3127 | which can use mipmap filtering. Mipmapped textures can not be in an atlas. |
3128 | |
3129 | Setting TextureHasAlphaChannel in \a options serves no purpose for this |
3130 | function since assuming an alpha channel and blending is the default. To opt |
3131 | out, set TextureIsOpaque. |
3132 | |
3133 | When the scene graph uses OpenGL, the returned texture will be using \c |
3134 | GL_TEXTURE_2D as texture target and \c GL_RGBA as internal format. With |
3135 | other graphics APIs, the texture format is typically \c RGBA8. Reimplement |
3136 | QSGTexture to create textures with different parameters. |
3137 | |
3138 | \warning This function will return 0 if the scene graph has not yet been |
3139 | initialized. |
3140 | |
3141 | \warning The returned texture is not memory managed by the scene graph and |
3142 | must be explicitly deleted by the caller on the rendering thread. This is |
3143 | achieved by deleting the texture from a QSGNode destructor or by using |
3144 | deleteLater() in the case where the texture already has affinity to the |
3145 | rendering thread. |
3146 | |
3147 | This function can be called from both the main and the render thread. |
3148 | |
3149 | \sa sceneGraphInitialized(), QSGTexture |
3150 | */ |
3151 | |
3152 | QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const |
3153 | { |
3154 | Q_D(const QQuickWindow); |
3155 | if (!isSceneGraphInitialized()) // check both for d->context and d->context->isValid() |
3156 | return nullptr; |
3157 | uint flags = 0; |
3158 | if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; |
3159 | if (options & TextureHasMipmaps) flags |= QSGRenderContext::CreateTexture_Mipmap; |
3160 | if (!(options & TextureIsOpaque)) flags |= QSGRenderContext::CreateTexture_Alpha; |
3161 | return d->context->createTexture(image, flags); |
3162 | } |
3163 | |
3164 | /*! |
3165 | Creates a new QSGTexture from the supplied \a texture. |
3166 | |
3167 | Use \a options to customize the texture attributes. Only the |
3168 | TextureHasAlphaChannel flag is taken into account by this function. When |
3169 | set, the resulting QSGTexture is always treated by the scene graph renderer |
3170 | as needing blending. For textures that are fully opaque, not setting the |
3171 | flag can save the cost of performing alpha blending during rendering. The |
3172 | flag has no direct correspondence to the \l{QRhiTexture::format()}{format} |
3173 | of the QRhiTexture, i.e. not setting the flag while having a texture format |
3174 | such as the commonly used \l QRhiTexture::RGBA8 is perfectly normal. |
3175 | |
3176 | Mipmapping is not controlled by \a options since \a texture is already |
3177 | created and has the presence or lack of mipmaps baked in. |
3178 | |
3179 | The returned QSGTexture owns the QRhiTexture, meaning \a texture is |
3180 | destroyed together with the returned QSGTexture. |
3181 | |
3182 | If \a texture owns its underlying native graphics resources (OpenGL texture |
3183 | object, Vulkan image, etc.), that depends on how the QRhiTexture was created |
3184 | (\l{QRhiTexture::create()} or \l{QRhiTexture::createFrom()}), and that is |
3185 | not controlled or changed by this function. |
3186 | |
3187 | \note This is only functional when the scene graph has already initialized |
3188 | and is using the default, \l{QRhi}-based \l{Scene Graph |
3189 | Adaptations}{adaptation}. The return value is \nullptr otherwise. |
3190 | |
3191 | \note This function can only be called on the scene graph render thread. |
3192 | |
3193 | \since 6.6 |
3194 | |
3195 | \sa createTextureFromImage(), sceneGraphInitialized(), QSGTexture |
3196 | */ |
3197 | QSGTexture *QQuickWindow::createTextureFromRhiTexture(QRhiTexture *texture, CreateTextureOptions options) const |
3198 | { |
3199 | Q_D(const QQuickWindow); |
3200 | if (!d->rhi) |
3201 | return nullptr; |
3202 | |
3203 | QSGPlainTexture *t = new QSGPlainTexture; |
3204 | t->setOwnsTexture(true); |
3205 | t->setTexture(texture); |
3206 | t->setHasAlphaChannel(options & QQuickWindow::TextureHasAlphaChannel); |
3207 | t->setTextureSize(texture->pixelSize()); |
3208 | return t; |
3209 | } |
3210 | |
3211 | // Legacy, private alternative to createTextureFromRhiTexture() that internally |
3212 | // creates a QRhiTexture wrapping the existing native graphics resource. |
3213 | // New code should prefer using the public API. |
3214 | QSGTexture *QQuickWindowPrivate::createTextureFromNativeTexture(quint64 nativeObjectHandle, |
3215 | int nativeLayoutOrState, |
3216 | uint nativeFormat, |
3217 | const QSize &size, |
3218 | QQuickWindow::CreateTextureOptions options, |
3219 | TextureFromNativeTextureFlags flags) const |
3220 | { |
3221 | if (!rhi) |
3222 | return nullptr; |
3223 | |
3224 | QSGPlainTexture *texture = new QSGPlainTexture; |
3225 | texture->setTextureFromNativeTexture(rhi, nativeObjectHandle, nativeLayoutOrState, nativeFormat, |
3226 | size, options, flags); |
3227 | texture->setHasAlphaChannel(options & QQuickWindow::TextureHasAlphaChannel); |
3228 | // note that the QRhiTexture does not (and cannot) own the native object |
3229 | texture->setOwnsTexture(true); // texture meaning the QRhiTexture here, not the native object |
3230 | texture->setTextureSize(size); |
3231 | return texture; |
3232 | } |
3233 | |
3234 | /*! |
3235 | \qmlproperty color Window::color |
3236 | |
3237 | The background color for the window. |
3238 | |
3239 | Setting this property is more efficient than using a separate Rectangle. |
3240 | |
3241 | \note If you set the color to \c "transparent" or to a color with alpha translucency, |
3242 | you should also set suitable \l flags such as \c {flags: Qt.FramelessWindowHint}. |
3243 | Otherwise, window translucency may not be enabled consistently on all platforms. |
3244 | */ |
3245 | |
3246 | /*! |
3247 | \property QQuickWindow::color |
3248 | \brief The color used to clear the color buffer at the beginning of each frame. |
3249 | |
3250 | By default, the clear color is white. |
3251 | |
3252 | \sa setDefaultAlphaBuffer() |
3253 | */ |
3254 | |
3255 | void QQuickWindow::setColor(const QColor &color) |
3256 | { |
3257 | Q_D(QQuickWindow); |
3258 | if (color == d->clearColor) |
3259 | return; |
3260 | |
3261 | if (color.alpha() != d->clearColor.alpha()) { |
3262 | QSurfaceFormat fmt = requestedFormat(); |
3263 | if (color.alpha() < 255) |
3264 | fmt.setAlphaBufferSize(8); |
3265 | else |
3266 | fmt.setAlphaBufferSize(-1); |
3267 | setFormat(fmt); |
3268 | } |
3269 | d->clearColor = color; |
3270 | emit colorChanged(color); |
3271 | update(); |
3272 | } |
3273 | |
3274 | QColor QQuickWindow::color() const |
3275 | { |
3276 | return d_func()->clearColor; |
3277 | } |
3278 | |
3279 | /*! |
3280 | \brief Returns whether to use alpha transparency on newly created windows. |
3281 | |
3282 | \since 5.1 |
3283 | \sa setDefaultAlphaBuffer() |
3284 | */ |
3285 | bool QQuickWindow::hasDefaultAlphaBuffer() |
3286 | { |
3287 | return QQuickWindowPrivate::defaultAlphaBuffer; |
3288 | } |
3289 | |
3290 | /*! |
3291 | \brief \a useAlpha specifies whether to use alpha transparency on newly created windows. |
3292 | \since 5.1 |
3293 | |
3294 | In any application which expects to create translucent windows, it's necessary to set |
3295 | this to true before creating the first QQuickWindow. The default value is false. |
3296 | |
3297 | \sa hasDefaultAlphaBuffer() |
3298 | */ |
3299 | void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha) |
3300 | { |
3301 | QQuickWindowPrivate::defaultAlphaBuffer = useAlpha; |
3302 | } |
3303 | |
3304 | /*! |
3305 | \struct QQuickWindow::GraphicsStateInfo |
3306 | \inmodule QtQuick |
3307 | \since 5.14 |
3308 | |
3309 | \brief Describes some of the RHI's graphics state at the point of a |
3310 | \l{QQuickWindow::beginExternalCommands()}{beginExternalCommands()} call. |
3311 | */ |
3312 | |
3313 | /*! |
3314 | \variable QQuickWindow::GraphicsStateInfo::currentFrameSlot |
3315 | \since 5.14 |
3316 | \brief the current frame slot index while recording a frame. |
3317 | |
3318 | When the scenegraph renders with lower level 3D APIs such as Vulkan or |
3319 | Metal, it is the Qt's responsibility to ensure blocking whenever starting a |
3320 | new frame and finding the CPU is already a certain number of frames ahead |
3321 | of the GPU (because the command buffer submitted in frame no. \c{current} - |
3322 | \c{FramesInFlight} has not yet completed). With other graphics APIs, such |
3323 | as OpenGL or Direct 3D 11 this level of control is not exposed to the API |
3324 | client but rather handled by the implementation of the graphics API. |
3325 | |
3326 | By extension, this also means that the appropriate double (or triple) |
3327 | buffering of resources, such as buffers, is up to the graphics API client |
3328 | to manage. Most commonly, a uniform buffer where the data changes between |
3329 | frames cannot simply change its contents when submitting a frame, given |
3330 | that the frame may still be active ("in flight") when starting to record |
3331 | the next frame. To avoid stalling the pipeline, one way is to have multiple |
3332 | buffers (and memory allocations) under the hood, thus realizing at least a |
3333 | double buffered scheme for such resources. |
3334 | |
3335 | Applications that integrate rendering done directly with a graphics API |
3336 | such as Vulkan may want to perform a similar double or triple buffering of |
3337 | their own graphics resources, in a way that is compatible with the Qt |
3338 | rendering engine's frame submission process. That then involves knowing the |
3339 | values for the maximum number of in-flight frames (which is typically 2 or |
3340 | 3) and the current frame slot index, which is a number running 0, 1, .., |
3341 | FramesInFlight-1, and then wrapping around. The former is exposed in the |
3342 | \l{QQuickWindow::GraphicsStateInfo::framesInFlight}{framesInFlight} |
3343 | variable. The latter, current index, is this value. |
3344 | |
3345 | For an example of using these values in practice, refer to the {Scene Graph |
3346 | - Vulkan Under QML} and {Scene Graph - Vulkan Texture Import} examples. |
3347 | */ |
3348 | |
3349 | /*! |
3350 | \variable QQuickWindow::GraphicsStateInfo::framesInFlight |
3351 | \since 5.14 |
3352 | \brief the maximum number of frames kept in flight. |
3353 | |
3354 | See \l{QQuickWindow::GraphicsStateInfo::currentFrameSlot}{currentFrameSlot} |
3355 | for a detailed description. |
3356 | */ |
3357 | |
3358 | /*! |
3359 | \return a reference to a GraphicsStateInfo struct describing some of the |
3360 | RHI's internal state, in particular, the double or tripple buffering status |
3361 | of the backend (such as, the Vulkan or Metal integrations). This is |
3362 | relevant when the underlying graphics APIs is Vulkan or Metal, and the |
3363 | external rendering code wishes to perform double or tripple buffering of |
3364 | its own often-changing resources, such as, uniform buffers, in order to |
3365 | avoid stalling the pipeline. |
3366 | */ |
3367 | const QQuickWindow::GraphicsStateInfo &QQuickWindow::graphicsStateInfo() |
3368 | { |
3369 | Q_D(QQuickWindow); |
3370 | if (d->rhi) { |
3371 | d->rhiStateInfo.currentFrameSlot = d->rhi->currentFrameSlot(); |
3372 | d->rhiStateInfo.framesInFlight = d->rhi->resourceLimit(limit: QRhi::FramesInFlight); |
3373 | } |
3374 | return d->rhiStateInfo; |
3375 | } |
3376 | |
3377 | /*! |
3378 | When mixing raw graphics (OpenGL, Vulkan, Metal, etc.) commands with scene |
3379 | graph rendering, it is necessary to call this function before recording |
3380 | commands to the command buffer used by the scene graph to render its main |
3381 | render pass. This is to avoid clobbering state. |
3382 | |
3383 | In practice this function is often called from a slot connected to the |
3384 | beforeRenderPassRecording() or afterRenderPassRecording() signals. |
3385 | |
3386 | The function does not need to be called when recording commands to the |
3387 | application's own command buffer (such as, a VkCommandBuffer or |
3388 | MTLCommandBuffer + MTLRenderCommandEncoder created and managed by the |
3389 | application, not retrieved from the scene graph). With graphics APIs where |
3390 | no native command buffer concept is exposed (OpenGL, Direct 3D 11), |
3391 | beginExternalCommands() and endExternalCommands() together provide a |
3392 | replacement for the Qt 5 resetOpenGLState() function. |
3393 | |
3394 | Calling this function and endExternalCommands() is not necessary within the |
3395 | \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode |
3396 | because the scene graph performs the necessary steps implicitly for render |
3397 | nodes. |
3398 | |
3399 | Native graphics objects (such as, graphics device, command buffer or |
3400 | encoder) are accessible via QSGRendererInterface::getResource(). |
3401 | |
3402 | \warning Watch out for the fact that |
3403 | QSGRendererInterface::CommandListResource may return a different object |
3404 | between beginExternalCommands() - endExternalCommands(). This can happen |
3405 | when the underlying implementation provides a dedicated secondary command |
3406 | buffer for recording external graphics commands within a render pass. |
3407 | Therefore, always query CommandListResource after calling this function. Do |
3408 | not attempt to reuse an object from an earlier query. |
3409 | |
3410 | \note When the scenegraph is using OpenGL, pay attention to the fact that |
3411 | the OpenGL state in the context can have arbitrary settings, and this |
3412 | function does not perform any resetting of the state back to defaults. |
3413 | |
3414 | \sa endExternalCommands(), QQuickOpenGLUtils::resetOpenGLState() |
3415 | |
3416 | \since 5.14 |
3417 | */ |
3418 | void QQuickWindow::beginExternalCommands() |
3419 | { |
3420 | Q_D(QQuickWindow); |
3421 | if (d->rhi && d->context && d->context->isValid()) { |
3422 | QSGDefaultRenderContext *rc = static_cast<QSGDefaultRenderContext *>(d->context); |
3423 | QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer(); |
3424 | if (cb) |
3425 | cb->beginExternal(); |
3426 | } |
3427 | } |
3428 | |
3429 | /*! |
3430 | When mixing raw graphics (OpenGL, Vulkan, Metal, etc.) commands with scene |
3431 | graph rendering, it is necessary to call this function after recording |
3432 | commands to the command buffer used by the scene graph to render its main |
3433 | render pass. This is to avoid clobbering state. |
3434 | |
3435 | In practice this function is often called from a slot connected to the |
3436 | beforeRenderPassRecording() or afterRenderPassRecording() signals. |
3437 | |
3438 | The function does not need to be called when recording commands to the |
3439 | application's own command buffer (such as, a VkCommandBuffer or |
3440 | MTLCommandBuffer + MTLRenderCommandEncoder created and managed by the |
3441 | application, not retrieved from the scene graph). With graphics APIs where |
3442 | no native command buffer concept is exposed (OpenGL, Direct 3D 11), |
3443 | beginExternalCommands() and endExternalCommands() together provide a |
3444 | replacement for the Qt 5 resetOpenGLState() function. |
3445 | |
3446 | Calling this function and beginExternalCommands() is not necessary within the |
3447 | \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode |
3448 | because the scene graph performs the necessary steps implicitly for render |
3449 | nodes. |
3450 | |
3451 | \sa beginExternalCommands(), QQuickOpenGLUtils::resetOpenGLState() |
3452 | |
3453 | \since 5.14 |
3454 | */ |
3455 | void QQuickWindow::endExternalCommands() |
3456 | { |
3457 | Q_D(QQuickWindow); |
3458 | if (d->rhi && d->context && d->context->isValid()) { |
3459 | QSGDefaultRenderContext *rc = static_cast<QSGDefaultRenderContext *>(d->context); |
3460 | QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer(); |
3461 | if (cb) |
3462 | cb->endExternal(); |
3463 | } |
3464 | } |
3465 | |
3466 | /*! |
3467 | \qmlproperty string Window::title |
3468 | |
3469 | The window's title in the windowing system. |
3470 | |
3471 | The window title might appear in the title area of the window decorations, |
3472 | depending on the windowing system and the window flags. It might also |
3473 | be used by the windowing system to identify the window in other contexts, |
3474 | such as in the task switcher. |
3475 | */ |
3476 | |
3477 | /*! |
3478 | \qmlproperty Qt::WindowModality Window::modality |
3479 | |
3480 | The modality of the window. |
3481 | |
3482 | A modal window prevents other windows from receiving input events. |
3483 | Possible values are Qt.NonModal (the default), Qt.WindowModal, |
3484 | and Qt.ApplicationModal. |
3485 | */ |
3486 | |
3487 | /*! |
3488 | \qmlproperty Qt::WindowFlags Window::flags |
3489 | |
3490 | The window flags of the window. |
3491 | |
3492 | The window flags control the window's appearance in the windowing system, |
3493 | whether it's a dialog, popup, or a regular window, and whether it should |
3494 | have a title bar, etc. |
3495 | |
3496 | The flags that you read from this property might differ from the ones |
3497 | that you set if the requested flags could not be fulfilled. |
3498 | |
3499 | \snippet qml/splashWindow.qml entire |
3500 | |
3501 | \sa Qt::WindowFlags, {Qt Quick Examples - Window and Screen} |
3502 | */ |
3503 | |
3504 | /*! |
3505 | \qmlattachedproperty Window Window::window |
3506 | \since 5.7 |
3507 | |
3508 | This attached property holds the item's window. |
3509 | The Window attached property can be attached to any Item. |
3510 | */ |
3511 | |
3512 | /*! |
3513 | \qmlattachedproperty int Window::width |
3514 | \qmlattachedproperty int Window::height |
3515 | \since 5.5 |
3516 | |
3517 | These attached properties hold the size of the item's window. |
3518 | The Window attached property can be attached to any Item. |
3519 | */ |
3520 | |
3521 | /*! |
3522 | \qmlproperty int Window::x |
3523 | \qmlproperty int Window::y |
3524 | \qmlproperty int Window::width |
3525 | \qmlproperty int Window::height |
3526 | |
3527 | Defines the window's position and size. |
3528 | |
3529 | The (x,y) position is relative to the \l Screen if there is only one, |
3530 | or to the virtual desktop (arrangement of multiple screens). |
3531 | |
3532 | \note Not all windowing systems support setting or querying top level |
3533 | window positions. On such a system, programmatically moving windows |
3534 | may not have any effect, and artificial values may be returned for |
3535 | the current positions, such as \c QPoint(0, 0). |
3536 | |
3537 | \qml |
3538 | Window { x: 100; y: 100; width: 100; height: 100 } |
3539 | \endqml |
3540 | |
3541 | \image screen-and-window-dimensions.jpg |
3542 | */ |
3543 | |
3544 | /*! |
3545 | \qmlproperty int Window::minimumWidth |
3546 | \qmlproperty int Window::minimumHeight |
3547 | \since 5.1 |
3548 | |
3549 | Defines the window's minimum size. |
3550 | |
3551 | This is a hint to the window manager to prevent resizing below the specified |
3552 | width and height. |
3553 | */ |
3554 | |
3555 | /*! |
3556 | \qmlproperty int Window::maximumWidth |
3557 | \qmlproperty int Window::maximumHeight |
3558 | \since 5.1 |
3559 | |
3560 | Defines the window's maximum size. |
3561 | |
3562 | This is a hint to the window manager to prevent resizing above the specified |
3563 | width and height. |
3564 | */ |
3565 | |
3566 | /*! |
3567 | \qmlproperty bool Window::visible |
3568 | |
3569 | Whether the window is visible on the screen. |
3570 | |
3571 | Setting visible to false is the same as setting \l visibility to \l {QWindow::}{Hidden}. |
3572 | |
3573 | The default value is \c false, unless overridden by setting \l visibility. |
3574 | |
3575 | \sa visibility |
3576 | */ |
3577 | |
3578 | /*! |
3579 | \keyword qml-window-visibility-prop |
3580 | \qmlproperty QWindow::Visibility Window::visibility |
3581 | |
3582 | The screen-occupation state of the window. |
3583 | |
3584 | Visibility is whether the window should appear in the windowing system as |
3585 | normal, minimized, maximized, fullscreen or hidden. |
3586 | |
3587 | To set the visibility to \l {QWindow::}{AutomaticVisibility} means to give the |
3588 | window a default visible state, which might be \l {QWindow::}{FullScreen} or |
3589 | \l {QWindow::}{Windowed} depending on the platform. However when reading the |
3590 | visibility property you will always get the actual state, never |
3591 | \c AutomaticVisibility. |
3592 | |
3593 | When a window is not visible, its visibility is \c Hidden, and setting |
3594 | visibility to \l {QWindow::}{Hidden} is the same as setting \l visible to \c false. |
3595 | |
3596 | \snippet qml/windowVisibility.qml entire |
3597 | |
3598 | \sa visible, {Qt Quick Examples - Window and Screen} |
3599 | \since 5.1 |
3600 | */ |
3601 | |
3602 | /*! |
3603 | \qmlattachedproperty QWindow::Visibility Window::visibility |
3604 | \readonly |
3605 | \since 5.4 |
3606 | |
3607 | This attached property holds whether the window is currently shown |
3608 | in the windowing system as normal, minimized, maximized, fullscreen or |
3609 | hidden. The \c Window attached property can be attached to any Item. If the |
3610 | item is not shown in any window, the value will be \l {QWindow::}{Hidden}. |
3611 | |
3612 | \sa visible, {qml-window-visibility-prop}{visibility} |
3613 | */ |
3614 | |
3615 | /*! |
3616 | \qmlproperty Item Window::contentItem |
3617 | \readonly |
3618 | \brief The invisible root item of the scene. |
3619 | */ |
3620 | |
3621 | /*! |
3622 | \qmlproperty Qt::ScreenOrientation Window::contentOrientation |
3623 | |
3624 | This is a hint to the window manager in case it needs to display |
3625 | additional content like popups, dialogs, status bars, or similar |
3626 | in relation to the window. |
3627 | |
3628 | The recommended orientation is \l {Screen::orientation}{Screen.orientation}, but |
3629 | an application doesn't have to support all possible orientations, |
3630 | and thus can opt to ignore the current screen orientation. |
3631 | |
3632 | The difference between the window and the content orientation |
3633 | determines how much to rotate the content by. |
3634 | |
3635 | The default value is Qt::PrimaryOrientation. |
3636 | |
3637 | \sa Screen |
3638 | |
3639 | \since 5.1 |
3640 | */ |
3641 | |
3642 | /*! |
3643 | \qmlproperty real Window::opacity |
3644 | |
3645 | The opacity of the window. |
3646 | |
3647 | If the windowing system supports window opacity, this can be used to fade the |
3648 | window in and out, or to make it semitransparent. |
3649 | |
3650 | A value of 1.0 or above is treated as fully opaque, whereas a value of 0.0 or below |
3651 | is treated as fully transparent. Values inbetween represent varying levels of |
3652 | translucency between the two extremes. |
3653 | |
3654 | The default value is 1.0. |
3655 | |
3656 | \since 5.1 |
3657 | */ |
3658 | |
3659 | /*! |
3660 | \qmlproperty variant Window::screen |
3661 | |
3662 | The screen with which the window is associated. |
3663 | |
3664 | If specified before showing a window, will result in the window being shown |
3665 | on that screen, unless an explicit window position has been set. The value |
3666 | must be an element from the Qt.application.screens array. |
3667 | |
3668 | \note To ensure that the window is associated with the desired screen when |
3669 | the underlying native window is created, make sure this property is set as |
3670 | early as possible and that the setting of its value is not deferred. This |
3671 | can be particularly important on embedded platforms without a windowing system, |
3672 | where only one window per screen is allowed at a time. Setting the screen after |
3673 | a window has been created does not move the window if the new screen is part of |
3674 | the same virtual desktop as the old screen. |
3675 | |
3676 | \since 5.9 |
3677 | |
3678 | \sa QWindow::setScreen(), QWindow::screen(), QScreen, {QtQml::Qt::application}{Qt.application} |
3679 | */ |
3680 | |
3681 | /*! |
3682 | \qmlproperty QWindow Window::transientParent |
3683 | \since 5.13 |
3684 | |
3685 | The window for which this window is a transient pop-up. |
3686 | |
3687 | This is a hint to the window manager that this window is a dialog or pop-up |
3688 | on behalf of the transient parent. It usually means that the transient |
3689 | window will be centered over its transient parent when it is initially |
3690 | shown, that minimizing the parent window will also minimize the transient |
3691 | window, and so on; however results vary somewhat from platform to platform. |
3692 | |
3693 | Declaring a Window inside an Item or another Window, either via the |
3694 | \l{Window::data}{default property} or a dedicated property, will automatically |
3695 | set up a transient parent relationship to the containing window, |
3696 | unless the \l transientParent property is explicitly set. This applies |
3697 | when creating Window items via \l [QML] {QtQml::Qt::createComponent()} |
3698 | {Qt.createComponent} or \l [QML] {QtQml::Qt::createQmlObject()} |
3699 | {Qt.createQmlObject} as well, as long as an Item or Window is passed |
3700 | as the \c parent argument. |
3701 | |
3702 | A Window with a transient parent will not be shown until its transient |
3703 | parent is shown, even if the \l visible property is \c true. This also |
3704 | applies for the automatic transient parent relationship described above. |
3705 | In particular, if the Window's containing element is an Item, the window |
3706 | will not be shown until the containing item is added to a scene, via its |
3707 | \l{Concepts - Visual Parent in Qt Quick}{visual parent hierarchy}. Setting |
3708 | the \l transientParent to \c null will override this behavior: |
3709 | |
3710 | \snippet qml/nestedWindowTransientParent.qml 0 |
3711 | \snippet qml/nestedWindowTransientParent.qml 1 |
3712 | |
3713 | In order to cause the window to be centered above its transient parent by |
3714 | default, depending on the window manager, it may also be necessary to set |
3715 | the \l Window::flags property with a suitable \l Qt::WindowType (such as |
3716 | \c Qt::Dialog). |
3717 | |
3718 | \sa {QQuickWindow::}{parent()} |
3719 | */ |
3720 | |
3721 | /*! |
3722 | \property QQuickWindow::transientParent |
3723 | \brief The window for which this window is a transient pop-up. |
3724 | \since 5.13 |
3725 | |
3726 | This is a hint to the window manager that this window is a dialog or pop-up |
3727 | on behalf of the transient parent, which may be any kind of \l QWindow. |
3728 | |
3729 | In order to cause the window to be centered above its transient parent by |
3730 | default, depending on the window manager, it may also be necessary to set |
3731 | the \l flags property with a suitable \l Qt::WindowType (such as \c Qt::Dialog). |
3732 | |
3733 | \sa parent() |
3734 | */ |
3735 | |
3736 | /*! |
3737 | \qmlproperty Item Window::activeFocusItem |
3738 | \since 5.1 |
3739 | |
3740 | The item which currently has active focus or \c null if there is |
3741 | no item with active focus. |
3742 | */ |
3743 | |
3744 | /*! |
3745 | \qmlattachedproperty Item Window::activeFocusItem |
3746 | \since 5.4 |
3747 | |
3748 | This attached property holds the item which currently has active focus or |
3749 | \c null if there is no item with active focus. The Window attached property |
3750 | can be attached to any Item. |
3751 | */ |
3752 | |
3753 | /*! |
3754 | \qmlproperty bool Window::active |
3755 | \since 5.1 |
3756 | |
3757 | The active status of the window. |
3758 | |
3759 | \snippet qml/windowPalette.qml declaration-and-color |
3760 | \snippet qml/windowPalette.qml closing-brace |
3761 | |
3762 | \sa requestActivate() |
3763 | */ |
3764 | |
3765 | /*! |
3766 | \qmlattachedproperty bool Window::active |
3767 | \since 5.4 |
3768 | |
3769 | This attached property tells whether the window is active. The Window |
3770 | attached property can be attached to any Item. |
3771 | |
3772 | Here is an example which changes a label to show the active state of the |
3773 | window in which it is shown: |
3774 | |
3775 | \snippet qml/windowActiveAttached.qml entire |
3776 | */ |
3777 | |
3778 | /*! |
3779 | \qmlmethod QtQuick::Window::requestActivate() |
3780 | \since 5.1 |
3781 | |
3782 | Requests the window to be activated, i.e. receive keyboard focus. |
3783 | */ |
3784 | |
3785 | /*! |
3786 | \qmlmethod QtQuick::Window::alert(int msec) |
3787 | \since 5.1 |
3788 | |
3789 | Causes an alert to be shown for \a msec milliseconds. If \a msec is \c 0 |
3790 | (the default), then the alert is shown indefinitely until the window |
3791 | becomes active again. |
3792 | |
3793 | In alert state, the window indicates that it demands attention, for example |
3794 | by flashing or bouncing the taskbar entry. |
3795 | */ |
3796 | |
3797 | /*! |
3798 | \qmlmethod QtQuick::Window::close() |
3799 | |
3800 | Closes the window. |
3801 | |
3802 | When this method is called, or when the user tries to close the window by |
3803 | its title bar button, the \l closing signal will be emitted. If there is no |
3804 | handler, or the handler does not revoke permission to close, the window |
3805 | will subsequently close. If the QGuiApplication::quitOnLastWindowClosed |
3806 | property is \c true, and there are no other windows open, the application |
3807 | will quit. |
3808 | */ |
3809 | |
3810 | /*! |
3811 | \qmlmethod QtQuick::Window::raise() |
3812 | |
3813 | Raises the window in the windowing system. |
3814 | |
3815 | Requests that the window be raised to appear above other windows. |
3816 | */ |
3817 | |
3818 | /*! |
3819 | \qmlmethod QtQuick::Window::lower() |
3820 | |
3821 | Lowers the window in the windowing system. |
3822 | |
3823 | Requests that the window be lowered to appear below other windows. |
3824 | */ |
3825 | |
3826 | /*! |
3827 | \qmlmethod QtQuick::Window::show() |
3828 | |
3829 | Shows the window. |
3830 | |
3831 | This is equivalent to calling showFullScreen(), showMaximized(), or showNormal(), |
3832 | depending on the platform's default behavior for the window type and flags. |
3833 | |
3834 | \sa showFullScreen(), showMaximized(), showNormal(), hide(), QQuickItem::flags() |
3835 | */ |
3836 | |
3837 | /*! |
3838 | \qmlmethod QtQuick::Window::hide() |
3839 | |
3840 | Hides the window. |
3841 | |
3842 | Equivalent to setting \l visible to \c false or \l visibility to \l {QWindow::}{Hidden}. |
3843 | |
3844 | \sa show() |
3845 | */ |
3846 | |
3847 | /*! |
3848 | \qmlmethod QtQuick::Window::showMinimized() |
3849 | |
3850 | Shows the window as minimized. |
3851 | |
3852 | Equivalent to setting \l visibility to \l {QWindow::}{Minimized}. |
3853 | */ |
3854 | |
3855 | /*! |
3856 | \qmlmethod QtQuick::Window::showMaximized() |
3857 | |
3858 | Shows the window as maximized. |
3859 | |
3860 | Equivalent to setting \l visibility to \l {QWindow::}{Maximized}. |
3861 | */ |
3862 | |
3863 | /*! |
3864 | \qmlmethod QtQuick::Window::showFullScreen() |
3865 | |
3866 | Shows the window as fullscreen. |
3867 | |
3868 | Equivalent to setting \l visibility to \l {QWindow::}{FullScreen}. |
3869 | */ |
3870 | |
3871 | /*! |
3872 | \qmlmethod QtQuick::Window::showNormal() |
3873 | |
3874 | Shows the window as normal, i.e. neither maximized, minimized, nor fullscreen. |
3875 | |
3876 | Equivalent to setting \l visibility to \l {QWindow::}{Windowed}. |
3877 | */ |
3878 | |
3879 | /*! |
3880 | \enum QQuickWindow::RenderStage |
3881 | \since 5.4 |
3882 | |
3883 | \value BeforeSynchronizingStage Before synchronization. |
3884 | \value AfterSynchronizingStage After synchronization. |
3885 | \value BeforeRenderingStage Before rendering. |
3886 | \value AfterRenderingStage After rendering. |
3887 | \value AfterSwapStage After the frame is swapped. |
3888 | \value NoStage As soon as possible. This value was added in Qt 5.6. |
3889 | |
3890 | \sa {Scene Graph and Rendering} |
3891 | */ |
3892 | |
3893 | /*! |
3894 | \since 5.4 |
3895 | |
3896 | Schedules \a job to run when the rendering of this window reaches |
3897 | the given \a stage. |
3898 | |
3899 | This is a convenience to the equivalent signals in QQuickWindow for |
3900 | "one shot" tasks. |
3901 | |
3902 | The window takes ownership over \a job and will delete it when the |
3903 | job is completed. |
3904 | |
3905 | If rendering is shut down before \a job has a chance to run, the |
3906 | job will be run and then deleted as part of the scene graph cleanup. |
3907 | If the window is never shown and no rendering happens before the QQuickWindow |
3908 | is destroyed, all pending jobs will be destroyed without their run() |
3909 | method being called. |
3910 | |
3911 | If the rendering is happening on a different thread, then the job |
3912 | will happen on the rendering thread. |
3913 | |
3914 | If \a stage is \l NoStage, \a job will be run at the earliest opportunity |
3915 | whenever the render thread is not busy rendering a frame. If the window is |
3916 | not exposed, and is not renderable, at the time the job is either posted or |
3917 | handled, the job is deleted without executing the run() method. If a |
3918 | non-threaded renderer is in use, the run() method of the job is executed |
3919 | synchronously. When rendering with OpenGL, the OpenGL context is changed to |
3920 | the renderer's context before executing any job, including \l NoStage jobs. |
3921 | |
3922 | \note This function does not trigger rendering; the jobs targeting any other |
3923 | stage than NoStage will be stored run until rendering is triggered elsewhere. |
3924 | To force the job to run earlier, call QQuickWindow::update(); |
3925 | |
3926 | \sa beforeRendering(), afterRendering(), beforeSynchronizing(), |
3927 | afterSynchronizing(), frameSwapped(), sceneGraphInvalidated() |
3928 | */ |
3929 | |
3930 | void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage) |
3931 | { |
3932 | Q_D(QQuickWindow); |
3933 | |
3934 | d->renderJobMutex.lock(); |
3935 | if (stage == BeforeSynchronizingStage) { |
3936 | d->beforeSynchronizingJobs << job; |
3937 | } else if (stage == AfterSynchronizingStage) { |
3938 | d->afterSynchronizingJobs << job; |
3939 | } else if (stage == BeforeRenderingStage) { |
3940 | d->beforeRenderingJobs << job; |
3941 | } else if (stage == AfterRenderingStage) { |
3942 | d->afterRenderingJobs << job; |
3943 | } else if (stage == AfterSwapStage) { |
3944 | d->afterSwapJobs << job; |
3945 | } else if (stage == NoStage) { |
3946 | if (d->renderControl && d->rhi && d->rhi->thread() == QThread::currentThread()) { |
3947 | job->run(); |
3948 | delete job; |
3949 | } else if (isExposed()) { |
3950 | d->windowManager->postJob(window: this, job); |
3951 | } else { |
3952 | delete job; |
3953 | } |
3954 | } |
3955 | d->renderJobMutex.unlock(); |
3956 | } |
3957 | |
3958 | void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs) |
3959 | { |
3960 | renderJobMutex.lock(); |
3961 | QList<QRunnable *> jobList = *jobs; |
3962 | jobs->clear(); |
3963 | renderJobMutex.unlock(); |
3964 | |
3965 | for (QRunnable *r : std::as_const(t&: jobList)) { |
3966 | r->run(); |
3967 | delete r; |
3968 | } |
3969 | } |
3970 | |
3971 | void QQuickWindow::runJobsAfterSwap() |
3972 | { |
3973 | Q_D(QQuickWindow); |
3974 | d->runAndClearJobs(jobs: &d->afterSwapJobs); |
3975 | } |
3976 | |
3977 | /*! |
3978 | Returns the device pixel ratio for this window. |
3979 | |
3980 | This is different from QWindow::devicePixelRatio() in that it supports |
3981 | redirected rendering via QQuickRenderControl and QQuickRenderTarget. When |
3982 | using a QQuickRenderControl, the QQuickWindow is often not fully created, |
3983 | meaning it is never shown and there is no underlying native window created |
3984 | in the windowing system. As a result, querying properties like the device |
3985 | pixel ratio cannot give correct results. This function takes into account |
3986 | both QQuickRenderControl::renderWindowFor() and |
3987 | QQuickRenderTarget::devicePixelRatio(). When no redirection is in effect, |
3988 | the result is same as QWindow::devicePixelRatio(). |
3989 | |
3990 | \sa QQuickRenderControl, QQuickRenderTarget, setRenderTarget(), QWindow::devicePixelRatio() |
3991 | */ |
3992 | qreal QQuickWindow::effectiveDevicePixelRatio() const |
3993 | { |
3994 | Q_D(const QQuickWindow); |
3995 | QWindow *w = QQuickRenderControl::renderWindowFor(win: const_cast<QQuickWindow *>(this)); |
3996 | if (w) |
3997 | return w->devicePixelRatio(); |
3998 | |
3999 | if (!d->customRenderTarget.isNull()) |
4000 | return d->customRenderTarget.devicePixelRatio(); |
4001 | |
4002 | return devicePixelRatio(); |
4003 | } |
4004 | |
4005 | /*! |
4006 | \return the current renderer interface. The value is always valid and is never null. |
4007 | |
4008 | \note This function can be called at any time after constructing the |
4009 | QQuickWindow, even while isSceneGraphInitialized() is still false. However, |
4010 | some renderer interface functions, in particular |
4011 | QSGRendererInterface::getResource() will not be functional until the |
4012 | scenegraph is up and running. Backend queries, like |
4013 | QSGRendererInterface::graphicsApi() or QSGRendererInterface::shaderType(), |
4014 | will always be functional on the other hand. |
4015 | |
4016 | \note The ownership of the returned pointer stays with Qt. The returned |
4017 | instance may or may not be shared between different QQuickWindow instances, |
4018 | depending on the scenegraph backend in use. Therefore applications are |
4019 | expected to query the interface object for each QQuickWindow instead of |
4020 | reusing the already queried pointer. |
4021 | |
4022 | \sa QSGRenderNode, QSGRendererInterface |
4023 | |
4024 | \since 5.8 |
4025 | */ |
4026 | QSGRendererInterface *QQuickWindow::rendererInterface() const |
4027 | { |
4028 | Q_D(const QQuickWindow); |
4029 | |
4030 | // no context validity check - it is essential to be able to return a |
4031 | // renderer interface instance before scenegraphInitialized() is emitted |
4032 | // (depending on the backend, that can happen way too late for some of the |
4033 | // rif use cases, like examining the graphics api or shading language in |
4034 | // use) |
4035 | |
4036 | return d->context->sceneGraphContext()->rendererInterface(renderContext: d->context); |
4037 | } |
4038 | |
4039 | /*! |
4040 | \return the QRhi object used by this window for rendering. |
4041 | |
4042 | Available only when the window is using Qt's 3D API and shading language |
4043 | abstractions, meaning the result is always null when using the \c software |
4044 | adaptation. |
4045 | |
4046 | The result is valid only when rendering has been initialized, which is |
4047 | indicated by the emission of the sceneGraphInitialized() signal. Before |
4048 | that point, the returned value is null. With a regular, on-screen |
4049 | QQuickWindow scenegraph initialization typically happens when the native |
4050 | window gets exposed (shown) the first time. When using QQuickRenderControl, |
4051 | initialization is done in the explicit |
4052 | \l{QQuickRenderControl::initialize()}{initialize()} call. |
4053 | |
4054 | In practice this function is a shortcut to querying the QRhi via the |
4055 | QSGRendererInterface. |
4056 | |
4057 | \since 6.6 |
4058 | */ |
4059 | QRhi *QQuickWindow::rhi() const |
4060 | { |
4061 | Q_D(const QQuickWindow); |
4062 | return d->rhi; |
4063 | } |
4064 | |
4065 | /*! |
4066 | \return the QRhiSwapChain used by this window, if there is one. |
4067 | |
4068 | \note Only on-screen windows backed by one of the standard render loops |
4069 | (such as, \c basic or \c threaded) will have a swapchain. Otherwise the |
4070 | returned value is null. For example, the result is always null when the |
4071 | window is used with QQuickRenderControl. |
4072 | |
4073 | \since 6.6 |
4074 | */ |
4075 | QRhiSwapChain *QQuickWindow::swapChain() const |
4076 | { |
4077 | Q_D(const QQuickWindow); |
4078 | return d->swapchain; |
4079 | } |
4080 | |
4081 | /*! |
4082 | Requests the specified graphics \a api. |
4083 | |
4084 | When the built-in, default graphics adaptation is used, \a api specifies |
4085 | which graphics API (OpenGL, Vulkan, Metal, or Direct3D) the scene graph |
4086 | should use to render. In addition, the \c software backend is built-in as |
4087 | well, and can be requested by setting \a api to |
4088 | QSGRendererInterface::Software. |
4089 | |
4090 | Unlike setSceneGraphBackend(), which can only be used to request a given |
4091 | backend (shipped either built-in or installed as dynamically loaded |
4092 | plugins), this function works with the higher level concept of graphics |
4093 | APIs. It covers the backends that ship with Qt Quick, and thus have |
4094 | corresponding values in the QSGRendererInterface::GraphicsApi enum. |
4095 | |
4096 | When this function is not called at all, and the equivalent environment |
4097 | variable \c{QSG_RHI_BACKEND} is not set either, the scene graph will choose |
4098 | the graphics API to use based on the platform. |
4099 | |
4100 | This function becomes important in applications that are only prepared for |
4101 | rendering with a given API. For example, if there is native OpenGL or |
4102 | Vulkan rendering done by the application, it will want to ensure Qt Quick |
4103 | is rendering using OpenGL or Vulkan too. Such applications are expected to |
4104 | call this function early in their main() function. |
4105 | |
4106 | \note The call to the function must happen before constructing the first |
4107 | QQuickWindow in the application. The graphics API cannot be changed |
4108 | afterwards. |
4109 | |
4110 | \note When used in combination with QQuickRenderControl, this rule is |
4111 | relaxed: it is possible to change the graphics API, but only when all |
4112 | existing QQuickRenderControl and QQuickWindow instances have been |
4113 | destroyed. |
4114 | |
4115 | To query what graphics API the scene graph is using to render, |
4116 | QSGRendererInterface::graphicsApi() after the scene graph |
4117 | \l{QQuickWindow::isSceneGraphInitialized()}{has initialized}, which |
4118 | typically happens either when the window becomes visible for the first time, or |
4119 | when QQuickRenderControl::initialize() is called. |
4120 | |
4121 | To switch back to the default behavior, where the scene graph chooses a |
4122 | graphics API based on the platform and other conditions, set \a api to |
4123 | QSGRendererInterface::Unknown. |
4124 | |
4125 | \since 6.0 |
4126 | */ |
4127 | void QQuickWindow::setGraphicsApi(QSGRendererInterface::GraphicsApi api) |
4128 | { |
4129 | // Special cases: these are different scenegraph backends. |
4130 | switch (api) { |
4131 | case QSGRendererInterface::Software: |
4132 | setSceneGraphBackend(QStringLiteral("software")); |
4133 | break; |
4134 | case QSGRendererInterface::OpenVG: |
4135 | setSceneGraphBackend(QStringLiteral("openvg")); |
4136 | break; |
4137 | default: |
4138 | break; |
4139 | } |
4140 | |
4141 | // Standard case: tell the QRhi-based default adaptation what graphics api |
4142 | // (QRhi backend) to use. |
4143 | if (QSGRendererInterface::isApiRhiBased(api) || api == QSGRendererInterface::Unknown) |
4144 | QSGRhiSupport::instance_internal()->configure(api); |
4145 | } |
4146 | |
4147 | /*! |
4148 | \return the graphics API that would be used by the scene graph if it was |
4149 | initialized at this point in time. |
4150 | |
4151 | The standard way to query the API used by the scene graph is to use |
4152 | QSGRendererInterface::graphicsApi() once the scene graph has initialized, |
4153 | for example when or after the sceneGraphInitialized() signal is emitted. In |
4154 | that case one gets the true, real result, because then it is known that |
4155 | everything was initialized correctly using that graphics API. |
4156 | |
4157 | This is not always convenient. If the application needs to set up external |
4158 | frameworks, or needs to work with setGraphicsDevice() in a manner that |
4159 | depends on the scene graph's built in API selection logic, it is not always |
4160 | feasiable to defer such operations until after the QQuickWindow has been |
4161 | made visible or QQuickRenderControl::initialize() has been called. |
4162 | |
4163 | Therefore, this static function is provided as a counterpart to |
4164 | setGraphicsApi(): it can be called at any time, and the result reflects |
4165 | what API the scene graph would choose if it was initialized at the point of |
4166 | the call. |
4167 | |
4168 | \note This static function is intended to be called on the main (GUI) |
4169 | thread only. For querying the API when rendering, use QSGRendererInterface |
4170 | since that object lives on the render thread. |
4171 | |
4172 | \note This function does not take scene graph backends into account. |
4173 | |
4174 | \since 6.0 |
4175 | */ |
4176 | QSGRendererInterface::GraphicsApi QQuickWindow::graphicsApi() |
4177 | { |
4178 | // Note that this applies the settings e.g. from the env vars |
4179 | // (QSG_RHI_BACKEND) if it was not done at least once already. Whereas if |
4180 | // setGraphicsApi() was called before, or the scene graph is already |
4181 | // initialized, then this is just a simple query. |
4182 | return QSGRhiSupport::instance()->graphicsApi(); |
4183 | } |
4184 | |
4185 | /*! |
4186 | Requests a Qt Quick scenegraph \a backend. Backends can either be built-in |
4187 | or be installed in form of dynamically loaded plugins. |
4188 | |
4189 | \overload |
4190 | |
4191 | \note The call to the function must happen before constructing the first |
4192 | QQuickWindow in the application. It cannot be changed afterwards. |
4193 | |
4194 | See \l{Switch Between Adaptations in Your Application} for more information |
4195 | about the list of backends. If \a backend is invalid or an error occurs, the |
4196 | request is ignored. |
4197 | |
4198 | \note Calling this function is equivalent to setting the |
4199 | \c QT_QUICK_BACKEND or \c QMLSCENE_DEVICE environment variables. However, this |
4200 | API is safer to use in applications that spawn other processes as there is |
4201 | no need to worry about environment inheritance. |
4202 | |
4203 | \since 5.8 |
4204 | */ |
4205 | void QQuickWindow::setSceneGraphBackend(const QString &backend) |
4206 | { |
4207 | QSGContext::setBackend(backend); |
4208 | } |
4209 | |
4210 | /*! |
4211 | Returns the requested Qt Quick scenegraph backend. |
4212 | |
4213 | \note The return value of this function may still be outdated by |
4214 | subsequent calls to setSceneGraphBackend() until the first QQuickWindow in the |
4215 | application has been constructed. |
4216 | |
4217 | \note The value only reflects the request in the \c{QT_QUICK_BACKEND} |
4218 | environment variable after a QQuickWindow has been constructed. |
4219 | |
4220 | \since 5.9 |
4221 | */ |
4222 | QString QQuickWindow::sceneGraphBackend() |
4223 | { |
4224 | return QSGContext::backend(); |
4225 | } |
4226 | |
4227 | /*! |
4228 | Sets the graphics device objects for this window. The scenegraph will use |
4229 | existing device, physical device, and other objects specified by \a device |
4230 | instead of creating new ones. |
4231 | |
4232 | This function is very often used in combination with QQuickRenderControl |
4233 | and setRenderTarget(), in order to redirect Qt Quick rendering into a |
4234 | texture. |
4235 | |
4236 | A default constructed QQuickGraphicsDevice does not change the default |
4237 | behavior in any way. Once a \a device created via one of the |
4238 | QQuickGraphicsDevice factory functions, such as, |
4239 | QQuickGraphicsDevice::fromDeviceObjects(), is passed in, and the scenegraph |
4240 | uses a matching graphics API (with the example of fromDeviceObjects(), that |
4241 | would be Vulkan), the scenegraph will use the existing device objects (such |
4242 | as, the \c VkPhysicalDevice, \c VkDevice, and graphics queue family index, |
4243 | in case of Vulkan) encapsulated by the QQuickGraphicsDevice. This allows |
4244 | using the same device, and so sharing resources, such as buffers and |
4245 | textures, between Qt Quick and native rendering engines. |
4246 | |
4247 | \warning This function can only be called before initializing the |
4248 | scenegraph and will have no effect if called afterwards. In practice this |
4249 | typically means calling it right before QQuickRenderControl::initialize(). |
4250 | |
4251 | As an example, this time with Direct3D, the typical usage is expected to be |
4252 | the following: |
4253 | |
4254 | \badcode |
4255 | // native graphics resources set up by a custom D3D rendering engine |
4256 | ID3D11Device *device; |
4257 | ID3D11DeviceContext *context; |
4258 | ID3D11Texture2D *texture; |
4259 | ... |
4260 | // now to redirect Qt Quick content into 'texture' we could do the following: |
4261 | QQuickRenderControl *renderControl = new QQuickRenderControl; |
4262 | QQuickWindow *window = new QQuickWindow(renderControl); // this window will never be shown on-screen |
4263 | ... |
4264 | window->setGraphicsDevice(QQuickGraphicsDevice::fromDeviceAndContext(device, context)); |
4265 | renderControl->initialize(); |
4266 | window->setRenderTarget(QQuickRenderTarget::fromD3D11Texture(texture, textureSize); |
4267 | ... |
4268 | \endcode |
4269 | |
4270 | The key aspect of using this function is to ensure that resources or |
4271 | handles to resources, such as \c texture in the above example, are visible |
4272 | to and usable by both the external rendering engine and the scenegraph |
4273 | renderer. This requires using the same graphics device (or with OpenGL, |
4274 | OpenGL context). |
4275 | |
4276 | QQuickGraphicsDevice instances are implicitly shared, copyable, and |
4277 | can be passed by value. They do not own the associated native objects (such |
4278 | as, the ID3D11Device in the example). |
4279 | |
4280 | \note Using QQuickRenderControl does not always imply having to call this |
4281 | function. When adopting an existing device or context is not needed, this |
4282 | function should not be called, and the scene graph will then initialize its |
4283 | own devices and contexts normally, just as it would with an on-screen |
4284 | QQuickWindow. |
4285 | |
4286 | \since 6.0 |
4287 | |
4288 | \sa QQuickRenderControl, setRenderTarget(), setGraphicsApi() |
4289 | */ |
4290 | void QQuickWindow::setGraphicsDevice(const QQuickGraphicsDevice &device) |
4291 | { |
4292 | Q_D(QQuickWindow); |
4293 | d->customDeviceObjects = device; |
4294 | } |
4295 | |
4296 | /*! |
4297 | \return the QQuickGraphicsDevice passed to setGraphicsDevice(), or a |
4298 | default constructed one otherwise |
4299 | |
4300 | \since 6.0 |
4301 | |
4302 | \sa setGraphicsDevice() |
4303 | */ |
4304 | QQuickGraphicsDevice QQuickWindow::graphicsDevice() const |
4305 | { |
4306 | Q_D(const QQuickWindow); |
4307 | return d->customDeviceObjects; |
4308 | } |
4309 | |
4310 | /*! |
4311 | Sets the graphics configuration for this window. \a config contains various |
4312 | settings that may be taken into account by the scene graph when |
4313 | initializing the underlying graphics devices and contexts. |
4314 | |
4315 | Such additional configuration, specifying for example what device |
4316 | extensions to enable for Vulkan, becomes relevant and essential when |
4317 | integrating native graphics rendering code that relies on certain |
4318 | extensions. The same is true when integrating with an external 3D or VR |
4319 | engines, such as OpenXR. |
4320 | |
4321 | \note The configuration is ignored when adopting existing graphics devices |
4322 | via setGraphicsDevice() since the scene graph is then not in control of the |
4323 | actual construction of those objects. |
4324 | |
4325 | QQuickGraphicsConfiguration instances are implicitly shared, copyable, and |
4326 | can be passed by value. |
4327 | |
4328 | \warning Setting a QQuickGraphicsConfiguration on a QQuickWindow must |
4329 | happen early enough, before the scene graph is initialized for the first |
4330 | time for that window. With on-screen windows this means the call must be |
4331 | done before invoking show() on the QQuickWindow or QQuickView. With |
4332 | QQuickRenderControl the configuration must be finalized before calling |
4333 | \l{QQuickRenderControl::initialize()}{initialize()}. |
4334 | |
4335 | \since 6.0 |
4336 | */ |
4337 | void QQuickWindow::setGraphicsConfiguration(const QQuickGraphicsConfiguration &config) |
4338 | { |
4339 | Q_D(QQuickWindow); |
4340 | d->graphicsConfig = config; |
4341 | } |
4342 | |
4343 | /*! |
4344 | \return the QQuickGraphicsConfiguration passed to |
4345 | setGraphicsConfiguration(), or a default constructed one otherwise. |
4346 | |
4347 | \since 6.0 |
4348 | |
4349 | \sa setGraphicsConfiguration() |
4350 | */ |
4351 | QQuickGraphicsConfiguration QQuickWindow::graphicsConfiguration() const |
4352 | { |
4353 | Q_D(const QQuickWindow); |
4354 | return d->graphicsConfig; |
4355 | } |
4356 | |
4357 | /*! |
4358 | Creates a text node. When the scenegraph is not initialized, the return value is null. |
4359 | |
4360 | \since 6.7 |
4361 | \sa QSGTextNode |
4362 | */ |
4363 | QSGTextNode *QQuickWindow::createTextNode() const |
4364 | { |
4365 | Q_D(const QQuickWindow); |
4366 | return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createTextNode(renderContext: d->context) : nullptr; |
4367 | } |
4368 | |
4369 | /*! |
4370 | Creates a simple rectangle node. When the scenegraph is not initialized, the return value is null. |
4371 | |
4372 | This is cross-backend alternative to constructing a QSGSimpleRectNode directly. |
4373 | |
4374 | \since 5.8 |
4375 | \sa QSGRectangleNode |
4376 | */ |
4377 | QSGRectangleNode *QQuickWindow::createRectangleNode() const |
4378 | { |
4379 | Q_D(const QQuickWindow); |
4380 | return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createRectangleNode() : nullptr; |
4381 | } |
4382 | |
4383 | /*! |
4384 | Creates a simple image node. When the scenegraph is not initialized, the return value is null. |
4385 | |
4386 | This is cross-backend alternative to constructing a QSGSimpleTextureNode directly. |
4387 | |
4388 | \since 5.8 |
4389 | \sa QSGImageNode |
4390 | */ |
4391 | QSGImageNode *QQuickWindow::createImageNode() const |
4392 | { |
4393 | Q_D(const QQuickWindow); |
4394 | return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createImageNode() : nullptr; |
4395 | } |
4396 | |
4397 | /*! |
4398 | Creates a nine patch node. When the scenegraph is not initialized, the return value is null. |
4399 | |
4400 | \since 5.8 |
4401 | */ |
4402 | QSGNinePatchNode *QQuickWindow::createNinePatchNode() const |
4403 | { |
4404 | Q_D(const QQuickWindow); |
4405 | return isSceneGraphInitialized() ? d->context->sceneGraphContext()->createNinePatchNode() : nullptr; |
4406 | } |
4407 | |
4408 | /*! |
4409 | \since 5.10 |
4410 | |
4411 | Returns the render type of text-like elements in Qt Quick. |
4412 | The default is QQuickWindow::QtTextRendering. |
4413 | |
4414 | \sa setTextRenderType() |
4415 | */ |
4416 | QQuickWindow::TextRenderType QQuickWindow::textRenderType() |
4417 | { |
4418 | return QQuickWindowPrivate::textRenderType; |
4419 | } |
4420 | |
4421 | /*! |
4422 | \since 5.10 |
4423 | |
4424 | Sets the default render type of text-like elements in Qt Quick to \a renderType. |
4425 | |
4426 | \note setting the render type will only affect elements created afterwards; |
4427 | the render type of existing elements will not be modified. |
4428 | |
4429 | \sa textRenderType() |
4430 | */ |
4431 | void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType) |
4432 | { |
4433 | QQuickWindowPrivate::textRenderType = renderType; |
4434 | } |
4435 | |
4436 | |
4437 | /*! |
4438 | \since 6.0 |
4439 | \qmlproperty Palette Window::palette |
4440 | |
4441 | This property holds the palette currently set for the window. |
4442 | |
4443 | The default palette depends on the system environment. QGuiApplication maintains a system/theme |
4444 | palette which serves as a default for all application windows. You can also set the default palette |
4445 | for windows by passing a custom palette to QGuiApplication::setPalette(), before loading any QML. |
4446 | |
4447 | Window propagates explicit palette properties to child items and controls, |
4448 | overriding any system defaults for that property. |
4449 | |
4450 | \snippet qml/windowPalette.qml entire |
4451 | |
4452 | \sa Item::palette, Popup::palette, ColorGroup, SystemPalette |
4453 | //! internal \sa QQuickAbstractPaletteProvider, QQuickPalette |
4454 | */ |
4455 | |
4456 | #ifndef QT_NO_DEBUG_STREAM |
4457 | QDebug operator<<(QDebug debug, const QQuickWindow *win) |
4458 | { |
4459 | QDebugStateSaver saver(debug); |
4460 | debug.nospace(); |
4461 | if (!win) { |
4462 | debug << "QQuickWindow(nullptr)"; |
4463 | return debug; |
4464 | } |
4465 | |
4466 | debug << win->metaObject()->className() << '(' << static_cast<const void *>(win); |
4467 | if (win->isActive()) |
4468 | debug << " active"; |
4469 | if (win->isExposed()) |
4470 | debug << " exposed"; |
4471 | debug << ", visibility="<< win->visibility() << ", flags="<< win->flags(); |
4472 | if (!win->title().isEmpty()) |
4473 | debug << ", title="<< win->title(); |
4474 | if (!win->objectName().isEmpty()) |
4475 | debug << ", name="<< win->objectName(); |
4476 | if (win->parent()) |
4477 | debug << ", parent="<< static_cast<const void *>(win->parent()); |
4478 | if (win->transientParent()) |
4479 | debug << ", transientParent="<< static_cast<const void *>(win->transientParent()); |
4480 | debug << ", geometry="; |
4481 | QtDebugUtils::formatQRect(debug, rect: win->geometry()); |
4482 | debug << ')'; |
4483 | return debug; |
4484 | } |
4485 | #endif |
4486 | |
4487 | QT_END_NAMESPACE |
4488 | |
4489 | #include "qquickwindow.moc" |
4490 | #include "moc_qquickwindow_p.cpp" |
4491 | #include "moc_qquickwindow.cpp" |
4492 |
Definitions
- lcDirty
- lcQuickWindow
- lcTransient
- defaultAlphaBuffer
- textRenderType
- QQuickWindowIncubationController
- QQuickWindowIncubationController
- timerEvent
- incubateAgain
- incubate
- animationStopped
- incubatingObjectCountChanged
- accessibleRoot
- QQuickRootItem
- exposeEvent
- resizeEvent
- showEvent
- hideEvent
- closeEvent
- focusOutEvent
- focusInEvent
- transformDirtyOnItemOrAncestor
- PolishLoopDetector
- PolishLoopDetector
- check
- polishItems
- update
- updatePixelRatioHelper
- physicalDpiChanged
- handleFontDatabaseChanged
- forcePolishHelper
- handleScreenChanged
- forcePolish
- forceUpdate
- reset
- reset
- invalidateFontData
- ensureCustomRenderTarget
- setCustomCommandBuffer
- syncSceneGraph
- emitBeforeRenderPassRecording
- emitAfterRenderPassRecording
- multiViewCount
- activeCustomRhiRenderTarget
- renderSceneGraph
- QQuickWindowPrivate
- ~QQuickWindowPrivate
- setPalette
- updateWindowPalette
- updateChildrenPalettes
- init
- handleApplicationStateChanged
- data
- dirtyItem
- mouseGrabberItem
- cleanup
- QQuickWindow
- QQuickWindow
- QQuickWindow
- QQuickWindow
- ~QQuickWindow
- releaseResources
- setPersistentGraphics
- isPersistentGraphics
- setPersistentSceneGraph
- isPersistentSceneGraph
- contentItem
- activeFocusItem
- focusObject
- event
- updateChildWindowStackingOrder
- keyPressEvent
- keyReleaseEvent
- wheelEvent
- tabletEvent
- mousePressEvent
- mouseMoveEvent
- mouseDoubleClickEvent
- mouseReleaseEvent
- updateCursor
- findCursorItemAndHandler
- clearFocusObject
- setFocusToTarget
- data_append
- data_count
- data_at
- data_clear
- data_removeLast
- isRenderable
- rhiCreationFailureMessage
- cleanupNodes
- cleanupNodesOnShutdown
- cleanupNodesOnShutdown
- updateDirtyNodes
- qquickitem_before_paintNode
- fetchNextNode
- updateDirtyNode
- emitError
- maybeUpdate
- cleanupSceneGraph
- openglContext
- isSceneGraphInitialized
- setRenderTarget
- renderTarget
- grabWindow
- incubationController
- createTextureFromImage
- createTextureFromImage
- createTextureFromRhiTexture
- createTextureFromNativeTexture
- setColor
- color
- hasDefaultAlphaBuffer
- setDefaultAlphaBuffer
- graphicsStateInfo
- beginExternalCommands
- endExternalCommands
- scheduleRenderJob
- runAndClearJobs
- runJobsAfterSwap
- effectiveDevicePixelRatio
- rendererInterface
- rhi
- swapChain
- setGraphicsApi
- graphicsApi
- setSceneGraphBackend
- sceneGraphBackend
- setGraphicsDevice
- graphicsDevice
- setGraphicsConfiguration
- graphicsConfiguration
- createTextNode
- createRectangleNode
- createImageNode
- createNinePatchNode
- textRenderType
- setTextRenderType
Learn Advanced QML with KDAB
Find out more