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