5#include "qplatformdefs.h"
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>
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>
25#include <QtGui/private/qwindow_p.h>
27#include <qpa/qplatformbackingstore.h>
31Q_GLOBAL_STATIC(QPlatformTextureList, qt_dummy_platformTextureList)
38class QPlatformTextureListWatcher :
public QObject
42 QPlatformTextureListWatcher(QWidgetRepaintManager *repaintManager)
43 : m_repaintManager(repaintManager) {}
45 void watch(QPlatformTextureList *textureList) {
46 connect(textureList, SIGNAL(locked(
bool)), SLOT(onLockStatusChanged(
bool)));
47 m_locked[textureList] = textureList->isLocked();
50 bool isLocked()
const {
51 for (
const auto &[_, v] : m_locked.asKeyValueRange()) {
59 void onLockStatusChanged(
bool locked) {
60 QPlatformTextureList *tl =
static_cast<QPlatformTextureList *>(sender());
61 m_locked[tl] = locked;
63 m_repaintManager->sync();
67 QHash<QPlatformTextureList *,
bool> m_locked;
68 QWidgetRepaintManager *m_repaintManager;
73QWidgetRepaintManager::QWidgetRepaintManager(QWidget *topLevel)
74 : tlw(topLevel), store(tlw->backingStore())
79 updateLists(topLevel);
82void QWidgetRepaintManager::updateLists(QWidget *cur)
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())
96 if (cur->testAttribute(Qt::WA_StaticContents))
100QWidgetRepaintManager::~QWidgetRepaintManager()
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));
109
110
111
112
113
115void QWidgetPrivate::invalidateBackingStore(
const T &r)
120 if (QCoreApplication::closingDown())
124 if (!q->isVisible() || !q->updatesEnabled())
127 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
128 if (!tlwExtra || !tlwExtra->backingStore || !tlwExtra->repaintManager)
132 clipped &= clipRect();
133 if (clipped.isEmpty())
136 if (!graphicsEffect && extra && extra->hasMask) {
137 QRegion masked(extra->mask);
139 if (masked.isEmpty())
142 tlwExtra->repaintManager->markDirty(masked, q,
143 QWidgetRepaintManager::UpdateLater, QWidgetRepaintManager::BufferInvalid);
145 tlwExtra->repaintManager->markDirty(clipped, q,
146 QWidgetRepaintManager::UpdateLater, QWidgetRepaintManager::BufferInvalid);
150template Q_AUTOTEST_EXPORT
void QWidgetPrivate::invalidateBackingStore<QRect>(
const QRect &r);
156
157
158
159
160
161
162
163
164
165
166
168void QWidgetRepaintManager::markDirty(
const T &r, QWidget *widget, UpdateTime updateTime, BufferState bufferState)
170 qCInfo(lcWidgetPainting) <<
"Marking" << r <<
"of" << widget <<
"dirty"
171 <<
"with" << updateTime;
173 Q_ASSERT(tlw->d_func()->extra);
174 Q_ASSERT(tlw->d_func()->extra->topextra);
175 Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
176 Q_ASSERT(widget->window() == tlw);
177 Q_ASSERT(!r.isEmpty());
179#if QT_CONFIG(graphicseffect)
180 widget->d_func()->invalidateGraphicsEffectsRecursively();
183 QRect widgetRect = widgetRectFor(widget, r);
187 if (widget->d_func()->shouldPaintOnScreen()) {
188 if (widget->d_func()->dirty.isEmpty()) {
189 widget->d_func()->dirty = r;
190 sendUpdateRequest(widget, updateTime);
192 }
else if (qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {
193 if (updateTime == UpdateNow)
194 sendUpdateRequest(widget, updateTime);
198 const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
199 widget->d_func()->dirty += r;
200 if (!eventAlreadyPosted || updateTime == UpdateNow)
201 sendUpdateRequest(widget, updateTime);
207 if (QWidgetPrivate::get(widget)->renderToTexture) {
208 if (!widget->d_func()->inDirtyList)
209 addDirtyRenderToTextureWidget(widget);
210 if (!updateRequestSent || updateTime == UpdateNow)
211 sendUpdateRequest(tlw, updateTime);
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)
222 translatedRect = translatedRect.intersected(QRect(QPoint(), tlw->size()));
224 if (qt_region_strictContains(dirty, translatedRect)) {
225 if (updateTime == UpdateNow)
226 sendUpdateRequest(tlw, updateTime);
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);
239 dirty += r.translated(offset);
241 if (!eventAlreadyPosted || updateTime == UpdateNow)
242 sendUpdateRequest(tlw, updateTime);
248 if (dirtyWidgets.isEmpty()) {
249 addDirtyWidget(widget, r);
250 sendUpdateRequest(tlw, updateTime);
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);
263 widget->d_func()->dirty += r;
266 addDirtyWidget(widget, r);
271 if (updateTime == UpdateNow)
272 sendUpdateRequest(tlw, updateTime);
274template void QWidgetRepaintManager::markDirty<QRect>(
const QRect &, QWidget *, UpdateTime, BufferState);
275template void QWidgetRepaintManager::markDirty<QRegion>(
const QRegion &, QWidget *, UpdateTime, BufferState);
277void QWidgetRepaintManager::addDirtyWidget(QWidget *widget,
const QRegion &rgn)
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());
286 widgetPrivate->dirty = rgn;
287 dirtyWidgets.append(widget);
288 widgetPrivate->inDirtyList =
true;
292void QWidgetRepaintManager::removeDirtyWidget(QWidget *w)
297 dirtyWidgets.removeAll(w);
298 dirtyRenderToTextureWidgets.removeAll(w);
301 needsFlushWidgets.removeAll(w);
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)))
307 removeDirtyWidget(child);
311void QWidgetRepaintManager::resetWidget(QWidget *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();
321void QWidgetRepaintManager::addDirtyRenderToTextureWidget(QWidget *widget)
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;
331void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime updateTime)
336 qCInfo(lcWidgetPainting) <<
"Sending update request to" << widget <<
"with" << updateTime;
342 if (updateTime == UpdateNow && QWidgetPrivate::get(widget)->textureChildSeen) {
344 QWidget *w = widget->window();
345 QScreen *ws = w->windowHandle()->screen();
347 refresh = ws->refreshRate();
348 QWindowPrivate *wd = QWindowPrivate::get(w->windowHandle());
349 if (wd->lastComposeTime.isValid()) {
350 const qint64 elapsed = wd->lastComposeTime.elapsed();
351 if (elapsed <= qint64(1000.0f / refresh))
352 updateTime = UpdateLater;
356 switch (updateTime) {
361 if (!widget->d_func()->shouldPaintOnScreen())
362 updateRequestSent =
true;
363 QCoreApplication::postEvent(widget,
new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
366 QEvent event(QEvent::UpdateRequest);
367 QCoreApplication::sendEvent(widget, &event);
377 return widget && widget->windowHandle() && widget->windowHandle()->handle();
382void QWidgetPrivate::moveRect(
const QRect &rect,
int dx,
int dy)
385 if (!q->isVisible() || (dx == 0 && dy == 0))
388 QWidget *tlw = q->window();
390 static const bool accelEnv = qEnvironmentVariableIntValue(
"QT_NO_FAST_MOVE") == 0;
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);
404 bool accelerateMove = accelEnv && isOpaque && !nativeWithTextureChild && sourceRect.isValid()
405#if QT_CONFIG(graphicsview)
407 && !tlw->d_func()->extra->proxyWidget
409 && !isOverlapped(sourceRect) && !isOverlapped(destRect);
411 if (!accelerateMove) {
412 QRegion parentRegion(effectiveRectFor(parentRect));
413 if (!extra || !extra->hasMask) {
414 parentRegion -= newRect;
417 parentRegion += newRect & clipR;
419 parentPrivate->invalidateBackingStore(parentRegion);
420 invalidateBackingStore((newRect & clipR).translated(-data.crect.topLeft()));
422 QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(tlw)->maybeRepaintManager();
423 Q_ASSERT(repaintManager);
424 QRegion childExpose(newRect & clipR);
426 if (repaintManager->bltRect(sourceRect, dx, dy, parentWidget))
427 childExpose -= destRect;
429 if (!parentWidget->updatesEnabled())
432 const bool childUpdatesEnabled = q->updatesEnabled();
434 if (childUpdatesEnabled && !childExpose.isEmpty()) {
435 childExpose.translate(-data.crect.topLeft());
436 repaintManager->markDirty(childExpose, q);
440 QRegion parentExpose(parentRect);
441 parentExpose -= newRect;
442 if (extra && extra->hasMask)
443 parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft());
445 if (!parentExpose.isEmpty()) {
446 repaintManager->markDirty(parentExpose, parentWidget);
447 parentPrivate->isMoved =
true;
450 if (childUpdatesEnabled) {
451 QRegion needsFlush(sourceRect);
452 needsFlush += destRect;
453 repaintManager->markNeedsFlush(parentWidget, needsFlush, toplevelOffset);
459void QWidgetPrivate::scrollRect(
const QRect &rect,
int dx,
int dy)
462 QWidget *tlw = q->window();
464 QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(tlw)->maybeRepaintManager();
468 static const bool accelEnv = qEnvironmentVariableIntValue(
"QT_NO_FAST_SCROLL") == 0;
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())));
475 if (!accelerateScroll) {
477 QRegion region(scrollRect);
478 subtractOpaqueSiblings(region);
479 invalidateBackingStore(region);
481 invalidateBackingStore(scrollRect);
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);
488 QRegion childExpose(scrollRect);
489 if (sourceRect.isValid()) {
490 if (repaintManager->bltRect(sourceRect, dx, dy, q))
491 childExpose -= destRect;
495 if (rect == q->rect()) {
496 dirty.translate(dx, dy);
498 QRegion dirtyScrollRegion = dirty.intersected(scrollRect);
499 if (!dirtyScrollRegion.isEmpty()) {
500 dirty -= dirtyScrollRegion;
501 dirtyScrollRegion.translate(dx, dy);
502 dirty += dirtyScrollRegion;
507 if (!q->updatesEnabled())
510 if (!childExpose.isEmpty()) {
511 repaintManager->markDirty(childExpose, q);
518 repaintManager->markNeedsFlush(q, destRect, toplevelOffset);
523
524
525
526bool QWidgetRepaintManager::bltRect(
const QRect &rect,
int dx,
int dy, QWidget *widget)
528 const QPoint pos(widget->mapTo(tlw, rect.topLeft()));
529 const QRect tlwRect(QRect(pos, rect.size()));
530 if (dirty.intersects(tlwRect))
532 return store->scroll(tlwRect, dx, dy);
538 QPlatformTextureList *widgetTextures,
539 QList<QWidget *> *nativeChildren)
541 QWidgetPrivate *wd = QWidgetPrivate::get(widget);
542 if (wd->renderToTexture) {
543 QPlatformTextureList::Flags flags = wd->textureListFlags();
544 const QRect rect(widget->mapTo(tlw, QPoint()), widget->size());
545 QWidgetPrivate::TextureData data = wd->texture();
546 widgetTextures->appendTexture(widget, data.textureLeft, data.textureRight, rect, wd->clipRect(), flags);
549 for (
int i = 0; i < wd->children.size(); ++i) {
550 QWidget *w = qobject_cast<QWidget *>(wd->children.at(i));
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);
562 if (QWidgetPrivate::get(widget)->textureChildSeen) {
563 QList<QWidget *> nativeChildren;
564 auto tl = std::make_unique<QPlatformTextureList>();
567 findTextureWidgetsRecursively(tlw, widget, tl.get(), &nativeChildren);
570 QWidgetPrivate::get(tlw)->topData()->widgetTextures.push_back(std::move(tl));
572 for (QWidget *ncw : std::as_const(nativeChildren)) {
573 if (QWidgetPrivate::get(ncw)->textureChildSeen)
574 findAllTextureWidgetsRecursively(tlw, ncw);
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))
590 if (QWidgetPrivate::get(widget)->textureChildSeen)
591 return qt_dummy_platformTextureList();
599
600
601
602
605
606
607
608
609
610
611void QWidgetRepaintManager::sync(QWidget *exposedWidget,
const QRegion &exposedRegion)
613 qCInfo(lcWidgetPainting) <<
"Syncing" << exposedRegion <<
"of" << exposedWidget;
615 if (!tlw->isVisible())
618 if (!exposedWidget || !hasPlatformWindow(exposedWidget)
619 || !exposedWidget->isVisible() || !exposedWidget->testAttribute(Qt::WA_Mapped)
620 || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) {
625 if (!isDirty() && store->size().isValid()) {
626 QPlatformTextureList *widgetTextures = widgetTexturesFor(tlw, exposedWidget);
627 flush(exposedWidget, widgetTextures ? QRegion() : exposedRegion, widgetTextures);
634 QPoint offset = exposedWidget != tlw ? exposedWidget->mapTo(tlw, QPoint()) : QPoint();
635 markNeedsFlush(exposedWidget, exposedRegion, offset);
642
643
644void QWidgetRepaintManager::sync()
646 qCInfo(lcWidgetPainting) <<
"Syncing dirty widgets";
648 updateRequestSent =
false;
649 if (qt_widget_private(tlw)->shouldDiscardSyncRequest()) {
655 if (!tlw->isVisible()) {
657 for (
int i = 0; i < dirtyWidgets.size(); ++i)
658 resetWidget(dirtyWidgets.at(i));
659 dirtyWidgets.clear();
668bool QWidgetPrivate::shouldDiscardSyncRequest()
const
671 return !maybeTopData() || !q->testAttribute(Qt::WA_Mapped) || !q->isVisible();
674bool QWidgetRepaintManager::syncAllowed()
676 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
677 if (textureListWatcher && !textureListWatcher->isLocked()) {
678 textureListWatcher->deleteLater();
679 textureListWatcher =
nullptr;
680 }
else if (!tlwExtra->widgetTextures.empty()) {
681 bool skipSync =
false;
682 for (
const auto &tl : tlwExtra->widgetTextures) {
683 if (tl->isLocked()) {
684 if (!textureListWatcher)
685 textureListWatcher =
new QPlatformTextureListWatcher(
this);
686 if (!textureListWatcher->isLocked())
687 textureListWatcher->watch(tl.get());
699#if QT_CONFIG(graphicseffect)
701 if (w->graphicsEffect())
703 w = w->parentWidget();
709void QWidgetRepaintManager::paintAndFlush()
711 qCInfo(lcWidgetPainting) <<
"Painting and flushing dirty"
712 <<
"top level" << dirty <<
"and dirty widgets" << dirtyWidgets;
714 const bool updatesDisabled = !tlw->updatesEnabled();
715 bool repaintAllWidgets =
false;
717 const QRect tlwRect = tlw->data->crect;
718 if (!updatesDisabled && store->size() != tlwRect.size()) {
719 QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
720 if (hasStaticContents() && !store->size().isEmpty()
721 && integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents)) {
723 const QRect clipRect(QPoint(0, 0), store->size());
724 const QRegion staticRegion(staticContents(
nullptr, clipRect));
725 QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height());
726 newVisible -= staticRegion;
728 store->setStaticContents(staticRegion);
731 dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height());
732 for (
int i = 0; i < dirtyWidgets.size(); ++i)
733 resetWidget(dirtyWidgets.at(i));
734 dirtyWidgets.clear();
735 repaintAllWidgets =
true;
739 if (store->size() != tlwRect.size())
740 store->resize(tlwRect.size());
746 QRegion toClean(dirty);
752 QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets;
753 for (
int i = 0; i < dirtyWidgets.size(); ++i) {
754 QWidget *w = dirtyWidgets.at(i);
755 QWidgetPrivate *wd = w->d_func();
756 if (wd->data.in_destructor)
760 wd->dirty &= wd->clipRect();
761 wd->clipToEffectiveMask(wd->dirty);
764 bool hasDirtySiblingsAbove =
false;
767 wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove);
773 const QRegion dirtyBeforeSubtractedOpaqueChildren = wd->dirty;
776 if (!wd->isScrolled && !wd->isMoved)
777 wd->subtractOpaqueChildren(wd->dirty, w->rect());
779 if (wd->dirty.isEmpty() && wd->textureChildSeen)
780 wd->dirty = dirtyBeforeSubtractedOpaqueChildren;
782 if (wd->dirty.isEmpty()) {
787 const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint()))
789 toClean += widgetDirty;
791#if QT_CONFIG(graphicsview)
792 if (tlw->d_func()->extra->proxyWidget) {
798 if (!isDrawnInEffect(w) && !hasDirtySiblingsAbove && wd->isOpaque
799 && !dirty.intersects(widgetDirty.boundingRect())) {
800 opaqueNonOverlappedWidgets.append(w);
803 dirty += widgetDirty;
806 dirtyWidgets.clear();
811 QTLWExtra *tlwExtra = tlw->d_func()->topData();
812 tlwExtra->widgetTextures.clear();
813 findAllTextureWidgetsRecursively(tlw, tlw);
815 if (toClean.isEmpty()) {
821 QVarLengthArray<QWidget *, 16> paintPending;
822 const int numPaintPending = dirtyRenderToTextureWidgets.size();
823 paintPending.reserve(numPaintPending);
824 for (
int i = 0; i < numPaintPending; ++i) {
825 QWidget *w = dirtyRenderToTextureWidgets.at(i);
829 dirtyRenderToTextureWidgets.clear();
830 for (
int i = 0; i < numPaintPending; ++i) {
831 QWidget *w = paintPending[i];
832 w->d_func()->sendPaintEvent(w->rect());
834 QWidget *npw = w->nativeParentWidget();
835 if (hasPlatformWindow(w) || (npw && npw != tlw)) {
836 if (!hasPlatformWindow(w))
851 for (
const auto &tl : tlwExtra->widgetTextures) {
852 for (
int i = 0; i < tl->count(); ++i) {
853 QWidget *w =
static_cast<QWidget *>(tl->source(i));
854 if (dirtyRenderToTextureWidgets.contains(w)) {
855 const QRect rect = tl->geometry(i);
858 w->d_func()->renderToTextureReallyDirty = 1;
864 for (
int i = 0; i < dirtyRenderToTextureWidgets.size(); ++i)
865 resetWidget(dirtyRenderToTextureWidgets.at(i));
866 dirtyRenderToTextureWidgets.clear();
868#if QT_CONFIG(graphicsview)
869 if (tlw->d_func()->extra->proxyWidget) {
870 updateStaticContentsSize();
872 updateRequestSent =
false;
873 for (
const QRect &rect : toClean)
874 tlw->d_func()->extra->proxyWidget->update(rect);
879 store->beginPaint(toClean);
883 updateStaticContentsSize();
884 const QRegion dirtyCopy(dirty);
886 updateRequestSent =
false;
889 for (
int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
890 QWidget *w = opaqueNonOverlappedWidgets[i];
891 QWidgetPrivate *wd = w->d_func();
893 QWidgetPrivate::DrawWidgetFlags flags = QWidgetPrivate::DrawRecursive;
895 if (!wd->isScrolled && !wd->isMoved)
896 flags |= QWidgetPrivate::DontDrawOpaqueChildren;
898 flags |= QWidgetPrivate::DrawAsRoot;
900 QRegion toBePainted(wd->dirty);
905 offset += w->mapTo(tlw, QPoint());
906 wd->drawWidget(store->paintDevice(), toBePainted, offset, flags,
nullptr,
this);
910 if (repaintAllWidgets || !dirtyCopy.isEmpty()) {
911 QWidgetPrivate::DrawWidgetFlags flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive
912 | QWidgetPrivate::UseEffectRegionBounds;
913 tlw->d_func()->drawWidget(store->paintDevice(), dirtyCopy, QPoint(), flags,
nullptr,
this);
922
923
924
925
926
927void QWidgetRepaintManager::markNeedsFlush(QWidget *widget,
const QRegion ®ion,
const QPoint &topLevelOffset)
929 if (!widget || widget->d_func()->shouldPaintOnScreen() || region.isEmpty())
934 qCInfo(lcWidgetPainting) <<
"Marking" << region <<
"of top level"
935 << widget <<
"as needing flush";
936 topLevelNeedsFlush += region;
937 }
else if (!hasPlatformWindow(widget) && !widget->isWindow()) {
938 QWidget *nativeParent = widget->nativeParentWidget();
939 qCInfo(lcWidgetPainting) <<
"Marking" << region <<
"of"
940 << widget <<
"as needing flush in" << nativeParent
941 <<
"at offset" << topLevelOffset;
942 if (nativeParent == tlw) {
944 topLevelNeedsFlush += region.translated(topLevelOffset);
947 const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint());
948 markNeedsFlush(nativeParent, region.translated(nativeParentOffset));
952 qCInfo(lcWidgetPainting) <<
"Marking" << region
953 <<
"of native child" << widget <<
"as needing flush";
954 markNeedsFlush(widget, region);
958void QWidgetRepaintManager::markNeedsFlush(QWidget *widget,
const QRegion ®ion)
963 auto *widgetPrivate = qt_widget_private(widget);
964 if (!widgetPrivate->needsFlush)
965 widgetPrivate->needsFlush =
new QRegion;
967 *widgetPrivate->needsFlush += region;
969 if (!needsFlushWidgets.contains(widget))
970 needsFlushWidgets.append(widget);
974
975
976void QWidgetRepaintManager::flush()
978 qCInfo(lcWidgetPainting) <<
"Flushing top level"
979 << topLevelNeedsFlush <<
"and children" << needsFlushWidgets;
981 const bool hasNeedsFlushWidgets = !needsFlushWidgets.isEmpty();
982 bool flushed =
false;
985 if (!topLevelNeedsFlush.isEmpty()) {
986 flush(tlw, topLevelNeedsFlush, widgetTexturesFor(tlw, tlw));
987 topLevelNeedsFlush = QRegion();
992 if (!flushed && !hasNeedsFlushWidgets) {
993 if (!tlw->d_func()->topData()->widgetTextures.empty()) {
994 if (QPlatformTextureList *widgetTextures = widgetTexturesFor(tlw, tlw))
995 flush(tlw, QRegion(), widgetTextures);
999 if (!hasNeedsFlushWidgets)
1002 for (QWidget *w : std::exchange(needsFlushWidgets, {})) {
1003 QWidgetPrivate *wd = w->d_func();
1004 Q_ASSERT(wd->needsFlush);
1005 QPlatformTextureList *widgetTexturesForNative = wd->textureChildSeen ? widgetTexturesFor(tlw, w) :
nullptr;
1006 flush(w, *wd->needsFlush, widgetTexturesForNative);
1007 *wd->needsFlush = QRegion();
1012
1013
1014
1015
1016void QWidgetRepaintManager::flush(QWidget *widget,
const QRegion ®ion, QPlatformTextureList *widgetTextures)
1018 Q_ASSERT(!region.isEmpty() || widgetTextures);
1022 if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen))
1025 QWindow *window = widget->windowHandle();
1030 if (window->type() == Qt::ForeignWindow)
1033 static bool fpsDebug = qEnvironmentVariableIntValue(
"QT_DEBUG_FPS");
1037 if (perfTime.elapsed() > 5000) {
1038 double fps =
double(perfFrames * 1000) / perfTime.restart();
1039 qDebug(
"FPS: %.1f\n", fps);
1046 offset += widget->mapTo(tlw, QPoint());
1051 const bool flushWithRhi = widget->d_func()->usesRhiFlush;
1053 qCDebug(lcWidgetPainting) <<
"Flushing" << region <<
"of" << widget
1054 <<
"to" << window << (flushWithRhi ?
"using RHI" :
"");
1060 if (!widgetTextures)
1061 widgetTextures = qt_dummy_platformTextureList;
1065 auto *widgetPrivate = QWidgetPrivate::get(widget);
1066 widgetPrivate->sendComposeStatus(widget,
false);
1071 const bool translucentBackground = widget->testAttribute(Qt::WA_TranslucentBackground);
1073 QPlatformBackingStore::FlushResult flushResult;
1074 flushResult = store->handle()->rhiFlush(window,
1075 widget->devicePixelRatio(),
1079 translucentBackground);
1081 widgetPrivate->sendComposeStatus(widget,
true);
1083 if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) {
1084 qSendWindowChangeToTextureChildrenRecursively(widget->window(),
1085 QEvent::WindowAboutToChangeInternal);
1086 store->handle()->graphicsDeviceReportedLost(window);
1087 qSendWindowChangeToTextureChildrenRecursively(widget->window(),
1088 QEvent::WindowChangeInternal);
1092 store->flush(region, window, offset);
1098void QWidgetRepaintManager::addStaticWidget(QWidget *widget)
1103 Q_ASSERT(widget->testAttribute(Qt::WA_StaticContents));
1104 if (!staticWidgets.contains(widget))
1105 staticWidgets.append(widget);
1110void QWidgetRepaintManager::moveStaticWidgets(QWidget *reparented)
1112 Q_ASSERT(reparented);
1113 QWidgetRepaintManager *newPaintManager = reparented->d_func()->maybeRepaintManager();
1114 if (newPaintManager ==
this)
1118 while (i < staticWidgets.size()) {
1119 QWidget *w = staticWidgets.at(i);
1120 if (reparented == w || reparented->isAncestorOf(w)) {
1121 staticWidgets.removeAt(i);
1122 if (newPaintManager)
1123 newPaintManager->addStaticWidget(w);
1130void QWidgetRepaintManager::removeStaticWidget(QWidget *widget)
1132 staticWidgets.removeAll(widget);
1135bool QWidgetRepaintManager::hasStaticContents()
const
1137 return !staticWidgets.isEmpty();
1141
1142
1143
1144
1145QRegion QWidgetRepaintManager::staticContents(QWidget *parent,
const QRect &withinClipRect)
const
1147 if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) {
1148 QRect backingstoreRect(QPoint(0, 0), store->size());
1149 if (!withinClipRect.isEmpty())
1150 backingstoreRect &= withinClipRect;
1151 return QRegion(backingstoreRect);
1155 if (parent && parent->d_func()->children.isEmpty())
1158 const bool clipToRect = !withinClipRect.isEmpty();
1159 const int count = staticWidgets.size();
1160 for (
int i = 0; i < count; ++i) {
1161 QWidget *w = staticWidgets.at(i);
1162 QWidgetPrivate *wd = w->d_func();
1163 if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty()
1164 || !w->isVisible() || (parent && !parent->isAncestorOf(w))) {
1168 QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height());
1169 const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint());
1171 rect &= withinClipRect.translated(-offset);
1175 rect &= wd->clipRect();
1179 QRegion visible(rect);
1180 wd->clipToEffectiveMask(visible);
1181 if (visible.isEmpty())
1183 wd->subtractOpaqueSiblings(visible,
nullptr,
true);
1185 visible.translate(offset);
1192void QWidgetRepaintManager::updateStaticContentsSize()
1194 for (
int i = 0; i < staticWidgets.size(); ++i) {
1195 QWidgetPrivate *wd = staticWidgets.at(i)->d_func();
1198 wd->extra->staticContentsSize = wd->data.crect.size();
1204bool QWidgetRepaintManager::isDirty()
const
1206 return !(dirtyWidgets.isEmpty() && dirty.isEmpty() && dirtyRenderToTextureWidgets.isEmpty());
1210
1211
1212
1213
1216
1217
1218
1219void QWidgetPrivate::invalidateBackingStore_resizeHelper(
const QPoint &oldPos,
const QSize &oldSize)
1222 Q_ASSERT(!q->isWindow());
1223 Q_ASSERT(q->parentWidget());
1225 const bool staticContents = q->testAttribute(Qt::WA_StaticContents);
1226 const bool sizeDecreased = (data.crect.width() < oldSize.width())
1227 || (data.crect.height() < oldSize.height());
1229 const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y());
1230 const bool parentAreaExposed = !offset.isNull() || sizeDecreased;
1231 const QRect newWidgetRect(q->rect());
1232 const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height());
1234 if (!staticContents || graphicsEffect) {
1235 QRegion staticChildren;
1236 QWidgetRepaintManager *bs =
nullptr;
1237 if (offset.isNull() && (bs = maybeRepaintManager()))
1238 staticChildren = bs->staticContents(q, oldWidgetRect);
1239 const bool hasStaticChildren = !staticChildren.isEmpty();
1241 if (hasStaticChildren) {
1242 QRegion dirty(newWidgetRect);
1243 dirty -= staticChildren;
1244 invalidateBackingStore(dirty);
1247 invalidateBackingStore(newWidgetRect);
1250 if (!parentAreaExposed)
1254 if (!graphicsEffect && extra && extra->hasMask) {
1255 QRegion parentExpose(extra->mask.translated(oldPos));
1256 parentExpose &= QRect(oldPos, oldSize);
1257 if (hasStaticChildren)
1258 parentExpose -= data.crect;
1259 q->parentWidget()->d_func()->invalidateBackingStore(parentExpose);
1261 if (hasStaticChildren && !graphicsEffect) {
1262 QRegion parentExpose(QRect(oldPos, oldSize));
1263 parentExpose -= data.crect;
1264 q->parentWidget()->d_func()->invalidateBackingStore(parentExpose);
1266 q->parentWidget()->d_func()->invalidateBackingStore(effectiveRectFor(QRect(oldPos, oldSize)));
1273 if (!offset.isNull()) {
1274 if (sizeDecreased) {
1275 const QSize minSize(qMin(oldSize.width(), data.crect.width()),
1276 qMin(oldSize.height(), data.crect.height()));
1277 moveRect(QRect(oldPos, minSize), offset.x(), offset.y());
1279 moveRect(QRect(oldPos, oldSize), offset.x(), offset.y());
1284 if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) {
1285 QRegion newVisible(newWidgetRect);
1286 newVisible -= oldWidgetRect;
1287 invalidateBackingStore(newVisible);
1290 if (!parentAreaExposed)
1294 const QRect oldRect(oldPos, oldSize);
1295 if (extra && extra->hasMask) {
1296 QRegion parentExpose(oldRect);
1297 parentExpose &= extra->mask.translated(oldPos);
1298 parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect);
1299 q->parentWidget()->d_func()->invalidateBackingStore(parentExpose);
1301 QRegion parentExpose(oldRect);
1302 parentExpose -= data.crect;
1303 q->parentWidget()->d_func()->invalidateBackingStore(parentExpose);
1309#include "qwidgetrepaintmanager.moc"
1310#include "moc_qwidgetrepaintmanager_p.cpp"
Combined button and popup list for selecting options.