Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwidgetrepaintmanager.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 "qplatformdefs.h"
5
7
8#include <QtCore/qglobal.h>
9#include <QtCore/qdebug.h>
10#include <QtCore/qvarlengtharray.h>
11#include <QtGui/qevent.h>
12#include <QtWidgets/qapplication.h>
13#include <QtGui/qpaintengine.h>
14#if QT_CONFIG(graphicsview)
15#include <QtWidgets/qgraphicsproxywidget.h>
16#endif
17
18#include <private/qwidget_p.h>
19#include <private/qapplication_p.h>
20#include <private/qpaintengine_raster_p.h>
21#if QT_CONFIG(graphicseffect)
22#include <private/qgraphicseffect_p.h>
23#endif
24#include <QtGui/private/qwindow_p.h>
25#include <QtGui/private/qhighdpiscaling_p.h>
26
27#include <qpa/qplatformbackingstore.h>
28
30
31Q_GLOBAL_STATIC(QPlatformTextureList, qt_dummy_platformTextureList)
32
33// Watches one or more QPlatformTextureLists for changes in the lock state and
34// triggers a backingstore sync when all the registered lists turn into
35// unlocked state. This is essential when a custom rhiFlush()
36// implementation in a platform plugin is not synchronous and keeps
37// holding on to the textures for some time even after returning from there.
39{
41public:
43 : m_repaintManager(repaintManager) {}
44
45 void watch(QPlatformTextureList *textureList) {
46 connect(textureList, SIGNAL(locked(bool)), SLOT(onLockStatusChanged(bool)));
47 m_locked[textureList] = textureList->isLocked();
48 }
49
50 bool isLocked() const {
51 for (const auto &[_, v] : m_locked.asKeyValueRange()) {
52 if (v)
53 return true;
54 }
55 return false;
56 }
57
58private slots:
59 void onLockStatusChanged(bool locked) {
60 QPlatformTextureList *tl = static_cast<QPlatformTextureList *>(sender());
61 m_locked[tl] = locked;
62 if (!isLocked())
63 m_repaintManager->sync();
64 }
65
66private:
67 QHash<QPlatformTextureList *, bool> m_locked;
68 QWidgetRepaintManager *m_repaintManager;
69};
70
71// ---------------------------------------------------------------------------
72
74 : tlw(topLevel), store(tlw->backingStore())
75{
76 Q_ASSERT(store);
77
78 // Ensure all existing subsurfaces and static widgets are added to their respective lists.
79 updateLists(topLevel);
80}
81
82void QWidgetRepaintManager::updateLists(QWidget *cur)
83{
84 if (!cur)
85 return;
86
87 QList<QObject*> children = cur->children();
88 for (int i = 0; i < children.size(); ++i) {
89 QWidget *child = qobject_cast<QWidget*>(children.at(i));
90 if (!child || child->isWindow())
91 continue;
92
93 updateLists(child);
94 }
95
96 if (cur->testAttribute(Qt::WA_StaticContents))
97 addStaticWidget(cur);
98}
99
101{
102 for (int c = 0; c < dirtyWidgets.size(); ++c)
103 resetWidget(dirtyWidgets.at(c));
104 for (int c = 0; c < dirtyRenderToTextureWidgets.size(); ++c)
105 resetWidget(dirtyRenderToTextureWidgets.at(c));
106}
107
114template <class T>
116{
117 if (r.isEmpty())
118 return;
119
121 return;
122
123 Q_Q(QWidget);
124 if (!q->isVisible() || !q->updatesEnabled())
125 return;
126
127 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
128 if (!tlwExtra || !tlwExtra->backingStore || !tlwExtra->repaintManager)
129 return;
130
131 T clipped(r);
132 clipped &= clipRect();
133 if (clipped.isEmpty())
134 return;
135
136 if (!graphicsEffect && extra && extra->hasMask) {
137 QRegion masked(extra->mask);
138 masked &= clipped;
139 if (masked.isEmpty())
140 return;
141
142 tlwExtra->repaintManager->markDirty(masked, q,
144 } else {
145 tlwExtra->repaintManager->markDirty(clipped, q,
147 }
148}
149// Needed by tst_QWidget
150template Q_AUTOTEST_EXPORT void QWidgetPrivate::invalidateBackingStore<QRect>(const QRect &r);
151
152static inline QRect widgetRectFor(QWidget *, const QRect &r) { return r; }
153static inline QRect widgetRectFor(QWidget *widget, const QRegion &) { return widget->rect(); }
154
167template <class T>
169{
170 qCInfo(lcWidgetPainting) << "Marking" << r << "of" << widget << "dirty"
171 << "with" << updateTime;
172
173 Q_ASSERT(tlw->d_func()->extra);
174 Q_ASSERT(tlw->d_func()->extra->topextra);
176 Q_ASSERT(widget->window() == tlw);
177 Q_ASSERT(!r.isEmpty());
178
179#if QT_CONFIG(graphicseffect)
180 widget->d_func()->invalidateGraphicsEffectsRecursively();
181#endif
182
183 QRect widgetRect = widgetRectFor(widget, r);
184
185 // ---------------------------------------------------------------------------
186
187 if (widget->d_func()->shouldPaintOnScreen()) {
188 if (widget->d_func()->dirty.isEmpty()) {
189 widget->d_func()->dirty = r;
190 sendUpdateRequest(widget, updateTime);
191 return;
192 } else if (qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {
193 if (updateTime == UpdateNow)
194 sendUpdateRequest(widget, updateTime);
195 return; // Already dirty
196 }
197
198 const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
199 widget->d_func()->dirty += r;
200 if (!eventAlreadyPosted || updateTime == UpdateNow)
201 sendUpdateRequest(widget, updateTime);
202 return;
203 }
204
205 // ---------------------------------------------------------------------------
206
207 if (QWidgetPrivate::get(widget)->renderToTexture) {
208 if (!widget->d_func()->inDirtyList)
209 addDirtyRenderToTextureWidget(widget);
210 if (!updateRequestSent || updateTime == UpdateNow)
211 sendUpdateRequest(tlw, updateTime);
212 return;
213 }
214
215 // ---------------------------------------------------------------------------
216
217 QRect effectiveWidgetRect = widget->d_func()->effectiveRectFor(widgetRect);
218 const QPoint offset = widget->mapTo(tlw, QPoint());
219 QRect translatedRect = effectiveWidgetRect.translated(offset);
220#if QT_CONFIG(graphicseffect)
221 // Graphics effects may exceed window size, clamp
222 translatedRect = translatedRect.intersected(QRect(QPoint(), tlw->size()));
223#endif
224 if (qt_region_strictContains(dirty, translatedRect)) {
225 if (updateTime == UpdateNow)
226 sendUpdateRequest(tlw, updateTime);
227 return; // Already dirty
228 }
229
230 // ---------------------------------------------------------------------------
231
232 if (bufferState == BufferInvalid) {
233 const bool eventAlreadyPosted = !dirty.isEmpty() || updateRequestSent;
234#if QT_CONFIG(graphicseffect)
235 if (widget->d_func()->graphicsEffect)
236 dirty += widget->d_func()->effectiveRectFor(r).translated(offset);
237 else
238#endif
239 dirty += r.translated(offset);
240
241 if (!eventAlreadyPosted || updateTime == UpdateNow)
242 sendUpdateRequest(tlw, updateTime);
243 return;
244 }
245
246 // ---------------------------------------------------------------------------
247
248 if (dirtyWidgets.isEmpty()) {
249 addDirtyWidget(widget, r);
250 sendUpdateRequest(tlw, updateTime);
251 return;
252 }
253
254 // ---------------------------------------------------------------------------
255
256 if (widget->d_func()->inDirtyList) {
257 if (!qt_region_strictContains(widget->d_func()->dirty, effectiveWidgetRect)) {
258#if QT_CONFIG(graphicseffect)
259 if (widget->d_func()->graphicsEffect)
260 widget->d_func()->dirty += widget->d_func()->effectiveRectFor(r);
261 else
262#endif
263 widget->d_func()->dirty += r;
264 }
265 } else {
266 addDirtyWidget(widget, r);
267 }
268
269 // ---------------------------------------------------------------------------
270
271 if (updateTime == UpdateNow)
272 sendUpdateRequest(tlw, updateTime);
273}
274template void QWidgetRepaintManager::markDirty<QRect>(const QRect &, QWidget *, UpdateTime, BufferState);
275template void QWidgetRepaintManager::markDirty<QRegion>(const QRegion &, QWidget *, UpdateTime, BufferState);
276
277void QWidgetRepaintManager::addDirtyWidget(QWidget *widget, const QRegion &rgn)
278{
279 if (widget && !widget->d_func()->inDirtyList && !widget->data->in_destructor) {
280 QWidgetPrivate *widgetPrivate = widget->d_func();
281#if QT_CONFIG(graphicseffect)
282 if (widgetPrivate->graphicsEffect)
283 widgetPrivate->dirty = widgetPrivate->effectiveRectFor(rgn.boundingRect());
284 else
285#endif // QT_CONFIG(graphicseffect)
286 widgetPrivate->dirty = rgn;
287 dirtyWidgets.append(widget);
288 widgetPrivate->inDirtyList = true;
289 }
290}
291
293{
294 if (!w)
295 return;
296
297 dirtyWidgets.removeAll(w);
298 dirtyRenderToTextureWidgets.removeAll(w);
299 resetWidget(w);
300
301 needsFlushWidgets.removeAll(w);
302
303 QWidgetPrivate *wd = w->d_func();
304 const int n = wd->children.size();
305 for (int i = 0; i < n; ++i) {
306 if (QWidget *child = qobject_cast<QWidget*>(wd->children.at(i)))
308 }
309}
310
311void QWidgetRepaintManager::resetWidget(QWidget *widget)
312{
313 if (widget) {
314 widget->d_func()->inDirtyList = false;
315 widget->d_func()->isScrolled = false;
316 widget->d_func()->isMoved = false;
317 widget->d_func()->dirty = QRegion();
318 }
319}
320
321void QWidgetRepaintManager::addDirtyRenderToTextureWidget(QWidget *widget)
322{
323 if (widget && !widget->d_func()->inDirtyList && !widget->data->in_destructor) {
324 QWidgetPrivate *widgetPrivate = widget->d_func();
325 Q_ASSERT(widgetPrivate->renderToTexture);
326 dirtyRenderToTextureWidgets.append(widget);
327 widgetPrivate->inDirtyList = true;
328 }
329}
330
331void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime updateTime)
332{
333 if (!widget)
334 return;
335
336 qCInfo(lcWidgetPainting) << "Sending update request to" << widget << "with" << updateTime;
337
338 // Having every repaint() leading to a sync/flush is bad as it causes
339 // compositing and waiting for vsync each and every time. Change to
340 // UpdateLater, except for approx. once per frame to prevent starvation in
341 // case the control does not get back to the event loop.
342 if (updateTime == UpdateNow && QWidgetPrivate::get(widget)->textureChildSeen) {
343 int refresh = 60;
344 QWidget *w = widget->window();
345 QScreen *ws = w->windowHandle()->screen();
346 if (ws)
347 refresh = ws->refreshRate();
348 QWindowPrivate *wd = QWindowPrivate::get(w->windowHandle());
349 if (wd->lastComposeTime.isValid()) {
351 if (elapsed <= qint64(1000.0f / refresh))
352 updateTime = UpdateLater;
353 }
354 }
355
356 switch (updateTime) {
357 case UpdateLater:
358 // Prevent redundant update request events, unless it's a
359 // paint on screen widget, as these don't go through the
360 // normal backingstore sync machinery.
361 if (!widget->d_func()->shouldPaintOnScreen())
362 updateRequestSent = true;
364 break;
365 case UpdateNow: {
368 break;
369 }
370 }
371}
372
373// ---------------------------------------------------------------------------
374
376{
377 return widget && widget->windowHandle() && widget->windowHandle()->handle();
378}
379
380//parent's coordinates; move whole rect; update parent and widget
381//assume the screen blt has already been done, so we don't need to refresh that part
382void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
383{
384 Q_Q(QWidget);
385 if (!q->isVisible() || (dx == 0 && dy == 0))
386 return;
387
388 QWidget *tlw = q->window();
389
390 static const bool accelEnv = qEnvironmentVariableIntValue("QT_NO_FAST_MOVE") == 0;
391
392 QWidget *parentWidget = q->parentWidget();
393 QPoint toplevelOffset = parentWidget->mapTo(tlw, QPoint());
394 QWidgetPrivate *parentPrivate = parentWidget->d_func();
395 const QRect clipR(parentPrivate->clipRect());
396 const QRect newRect(rect.translated(dx, dy));
397 QRect destRect = rect.intersected(clipR);
398 if (destRect.isValid())
399 destRect = destRect.translated(dx, dy).intersected(clipR);
400 const QRect sourceRect(destRect.translated(-dx, -dy));
401 const QRect parentRect(rect & clipR);
402 const bool nativeWithTextureChild = textureChildSeen && hasPlatformWindow(q);
403
404 bool accelerateMove = accelEnv && isOpaque && !nativeWithTextureChild && sourceRect.isValid()
405#if QT_CONFIG(graphicsview)
406 // No accelerate move for proxy widgets.
407 && !tlw->d_func()->extra->proxyWidget
408#endif
409 && !isOverlapped(sourceRect) && !isOverlapped(destRect);
410
411 if (!accelerateMove) {
412 QRegion parentRegion(effectiveRectFor(parentRect));
413 if (!extra || !extra->hasMask) {
414 parentRegion -= newRect;
415 } else {
416 // invalidateBackingStore() excludes anything outside the mask
417 parentRegion += newRect & clipR;
418 }
419 parentPrivate->invalidateBackingStore(parentRegion);
420 invalidateBackingStore((newRect & clipR).translated(-data.crect.topLeft()));
421 } else {
422 QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(tlw)->maybeRepaintManager();
423 Q_ASSERT(repaintManager);
424 QRegion childExpose(newRect & clipR);
425
426 if (repaintManager->bltRect(sourceRect, dx, dy, parentWidget))
427 childExpose -= destRect;
428
429 if (!parentWidget->updatesEnabled())
430 return;
431
432 const bool childUpdatesEnabled = q->updatesEnabled();
433
434 if (childUpdatesEnabled && !childExpose.isEmpty()) {
435 childExpose.translate(-data.crect.topLeft());
436 repaintManager->markDirty(childExpose, q);
437 isMoved = true;
438 }
439
440 QRegion parentExpose(parentRect);
441 parentExpose -= newRect;
442 if (extra && extra->hasMask)
443 parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft());
444
445 if (!parentExpose.isEmpty()) {
446 repaintManager->markDirty(parentExpose, parentWidget);
447 parentPrivate->isMoved = true;
448 }
449
450 if (childUpdatesEnabled) {
451 QRegion needsFlush(sourceRect);
452 needsFlush += destRect;
453 repaintManager->markNeedsFlush(parentWidget, needsFlush, toplevelOffset);
454 }
455 }
456}
457
458//widget's coordinates; scroll within rect; only update widget
459void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
460{
461 Q_Q(QWidget);
462 QWidget *tlw = q->window();
463
464 QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(tlw)->maybeRepaintManager();
465 if (!repaintManager)
466 return;
467
468 static const bool accelEnv = qEnvironmentVariableIntValue("QT_NO_FAST_SCROLL") == 0;
469
470 const QRect scrollRect = rect & clipRect();
471 bool overlapped = false;
472 bool accelerateScroll = accelEnv && isOpaque && !q_func()->testAttribute(Qt::WA_WState_InPaintEvent)
473 && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft())));
474
475 if (!accelerateScroll) {
476 if (overlapped) {
477 QRegion region(scrollRect);
480 }else {
482 }
483 } else {
484 const QPoint toplevelOffset = q->mapTo(tlw, QPoint());
485 const QRect destRect = scrollRect.translated(dx, dy) & scrollRect;
486 const QRect sourceRect = destRect.translated(-dx, -dy);
487
488 QRegion childExpose(scrollRect);
489 if (sourceRect.isValid()) {
490 if (repaintManager->bltRect(sourceRect, dx, dy, q))
491 childExpose -= destRect;
492 }
493
494 if (inDirtyList) {
495 if (rect == q->rect()) {
496 dirty.translate(dx, dy);
497 } else {
498 QRegion dirtyScrollRegion = dirty.intersected(scrollRect);
499 if (!dirtyScrollRegion.isEmpty()) {
500 dirty -= dirtyScrollRegion;
501 dirtyScrollRegion.translate(dx, dy);
502 dirty += dirtyScrollRegion;
503 }
504 }
505 }
506
507 if (!q->updatesEnabled())
508 return;
509
510 if (!childExpose.isEmpty()) {
511 repaintManager->markDirty(childExpose, q);
512 isScrolled = true;
513 }
514
515 // Instead of using native scroll-on-screen, we copy from
516 // backingstore, giving only one screen update for each
517 // scroll, and a solid appearance
518 repaintManager->markNeedsFlush(q, destRect, toplevelOffset);
519 }
520}
521
522/*
523 Moves the whole rect by (dx, dy) in widget's coordinate system.
524 Doesn't generate any updates.
525*/
527{
528 const QPoint pos(widget->mapTo(tlw, rect.topLeft()));
529 const QRect tlwRect(QRect(pos, rect.size()));
530 if (dirty.intersects(tlwRect))
531 return false; // We don't want to scroll junk.
532 return store->scroll(tlwRect, dx, dy);
533}
534
535// ---------------------------------------------------------------------------
536
538 QPlatformTextureList *widgetTextures,
539 QList<QWidget *> *nativeChildren)
540{
542 if (wd->renderToTexture) {
543 QPlatformTextureList::Flags flags = wd->textureListFlags();
544 const QRect rect(widget->mapTo(tlw, QPoint()), widget->size());
546 widgetTextures->appendTexture(widget, data.textureLeft, data.textureRight, rect, wd->clipRect(), flags);
547 }
548
549 for (int i = 0; i < wd->children.size(); ++i) {
551 // Stop at native widgets but store them. Stop at hidden widgets too.
552 if (w && !w->isWindow() && hasPlatformWindow(w))
553 nativeChildren->append(w);
554 if (w && !w->isWindow() && !hasPlatformWindow(w) && !w->isHidden() && QWidgetPrivate::get(w)->textureChildSeen)
555 findTextureWidgetsRecursively(tlw, w, widgetTextures, nativeChildren);
556 }
557}
558
560{
561 // textureChildSeen does not take native child widgets into account and that's good.
562 if (QWidgetPrivate::get(widget)->textureChildSeen) {
563 QList<QWidget *> nativeChildren;
564 auto tl = std::make_unique<QPlatformTextureList>();
565 // Look for texture widgets (incl. widget itself) from 'widget' down,
566 // but skip subtrees with a parent of a native child widget.
567 findTextureWidgetsRecursively(tlw, widget, tl.get(), &nativeChildren);
568 // tl may be empty regardless of textureChildSeen if we have native or hidden children.
569 if (!tl->isEmpty())
570 QWidgetPrivate::get(tlw)->topData()->widgetTextures.push_back(std::move(tl));
571 // Native child widgets, if there was any, get their own separate QPlatformTextureList.
572 for (QWidget *ncw : std::as_const(nativeChildren)) {
573 if (QWidgetPrivate::get(ncw)->textureChildSeen)
575 }
576 }
577}
578
580{
581 for (const auto &tl : QWidgetPrivate::get(tlw)->topData()->widgetTextures) {
582 Q_ASSERT(!tl->isEmpty());
583 for (int i = 0; i < tl->count(); ++i) {
584 QWidget *w = static_cast<QWidget *>(tl->source(i));
585 if ((hasPlatformWindow(w) && w == widget) || (!hasPlatformWindow(w) && w->nativeParentWidget() == widget))
586 return tl.get();
587 }
588 }
589
590 if (QWidgetPrivate::get(widget)->textureChildSeen)
591 return qt_dummy_platformTextureList();
592
593 return nullptr;
594}
595
596// ---------------------------------------------------------------------------
597
605void QWidgetRepaintManager::sync(QWidget *exposedWidget, const QRegion &exposedRegion)
606{
607 qCInfo(lcWidgetPainting) << "Syncing" << exposedRegion << "of" << exposedWidget;
608
609 if (!tlw->isVisible())
610 return;
611
612 if (!exposedWidget || !hasPlatformWindow(exposedWidget)
613 || !exposedWidget->isVisible() || !exposedWidget->testAttribute(Qt::WA_Mapped)
614 || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) {
615 return;
616 }
617
618 // Nothing to repaint.
619 if (!isDirty() && store->size().isValid()) {
620 QPlatformTextureList *widgetTextures = widgetTexturesFor(tlw, exposedWidget);
621 flush(exposedWidget, widgetTextures ? QRegion() : exposedRegion, widgetTextures);
622 return;
623 }
624
625 // As requests to sync a specific widget typically comes from an expose event
626 // we can't rely solely on our own dirty tracking to decide what to flush, and
627 // need to respect the platform's request to at least flush the entire widget,
628 QPoint offset = exposedWidget != tlw ? exposedWidget->mapTo(tlw, QPoint()) : QPoint();
629 markNeedsFlush(exposedWidget, exposedRegion, offset);
630
631 if (syncAllowed())
632 paintAndFlush();
633}
634
639{
640 qCInfo(lcWidgetPainting) << "Syncing dirty widgets";
641
642 updateRequestSent = false;
643 if (qt_widget_private(tlw)->shouldDiscardSyncRequest()) {
644 // If the top-level is minimized, it's not visible on the screen so we can delay the
645 // update until it's shown again. In order to do that we must keep the dirty states.
646 // These will be cleared when we receive the first expose after showNormal().
647 // However, if the widget is not visible (isVisible() returns false), everything will
648 // be invalidated once the widget is shown again, so clear all dirty states.
649 if (!tlw->isVisible()) {
650 dirty = QRegion();
651 for (int i = 0; i < dirtyWidgets.size(); ++i)
652 resetWidget(dirtyWidgets.at(i));
653 dirtyWidgets.clear();
654 }
655 return;
656 }
657
658 if (syncAllowed())
659 paintAndFlush();
660}
661
663{
664 Q_Q(const QWidget);
665 return !maybeTopData() || !q->testAttribute(Qt::WA_Mapped) || !q->isVisible();
666}
667
668bool QWidgetRepaintManager::syncAllowed()
669{
670 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
671 if (textureListWatcher && !textureListWatcher->isLocked()) {
672 textureListWatcher->deleteLater();
673 textureListWatcher = nullptr;
674 } else if (!tlwExtra->widgetTextures.empty()) {
675 bool skipSync = false;
676 for (const auto &tl : tlwExtra->widgetTextures) {
677 if (tl->isLocked()) {
678 if (!textureListWatcher)
679 textureListWatcher = new QPlatformTextureListWatcher(this);
680 if (!textureListWatcher->isLocked())
681 textureListWatcher->watch(tl.get());
682 skipSync = true;
683 }
684 }
685 if (skipSync) // cannot compose due to widget textures being in use
686 return false;
687 }
688 return true;
689}
690
691static bool isDrawnInEffect(const QWidget *w)
692{
693#if QT_CONFIG(graphicseffect)
694 do {
695 if (w->graphicsEffect())
696 return true;
697 w = w->parentWidget();
698 } while (w);
699#endif
700 return false;
701}
702
703void QWidgetRepaintManager::paintAndFlush()
704{
705 qCInfo(lcWidgetPainting) << "Painting and flushing dirty"
706 << "top level" << dirty << "and dirty widgets" << dirtyWidgets;
707
708 const bool updatesDisabled = !tlw->updatesEnabled();
709 bool repaintAllWidgets = false;
710
711 const QRect tlwRect = tlw->data->crect;
712 if (!updatesDisabled && store->size() != tlwRect.size()) {
714 if (hasStaticContents() && !store->size().isEmpty()
716 // Repaint existing dirty area and newly visible area.
717 const QRect clipRect(QPoint(0, 0), store->size());
718 const QRegion staticRegion(staticContents(nullptr, clipRect));
719 QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height());
720 newVisible -= staticRegion;
721 dirty += newVisible;
722 store->setStaticContents(staticRegion);
723 } else {
724 // Repaint everything.
725 dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height());
726 for (int i = 0; i < dirtyWidgets.size(); ++i)
727 resetWidget(dirtyWidgets.at(i));
728 dirtyWidgets.clear();
729 repaintAllWidgets = true;
730 }
731 }
732
733 if (store->size() != tlwRect.size())
734 store->resize(tlwRect.size());
735
736 if (updatesDisabled)
737 return;
738
739 // Contains everything that needs repaint.
740 QRegion toClean(dirty);
741
742 // Loop through all update() widgets and remove them from the list before they are
743 // painted (in case someone calls update() in paintEvent). If the widget is opaque
744 // and does not have transparent overlapping siblings, append it to the
745 // opaqueNonOverlappedWidgets list and paint it directly without composition.
746 QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets;
747 for (int i = 0; i < dirtyWidgets.size(); ++i) {
748 QWidget *w = dirtyWidgets.at(i);
749 QWidgetPrivate *wd = w->d_func();
750 if (wd->data.in_destructor)
751 continue;
752
753 // Clip with mask() and clipRect().
754 wd->dirty &= wd->clipRect();
755 wd->clipToEffectiveMask(wd->dirty);
756
757 // Subtract opaque siblings and children.
758 bool hasDirtySiblingsAbove = false;
759 // We know for sure that the widget isn't overlapped if 'isMoved' is true.
760 if (!wd->isMoved)
761 wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove);
762
763 // Make a copy of the widget's dirty region, to restore it in case there is an opaque
764 // render-to-texture child that completely covers the widget, because otherwise the
765 // render-to-texture child won't be visible, due to its parent widget not being redrawn
766 // with a proper blending mask.
767 const QRegion dirtyBeforeSubtractedOpaqueChildren = wd->dirty;
768
769 // Scrolled and moved widgets must draw all children.
770 if (!wd->isScrolled && !wd->isMoved)
771 wd->subtractOpaqueChildren(wd->dirty, w->rect());
772
773 if (wd->dirty.isEmpty() && wd->textureChildSeen)
774 wd->dirty = dirtyBeforeSubtractedOpaqueChildren;
775
776 if (wd->dirty.isEmpty()) {
777 resetWidget(w);
778 continue;
779 }
780
781 const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint()))
782 : wd->dirty);
783 toClean += widgetDirty;
784
785#if QT_CONFIG(graphicsview)
786 if (tlw->d_func()->extra->proxyWidget) {
787 resetWidget(w);
788 continue;
789 }
790#endif
791
792 if (!isDrawnInEffect(w) && !hasDirtySiblingsAbove && wd->isOpaque
793 && !dirty.intersects(widgetDirty.boundingRect())) {
794 opaqueNonOverlappedWidgets.append(w);
795 } else {
796 resetWidget(w);
797 dirty += widgetDirty;
798 }
799 }
800 dirtyWidgets.clear();
801
802 // Find all render-to-texture child widgets (including self).
803 // The search is cut at native widget boundaries, meaning that each native child widget
804 // has its own list for the subtree below it.
805 QTLWExtra *tlwExtra = tlw->d_func()->topData();
806 tlwExtra->widgetTextures.clear();
808
809 if (toClean.isEmpty()) {
810 // Nothing to repaint. However renderToTexture widgets are handled
811 // specially, they are not in the regular dirty list, in order to
812 // prevent triggering unnecessary backingstore painting when only the
813 // texture content changes. Check if we have such widgets in the special
814 // dirty list.
815 QVarLengthArray<QWidget *, 16> paintPending;
816 const int numPaintPending = dirtyRenderToTextureWidgets.size();
817 paintPending.reserve(numPaintPending);
818 for (int i = 0; i < numPaintPending; ++i) {
819 QWidget *w = dirtyRenderToTextureWidgets.at(i);
820 paintPending << w;
821 resetWidget(w);
822 }
823 dirtyRenderToTextureWidgets.clear();
824 for (int i = 0; i < numPaintPending; ++i) {
825 QWidget *w = paintPending[i];
826 w->d_func()->sendPaintEvent(w->rect());
827 if (w != tlw) {
828 QWidget *npw = w->nativeParentWidget();
829 if (hasPlatformWindow(w) || (npw && npw != tlw)) {
830 if (!hasPlatformWindow(w))
831 w = npw;
833 }
834 }
835 }
836
837 // We might have newly exposed areas on the screen if this function was
838 // called from sync(QWidget *, QRegion)), so we have to make sure those
839 // are flushed. We also need to composite the renderToTexture widgets.
840 flush();
841
842 return;
843 }
844
845 for (const auto &tl : tlwExtra->widgetTextures) {
846 for (int i = 0; i < tl->count(); ++i) {
847 QWidget *w = static_cast<QWidget *>(tl->source(i));
848 if (dirtyRenderToTextureWidgets.contains(w)) {
849 const QRect rect = tl->geometry(i); // mapped to the tlw already
850 // Set a flag to indicate that the paint event for this
851 // render-to-texture widget must not to be optimized away.
852 w->d_func()->renderToTextureReallyDirty = 1;
853 dirty += rect;
854 toClean += rect;
855 }
856 }
857 }
858 for (int i = 0; i < dirtyRenderToTextureWidgets.size(); ++i)
859 resetWidget(dirtyRenderToTextureWidgets.at(i));
860 dirtyRenderToTextureWidgets.clear();
861
862#if QT_CONFIG(graphicsview)
863 if (tlw->d_func()->extra->proxyWidget) {
864 updateStaticContentsSize();
865 dirty = QRegion();
866 updateRequestSent = false;
867 for (const QRect &rect : toClean)
868 tlw->d_func()->extra->proxyWidget->update(rect);
869 return;
870 }
871#endif
872
873 store->beginPaint(toClean);
874
875 // Must do this before sending any paint events because
876 // the size may change in the paint event.
877 updateStaticContentsSize();
878 const QRegion dirtyCopy(dirty);
879 dirty = QRegion();
880 updateRequestSent = false;
881
882 // Paint opaque non overlapped widgets.
883 for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
884 QWidget *w = opaqueNonOverlappedWidgets[i];
885 QWidgetPrivate *wd = w->d_func();
886
887 QWidgetPrivate::DrawWidgetFlags flags = QWidgetPrivate::DrawRecursive;
888 // Scrolled and moved widgets must draw all children.
889 if (!wd->isScrolled && !wd->isMoved)
891 if (w == tlw)
893
894 QRegion toBePainted(wd->dirty);
895 resetWidget(w);
896
898 if (w != tlw)
899 offset += w->mapTo(tlw, QPoint());
900 wd->drawWidget(store->paintDevice(), toBePainted, offset, flags, nullptr, this);
901 }
902
903 // Paint the rest with composition.
904 if (repaintAllWidgets || !dirtyCopy.isEmpty()) {
905 QWidgetPrivate::DrawWidgetFlags flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive
907 tlw->d_func()->drawWidget(store->paintDevice(), dirtyCopy, QPoint(), flags, nullptr, this);
908 }
909
910 store->endPaint();
911
912 flush();
913}
914
921void QWidgetRepaintManager::markNeedsFlush(QWidget *widget, const QRegion &region, const QPoint &topLevelOffset)
922{
923 if (!widget || widget->d_func()->shouldPaintOnScreen() || region.isEmpty())
924 return;
925
926 if (widget == tlw) {
927 // Top-level (native)
928 qCInfo(lcWidgetPainting) << "Marking" << region << "of top level"
929 << widget << "as needing flush";
930 topLevelNeedsFlush += region;
931 } else if (!hasPlatformWindow(widget) && !widget->isWindow()) {
932 QWidget *nativeParent = widget->nativeParentWidget();
933 qCInfo(lcWidgetPainting) << "Marking" << region << "of"
934 << widget << "as needing flush in" << nativeParent
935 << "at offset" << topLevelOffset;
936 if (nativeParent == tlw) {
937 // Alien widgets with the top-level as the native parent (common case)
938 topLevelNeedsFlush += region.translated(topLevelOffset);
939 } else {
940 // Alien widgets with native parent != tlw
941 const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint());
942 markNeedsFlush(nativeParent, region.translated(nativeParentOffset));
943 }
944 } else {
945 // Native child widgets
946 qCInfo(lcWidgetPainting) << "Marking" << region
947 << "of native child" << widget << "as needing flush";
948 markNeedsFlush(widget, region);
949 }
950}
951
953{
954 if (!widget)
955 return;
956
957 auto *widgetPrivate = qt_widget_private(widget);
958 if (!widgetPrivate->needsFlush)
959 widgetPrivate->needsFlush = new QRegion;
960
961 *widgetPrivate->needsFlush += region;
962
963 if (!needsFlushWidgets.contains(widget))
964 needsFlushWidgets.append(widget);
965}
966
970void QWidgetRepaintManager::flush()
971{
972 qCInfo(lcWidgetPainting) << "Flushing top level"
973 << topLevelNeedsFlush << "and children" << needsFlushWidgets;
974
975 const bool hasNeedsFlushWidgets = !needsFlushWidgets.isEmpty();
976 bool flushed = false;
977
978 // Flush the top level widget
979 if (!topLevelNeedsFlush.isEmpty()) {
980 flush(tlw, topLevelNeedsFlush, widgetTexturesFor(tlw, tlw));
981 topLevelNeedsFlush = QRegion();
982 flushed = true;
983 }
984
985 // Render-to-texture widgets are not in topLevelNeedsFlush so flush if we have not done it above.
986 if (!flushed && !hasNeedsFlushWidgets) {
987 if (!tlw->d_func()->topData()->widgetTextures.empty()) {
988 if (QPlatformTextureList *widgetTextures = widgetTexturesFor(tlw, tlw))
989 flush(tlw, QRegion(), widgetTextures);
990 }
991 }
992
993 if (!hasNeedsFlushWidgets)
994 return;
995
996 for (QWidget *w : std::exchange(needsFlushWidgets, {})) {
997 QWidgetPrivate *wd = w->d_func();
998 Q_ASSERT(wd->needsFlush);
999 QPlatformTextureList *widgetTexturesForNative = wd->textureChildSeen ? widgetTexturesFor(tlw, w) : nullptr;
1000 flush(w, *wd->needsFlush, widgetTexturesForNative);
1001 *wd->needsFlush = QRegion();
1002 }
1003}
1004
1005/*
1006 Flushes the contents of the backingstore into the screen area of \a widget.
1007
1008 \a region is the region to be updated in \a widget coordinates.
1009 */
1010void QWidgetRepaintManager::flush(QWidget *widget, const QRegion &region, QPlatformTextureList *widgetTextures)
1011{
1012 Q_ASSERT(!region.isEmpty() || widgetTextures);
1014 Q_ASSERT(tlw);
1015
1017 return;
1018
1019 // Foreign Windows do not have backing store content and must not be flushed
1020 if (QWindow *widgetWindow = widget->windowHandle()) {
1021 if (widgetWindow->type() == Qt::ForeignWindow)
1022 return;
1023 }
1024
1025 static bool fpsDebug = qEnvironmentVariableIntValue("QT_DEBUG_FPS");
1026 if (fpsDebug) {
1027 if (!perfFrames++)
1028 perfTime.start();
1029 if (perfTime.elapsed() > 5000) {
1030 double fps = double(perfFrames * 1000) / perfTime.restart();
1031 qDebug("FPS: %.1f\n", fps);
1032 perfFrames = 0;
1033 }
1034 }
1035
1036 QPoint offset;
1037 if (widget != tlw)
1038 offset += widget->mapTo(tlw, QPoint());
1039
1040 // Use a condition that tries to keep both QTBUG-108344 and QTBUG-113557
1041 // happy, i.e. support both (A) "native rhi-based child in a rhi-based
1042 // toplevel" and (B) "native raster child in a rhi-based toplevel".
1043 //
1044 // If the tlw and the backingstore are RHI-based, then there are two cases
1045 // to consider:
1046 //
1047 // (1) widget is not a native child, i.e. the QWindow for widget and tlw are
1048 // the same,
1049 //
1050 // (2) widget is a native child which we now attempt to flush with tlw's
1051 // backingstore to widget's native window. This is the interesting one.
1052 //
1053 // Using the condition tlw->usesRhiFlush on its own is insufficient since
1054 // it fails to capture the case of a raster-based native child widget
1055 // within tlw. (which must hit the non-rhi flush path)
1056 //
1057 // Extending the condition with tlw->windowHandle() == widget->windowHandle()
1058 // would be logical but wrong, when it comes to (A) since flushing a
1059 // RHI-based native child with a given 3D API using a RHI-based
1060 // tlw/backingstore with the same 3D API needs to be supported still. (this
1061 // happens when e.g. someone calls winId() on a QOpenGLWidget)
1062 //
1063 // Different 3D APIs do not need to be supported since we do not allow to
1064 // do things like having a QQuickWidget with Vulkan and a QOpenGLWidget in
1065 // the same toplevel, regardless of the widgets being native children or
1066 // not. Hence comparing the surfaceType() instead. This satisfies both (A)
1067 // and (B) given that an RHI-based toplevel cannot be RasterSurface.
1068 //
1069 if (tlw->d_func()->usesRhiFlush && tlw->windowHandle()->surfaceType() == widget->windowHandle()->surfaceType()) {
1070 QRhi *rhi = store->handle()->rhi();
1071 qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget
1072 << "with QRhi" << rhi
1073 << "to window" << widget->windowHandle();
1074 if (!widgetTextures)
1075 widgetTextures = qt_dummy_platformTextureList;
1076
1077 QWidgetPrivate *widgetWindowPrivate = widget->window()->d_func();
1078 widgetWindowPrivate->sendComposeStatus(widget->window(), false);
1079 // A window may have alpha even when the app did not request
1080 // WA_TranslucentBackground. Therefore the compositor needs to know whether the app intends
1081 // to rely on translucency, in order to decide if it should clear to transparent or opaque.
1082 const bool translucentBackground = widget->testAttribute(Qt::WA_TranslucentBackground);
1083
1085 flushResult = store->handle()->rhiFlush(widget->windowHandle(),
1087 region,
1088 offset,
1089 widgetTextures,
1090 translucentBackground);
1091 widgetWindowPrivate->sendComposeStatus(widget->window(), true);
1098 widget->update();
1099 }
1100 } else {
1101 qCInfo(lcWidgetPainting) << "Flushing" << region << "of" << widget;
1102 store->flush(region, widget->windowHandle(), offset);
1103 }
1104}
1105
1106// ---------------------------------------------------------------------------
1107
1109{
1110 if (!widget)
1111 return;
1112
1114 if (!staticWidgets.contains(widget))
1115 staticWidgets.append(widget);
1116}
1117
1118// Move the reparented widget and all its static children from this backing store
1119// to the new backing store if reparented into another top-level / backing store.
1121{
1122 Q_ASSERT(reparented);
1123 QWidgetRepaintManager *newPaintManager = reparented->d_func()->maybeRepaintManager();
1124 if (newPaintManager == this)
1125 return;
1126
1127 int i = 0;
1128 while (i < staticWidgets.size()) {
1129 QWidget *w = staticWidgets.at(i);
1130 if (reparented == w || reparented->isAncestorOf(w)) {
1131 staticWidgets.removeAt(i);
1132 if (newPaintManager)
1133 newPaintManager->addStaticWidget(w);
1134 } else {
1135 ++i;
1136 }
1137 }
1138}
1139
1144
1145bool QWidgetRepaintManager::hasStaticContents() const
1146{
1147 return !staticWidgets.isEmpty();
1148}
1149
1155QRegion QWidgetRepaintManager::staticContents(QWidget *parent, const QRect &withinClipRect) const
1156{
1157 if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) {
1158 QRect backingstoreRect(QPoint(0, 0), store->size());
1159 if (!withinClipRect.isEmpty())
1160 backingstoreRect &= withinClipRect;
1161 return QRegion(backingstoreRect);
1162 }
1163
1164 QRegion region;
1165 if (parent && parent->d_func()->children.isEmpty())
1166 return region;
1167
1168 const bool clipToRect = !withinClipRect.isEmpty();
1169 const int count = staticWidgets.size();
1170 for (int i = 0; i < count; ++i) {
1171 QWidget *w = staticWidgets.at(i);
1172 QWidgetPrivate *wd = w->d_func();
1173 if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty()
1174 || !w->isVisible() || (parent && !parent->isAncestorOf(w))) {
1175 continue;
1176 }
1177
1178 QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height());
1179 const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint());
1180 if (clipToRect)
1181 rect &= withinClipRect.translated(-offset);
1182 if (rect.isEmpty())
1183 continue;
1184
1185 rect &= wd->clipRect();
1186 if (rect.isEmpty())
1187 continue;
1188
1189 QRegion visible(rect);
1190 wd->clipToEffectiveMask(visible);
1191 if (visible.isEmpty())
1192 continue;
1193 wd->subtractOpaqueSiblings(visible, nullptr, /*alsoNonOpaque=*/true);
1194
1195 visible.translate(offset);
1196 region += visible;
1197 }
1198
1199 return region;
1200}
1201
1202void QWidgetRepaintManager::updateStaticContentsSize()
1203{
1204 for (int i = 0; i < staticWidgets.size(); ++i) {
1205 QWidgetPrivate *wd = staticWidgets.at(i)->d_func();
1206 if (!wd->extra)
1207 wd->createExtra();
1208 wd->extra->staticContentsSize = wd->data.crect.size();
1209 }
1210}
1211
1212// ---------------------------------------------------------------------------
1213
1215{
1216 return !(dirtyWidgets.isEmpty() && dirty.isEmpty() && dirtyRenderToTextureWidgets.isEmpty());
1217}
1218
1224{
1225 Q_Q(QWidget);
1226 Q_ASSERT(!q->isWindow());
1227 Q_ASSERT(q->parentWidget());
1228
1229 const bool staticContents = q->testAttribute(Qt::WA_StaticContents);
1230 const bool sizeDecreased = (data.crect.width() < oldSize.width())
1231 || (data.crect.height() < oldSize.height());
1232
1233 const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y());
1234 const bool parentAreaExposed = !offset.isNull() || sizeDecreased;
1235 const QRect newWidgetRect(q->rect());
1236 const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height());
1237
1238 if (!staticContents || graphicsEffect) {
1239 QRegion staticChildren;
1240 QWidgetRepaintManager *bs = nullptr;
1241 if (offset.isNull() && (bs = maybeRepaintManager()))
1242 staticChildren = bs->staticContents(q, oldWidgetRect);
1243 const bool hasStaticChildren = !staticChildren.isEmpty();
1244
1245 if (hasStaticChildren) {
1246 QRegion dirty(newWidgetRect);
1247 dirty -= staticChildren;
1249 } else {
1250 // Entire widget needs repaint.
1251 invalidateBackingStore(newWidgetRect);
1252 }
1253
1254 if (!parentAreaExposed)
1255 return;
1256
1257 // Invalidate newly exposed area of the parent.
1258 if (!graphicsEffect && extra && extra->hasMask) {
1259 QRegion parentExpose(extra->mask.translated(oldPos));
1260 parentExpose &= QRect(oldPos, oldSize);
1261 if (hasStaticChildren)
1262 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
1263 q->parentWidget()->d_func()->invalidateBackingStore(parentExpose);
1264 } else {
1265 if (hasStaticChildren && !graphicsEffect) {
1266 QRegion parentExpose(QRect(oldPos, oldSize));
1267 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
1268 q->parentWidget()->d_func()->invalidateBackingStore(parentExpose);
1269 } else {
1270 q->parentWidget()->d_func()->invalidateBackingStore(effectiveRectFor(QRect(oldPos, oldSize)));
1271 }
1272 }
1273 return;
1274 }
1275
1276 // Move static content to its new position.
1277 if (!offset.isNull()) {
1278 if (sizeDecreased) {
1279 const QSize minSize(qMin(oldSize.width(), data.crect.width()),
1280 qMin(oldSize.height(), data.crect.height()));
1281 moveRect(QRect(oldPos, minSize), offset.x(), offset.y());
1282 } else {
1283 moveRect(QRect(oldPos, oldSize), offset.x(), offset.y());
1284 }
1285 }
1286
1287 // Invalidate newly visible area of the widget.
1288 if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) {
1289 QRegion newVisible(newWidgetRect);
1290 newVisible -= oldWidgetRect;
1291 invalidateBackingStore(newVisible);
1292 }
1293
1294 if (!parentAreaExposed)
1295 return;
1296
1297 // Invalidate newly exposed area of the parent.
1298 const QRect oldRect(oldPos, oldSize);
1299 if (extra && extra->hasMask) {
1300 QRegion parentExpose(oldRect);
1301 parentExpose &= extra->mask.translated(oldPos);
1302 parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect);
1303 q->parentWidget()->d_func()->invalidateBackingStore(parentExpose);
1304 } else {
1305 QRegion parentExpose(oldRect);
1306 parentExpose -= data.crect;
1307 q->parentWidget()->d_func()->invalidateBackingStore(parentExpose);
1308 }
1309}
1310
1312{
1313 return store->handle()->rhi();
1314}
1315
1317
1318#include "qwidgetrepaintmanager.moc"
1319#include "moc_qwidgetrepaintmanager_p.cpp"
QPlatformBackingStore * handle() const
Returns a pointer to the QPlatformBackingStore implementation.
QPaintDevice * paintDevice()
Returns the paint device for this surface.
void beginPaint(const QRegion &)
Begins painting on the backing store surface in the given region.
void flush(const QRegion &region, QWindow *window=nullptr, const QPoint &offset=QPoint())
Flushes the given region from the specified window onto the screen.
void setStaticContents(const QRegion &region)
Set region as the static contents of this window.
void resize(const QSize &size)
Sets the size of the window surface to size.
QSize size() const
Returns the current size of the window surface.
bool scroll(const QRegion &area, int dx, int dy)
Scrolls the given area dx pixels to the right and dy downward; both dx and dy may be negative.
void endPaint()
Ends painting.
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static bool closingDown()
Returns true if the application objects are being destroyed; otherwise returns false.
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
qint64 elapsed() const noexcept
Returns the number of milliseconds since this QElapsedTimer was last started.
qint64 restart() noexcept
Restarts the timer and returns the number of milliseconds elapsed since the previous start.
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
bool isValid() const noexcept
Returns false if the timer has never been started or invalidated by a call to invalidate().
\inmodule QtCore
Definition qcoreevent.h:45
@ WindowAboutToChangeInternal
Definition qcoreevent.h:285
@ UpdateRequest
Definition qcoreevent.h:113
@ WindowChangeInternal
Definition qcoreevent.h:275
static QPlatformIntegration * platformIntegration()
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
void removeAt(qsizetype i)
Definition qlist.h:590
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
qsizetype removeAll(const AT &t)
Definition qlist.h:592
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
QObjectList children
Definition qobject.h:74
\inmodule QtCore
Definition qobject.h:103
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:201
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
qreal devicePixelRatio() const
virtual FlushResult rhiFlush(QWindow *window, qreal sourceDevicePixelRatio, const QRegion &region, const QPoint &offset, QPlatformTextureList *textures, bool translucentBackground)
Flushes the given region from the specified window, and compositing it with the specified textures li...
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
virtual bool hasCapability(Capability cap) const
QPlatformTextureListWatcher(QWidgetRepaintManager *repaintManager)
void watch(QPlatformTextureList *textureList)
QRect geometry(int index) const
void appendTexture(void *source, QRhiTexture *texture, const QRect &geometry, const QRect &clipRect=QRect(), Flags flags={ })
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:170
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:415
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr QRect translated(int dx, int dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:261
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
void translate(int dx, int dy)
Translates (moves) the region dx along the X axis and dy along the Y axis.
bool intersects(const QRegion &r) const
Definition qregion.cpp:613
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
QRegion intersected(const QRegion &r) const
QRegion translated(int dx, int dy) const
Definition qregion.cpp:593
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
QRect crect
Definition qwidget.h:90
uint in_destructor
Definition qwidget.h:88
QTLWExtra * maybeTopData() const
Definition qwidget_p.h:867
QRegion * needsFlush
Definition qwidget_p.h:652
QWidgetData data
Definition qwidget_p.h:704
bool isOverlapped(const QRect &rect) const
Definition qwidget_p.h:359
void subtractOpaqueChildren(QRegion &rgn, const QRect &clipRect) const
Definition qwidget.cpp:2007
void scrollRect(const QRect &, int dx, int dy)
bool shouldDiscardSyncRequest() const
void clipToEffectiveMask(QRegion &region) const
Definition qwidget.cpp:2104
static QWidgetPrivate * get(QWidget *w)
Definition qwidget_p.h:212
QWidgetRepaintManager * maybeRepaintManager() const
Definition qwidget_p.h:893
std::unique_ptr< QWExtra > extra
Definition qwidget_p.h:647
void subtractOpaqueSiblings(QRegion &source, bool *hasDirtySiblingsAbove=nullptr, bool alsoNonOpaque=false) const
Definition qwidget.cpp:2018
QRegion dirty
Definition qwidget_p.h:672
QGraphicsEffect * graphicsEffect
Definition qwidget_p.h:657
uint textureChildSeen
Definition qwidget_p.h:728
void invalidateBackingStore_resizeHelper(const QPoint &oldPos, const QSize &oldSize)
Invalidates the backing store when the widget is resized.
void drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, DrawWidgetFlags flags, QPainter *sharedPainter=nullptr, QWidgetRepaintManager *repaintManager=nullptr)
Definition qwidget.cpp:5448
uint renderToTexture
Definition qwidget_p.h:727
QRect effectiveRectFor(const QRegion &region) const
Definition qwidget_p.h:540
QRect clipRect() const
Definition qwidget.cpp:1865
void moveRect(const QRect &, int dx, int dy)
virtual QPlatformTextureList::Flags textureListFlags()
Definition qwidget_p.h:599
void createExtra()
Definition qwidget.cpp:1632
void invalidateBackingStore(const T &)
virtual TextureData texture() const
Definition qwidget_p.h:598
QRegion staticContents(QWidget *widget=nullptr, const QRect &withinClipRect=QRect()) const
Returns the static content inside the parent if non-zero; otherwise the static content for the entire...
void markDirty(const T &r, QWidget *widget, UpdateTime updateTime=UpdateLater, BufferState bufferState=BufferValid)
void addStaticWidget(QWidget *widget)
void sync()
Synchronizes the backing store, i.e.
void removeStaticWidget(QWidget *widget)
void moveStaticWidgets(QWidget *reparented)
bool bltRect(const QRect &rect, int dx, int dy, QWidget *widget)
void markNeedsFlush(QWidget *widget, const QRegion &region, const QPoint &topLevelOffset)
Marks the region of the widget as needing a flush.
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QWidget * nativeParentWidget() const
Definition qwidget.cpp:4333
QWidget * window() const
Returns the window for this widget, i.e.
Definition qwidget.cpp:4313
QSize size
the size of the widget excluding any window frame
Definition qwidget.h:113
bool updatesEnabled
whether updates are enabled
Definition qwidget.h:143
QRect rect
the internal geometry of the widget excluding any window frame
Definition qwidget.h:116
void update()
Updates the widget unless updates are disabled or the widget is hidden.
QWindow * windowHandle() const
If this is a native widget, return the associated QWindow.
Definition qwidget.cpp:2483
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
QPointF mapTo(const QWidget *, const QPointF &) const
Translates the widget coordinate pos to the coordinate system of parent.
Definition qwidget.cpp:4197
bool isWindow() const
Returns true if the widget is an independent window, otherwise returns false.
Definition qwidget.h:811
bool isAncestorOf(const QWidget *child) const
Returns true if this widget is a parent, (or grandparent and so on to any level), of the given child,...
Definition qwidget.cpp:8822
bool isVisible() const
Definition qwidget.h:874
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition qwidget.h:910
static QWindowPrivate * get(QWindow *window)
Definition qwindow_p.h:106
QElapsedTimer lastComposeTime
Definition qwindow_p.h:158
\inmodule QtGui
Definition qwindow.h:63
SurfaceType surfaceType() const override
Returns the surface type of the window.
Definition qwindow.cpp:665
QOpenGLWidget * widget
[1]
rect
[4]
Combined button and popup list for selecting options.
@ WA_TranslucentBackground
Definition qnamespace.h:402
@ WA_DontShowOnScreen
Definition qnamespace.h:383
@ WA_StaticContents
Definition qnamespace.h:288
@ WA_WState_InPaintEvent
Definition qnamespace.h:329
@ WA_Mapped
Definition qnamespace.h:293
QTextStream & ws(QTextStream &stream)
Calls \l {QTextStream::}{skipWhiteSpace()} on stream and returns stream.
@ LowEventPriority
@ ForeignWindow
Definition qnamespace.h:217
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qDebug
[1]
Definition qlogging.h:164
#define qCInfo(category,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLsizei const GLfloat * v
[13]
GLfloat GLfloat GLfloat w
[0]
GLboolean r
[2]
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLbitfield flags
GLenum GLuint GLintptr offset
GLfloat n
struct _cl_event * event
const GLubyte * c
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static double elapsed(qint64 after, qint64 before)
#define Q_AUTOTEST_EXPORT
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_OBJECT
#define slots
long long qint64
Definition qtypes.h:60
Q_WIDGETS_EXPORT QWidgetPrivate * qt_widget_private(QWidget *widget)
void qSendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent::Type eventType)
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
static void findAllTextureWidgetsRecursively(QWidget *tlw, QWidget *widget)
static QPlatformTextureList * widgetTexturesFor(QWidget *tlw, QWidget *widget)
static bool isDrawnInEffect(const QWidget *w)
static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures, QList< QWidget * > *nativeChildren)
static QRect widgetRectFor(QWidget *, const QRect &r)
static bool hasPlatformWindow(QWidget *widget)
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QObject::connect nullptr
QLayoutItem * child
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:45
QWidgetWindow * window
Definition qwidget_p.h:97