From d7057e7c1f1a4769c6e9b0e1c54446d5104c1484 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 11 May 2010 16:50:00 +0100 Subject: Added reference counting to QWidgetBackingStore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Symbian, the top-level widget's backing store must be destroyed when it is no longer required, in order to conserve memory. The criteria for destroying the backing store is when neither the TLW nor any of its native descendents (which share the backing store) are visible. In order to implement this requirement, a count must be kept of the number of native widgets which are using the TLW's backing store. This patch provides the mechanism for maintaining this count, and for destroying the backing store when the count is decremented to zero. No calls to either the increment nor decrement functions are made, however, by this code included in this patch; this code will be added to only the Symbian backend by a subsequent patch. Task-number: QTBUG-8697 Reviewed-by: Bjørn Erik Nilsen Reviewed-by: Jason Barron --- src/gui/embedded/qwsmanager_qws.cpp | 2 +- src/gui/kernel/qapplication_s60.cpp | 5 ++-- src/gui/kernel/qapplication_x11.cpp | 2 +- src/gui/kernel/qwidget.cpp | 57 +++++++++++++++++++++++++++++++------ src/gui/kernel/qwidget_p.h | 44 ++++++++++++++++++++++++++-- src/gui/kernel/qwidget_s60.cpp | 4 +-- src/gui/painting/qbackingstore.cpp | 4 +-- tests/auto/qwidget/tst_qwidget.cpp | 13 +++------ 8 files changed, 102 insertions(+), 29 deletions(-) diff --git a/src/gui/embedded/qwsmanager_qws.cpp b/src/gui/embedded/qwsmanager_qws.cpp index d6ef148..ac6d36e 100644 --- a/src/gui/embedded/qwsmanager_qws.cpp +++ b/src/gui/embedded/qwsmanager_qws.cpp @@ -392,7 +392,7 @@ void QWSManagerPrivate::dirtyRegion(int decorationRegion, const QRegion &clip) { QTLWExtra *topextra = managed->d_func()->extra->topextra; - QWidgetBackingStore *bs = topextra->backingStore; + QWidgetBackingStore *bs = topextra->backingStore.data(); const bool pendingUpdateRequest = bs->isDirty(); if (decorationRegion == QDecoration::All) { diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index b1e0f63..6997326 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1706,14 +1706,13 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent if (!w->d_func()->maybeTopData()) break; if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) { - delete w->d_func()->topData()->backingStore; - w->d_func()->topData()->backingStore = 0; + w->d_func()->topData()->backingStore.destroy(); // In order to ensure that any resources used by the window surface // are immediately freed, we flush the WSERV command buffer. S60->wsSession().Flush(); } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible) && !w->d_func()->maybeBackingStore()) { - w->d_func()->topData()->backingStore = new QWidgetBackingStore(w); + w->d_func()->topData()->backingStore.create(w); w->d_func()->invalidateBuffer(w->rect()); w->repaint(); } diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 25a7750..304cd17 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -5245,7 +5245,7 @@ bool QETWidget::translateConfigEvent(const XEvent *event) if (isVisible() && data->crect.size() != oldSize) { Q_ASSERT(d->extra->topextra); - QWidgetBackingStore *bs = d->extra->topextra->backingStore; + QWidgetBackingStore *bs = d->extra->topextra->backingStore.data(); const bool hasStaticContents = bs && bs->hasStaticContents(); // If we have a backing store with static contents, we have to disable the top-level // resize optimization in order to get invalidated regions for resized widgets. diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index e180001..a9ea9ac 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -161,6 +161,51 @@ static inline bool hasBackingStoreSupport() extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp + +QRefCountedWidgetBackingStore::QRefCountedWidgetBackingStore() + : m_ptr(0) + , m_count(0) +{ + +} + +QRefCountedWidgetBackingStore::~QRefCountedWidgetBackingStore() +{ + delete m_ptr; +} + +void QRefCountedWidgetBackingStore::create(QWidget *widget) +{ + destroy(); + m_ptr = new QWidgetBackingStore(widget); + m_count = 0; +} + +void QRefCountedWidgetBackingStore::destroy() +{ + delete m_ptr; + m_ptr = 0; + m_count = 0; +} + +void QRefCountedWidgetBackingStore::ref() +{ + Q_ASSERT(m_ptr); + ++m_count; +} + +void QRefCountedWidgetBackingStore::deref() +{ + if (m_count) { + Q_ASSERT(m_ptr); + if (0 == --m_count) { + delete m_ptr; + m_ptr = 0; + } + } +} + + QWidgetPrivate::QWidgetPrivate(int version) : QObjectPrivate(version) , extra(0) @@ -1324,11 +1369,9 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) // a real toplevel window needs a backing store if (isWindow() && windowType() != Qt::Desktop) { - delete d->topData()->backingStore; - // QWidgetBackingStore will check this variable, hence it must be 0 - d->topData()->backingStore = 0; + d->topData()->backingStore.destroy(); if (hasBackingStoreSupport()) - d->topData()->backingStore = new QWidgetBackingStore(this); + d->topData()->backingStore.create(this); } d->setModal_sys(); @@ -1451,8 +1494,7 @@ QWidget::~QWidget() // the backing store will delete its window surface, which may or may // not have a reference to this widget that will be used later to // notify the window it no longer has a surface. - delete d->extra->topextra->backingStore; - d->extra->topextra->backingStore = 0; + d->extra->topextra->backingStore.destroy(); } #endif if (QWidgetBackingStore *bs = d->maybeBackingStore()) { @@ -1540,7 +1582,6 @@ void QWidgetPrivate::createTLExtra() QTLWExtra* x = extra->topextra = new QTLWExtra; x->icon = 0; x->iconPixmap = 0; - x->backingStore = 0; x->windowSurface = 0; x->sharedPainter = 0; x->incw = x->inch = 0; @@ -1619,7 +1660,7 @@ void QWidgetPrivate::deleteExtra() #endif if (extra->topextra) { deleteTLSysExtra(); - delete extra->topextra->backingStore; + extra->topextra->backingStore.destroy(); delete extra->topextra->icon; delete extra->topextra->iconPixmap; #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 555647c..9f7ad95 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -110,13 +110,53 @@ class QWidgetItemV2; class QStyle; +class Q_AUTOTEST_EXPORT QRefCountedWidgetBackingStore +{ +public: + QRefCountedWidgetBackingStore(); + ~QRefCountedWidgetBackingStore(); + + void create(QWidget *tlw); + void destroy(); + + void ref(); + void deref(); + + inline QWidgetBackingStore* data() + { + return m_ptr; + } + + inline QWidgetBackingStore* operator->() + { + return m_ptr; + } + + inline QWidgetBackingStore& operator*() + { + return *m_ptr; + } + + inline operator bool() const + { + return (0 != m_ptr); + } + +private: + Q_DISABLE_COPY(QRefCountedWidgetBackingStore) + +private: + QWidgetBackingStore* m_ptr; + int m_count; +}; + struct QTLWExtra { // *************************** Cross-platform variables ***************************** // Regular pointers (keep them together to avoid gaps on 64 bits architectures). QIcon *icon; // widget icon QPixmap *iconPixmap; - QWidgetBackingStore *backingStore; + QRefCountedWidgetBackingStore backingStore; QWindowSurface *windowSurface; QPainter *sharedPainter; @@ -907,7 +947,7 @@ inline QWidgetBackingStore *QWidgetPrivate::maybeBackingStore() const { Q_Q(const QWidget); QTLWExtra *x = q->window()->d_func()->maybeTopData(); - return x ? x->backingStore : 0; + return x ? x->backingStore.data() : 0; } QT_END_NAMESPACE diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 438c2a3..6b91dff 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -908,14 +908,12 @@ void QWidgetPrivate::registerDropSite(bool /* on */) void QWidgetPrivate::createTLSysExtra() { - extra->topextra->backingStore = 0; extra->topextra->inExpose = 0; } void QWidgetPrivate::deleteTLSysExtra() { - delete extra->topextra->backingStore; - extra->topextra->backingStore = 0; + extra->topextra->backingStore.destroy(); } void QWidgetPrivate::createSysExtra() diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 8de9eaa..3ddffef 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -914,7 +914,7 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft())); } else { - QWidgetBackingStore *wbs = x->backingStore; + QWidgetBackingStore *wbs = x->backingStore.data(); QRegion childExpose(newRect & clipR); if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw)) @@ -957,7 +957,7 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) if (x->inTopLevelResize) return; - QWidgetBackingStore *wbs = x->backingStore; + QWidgetBackingStore *wbs = x->backingStore.data(); if (!wbs) return; diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index f4add5a..9369f4a 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -9500,9 +9500,7 @@ void tst_QWidget::destroyBackingStore() QTRY_VERIFY(w.numPaintEvents > 0); w.reset(); w.update(); - delete qt_widget_private(&w)->topData()->backingStore; - qt_widget_private(&w)->topData()->backingStore = 0; - qt_widget_private(&w)->topData()->backingStore = new QWidgetBackingStore(&w); + qt_widget_private(&w)->topData()->backingStore.create(&w); w.update(); QApplication::processEvents(); @@ -9524,7 +9522,7 @@ QWidgetBackingStore* backingStore(QWidget &widget) QWidgetBackingStore *backingStore = 0; #ifdef QT_BUILD_INTERNAL if (QTLWExtra *topExtra = qt_widget_private(&widget)->maybeTopData()) - backingStore = topExtra->backingStore; + backingStore = topExtra->backingStore.data(); #endif return backingStore; } @@ -10244,15 +10242,12 @@ class scrollWidgetWBS : public QWidget public: void deleteBackingStore() { - if (static_cast(d_ptr.data())->maybeBackingStore()) { - delete static_cast(d_ptr.data())->topData()->backingStore; - static_cast(d_ptr.data())->topData()->backingStore = 0; - } + static_cast(d_ptr.data())->topData()->backingStore.destroy(); } void enableBackingStore() { if (!static_cast(d_ptr.data())->maybeBackingStore()) { - static_cast(d_ptr.data())->topData()->backingStore = new QWidgetBackingStore(this); + static_cast(d_ptr.data())->topData()->backingStore.create(this); static_cast(d_ptr.data())->invalidateBuffer(this->rect()); repaint(); } -- cgit v0.12