summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/kernel/qapplication_s60.cpp65
-rw-r--r--src/gui/kernel/qt_s60_p.h1
-rw-r--r--src/gui/kernel/qwidget.cpp61
-rw-r--r--src/gui/kernel/qwidget_p.h17
-rw-r--r--src/gui/kernel/qwidget_s60.cpp6
-rw-r--r--tests/auto/qwidget/tst_qwidget.cpp75
6 files changed, 171 insertions, 54 deletions
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp
index 559bb6a..670bf34 100644
--- a/src/gui/kernel/qapplication_s60.cpp
+++ b/src/gui/kernel/qapplication_s60.cpp
@@ -135,6 +135,38 @@ void QS60Data::setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, boo
}
#endif
+void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible)
+{
+ if (QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control)) {
+ QWidget *const widget = QWidgetPrivate::mapper->value(control);
+ QWidget *const window = widget->window();
+ if (QTLWExtra *topData = qt_widget_private(window)->maybeTopData()) {
+ QWidgetBackingStoreTracker &backingStore = topData->backingStore;
+ if (visible) {
+ if (backingStore.data()) {
+ backingStore.registerWidget(widget);
+ } else {
+#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
+ S60->wsSession().SendEffectCommand(ETfxCmdRestoreLayer);
+#endif
+ backingStore.create(window);
+ backingStore.registerWidget(widget);
+ qt_widget_private(widget)->invalidateBuffer(widget->rect());
+ widget->repaint();
+ }
+ } else {
+#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
+ S60->wsSession().SendEffectCommand(ETfxCmdDeallocateLayer);
+#endif
+ backingStore.unregisterWidget(widget);
+ // In order to ensure that any resources used by the window surface
+ // are immediately freed, we flush the WSERV command buffer.
+ S60->wsSession().Flush();
+ }
+ }
+ }
+}
+
bool qt_nograb() // application no-grab option
{
#if defined(QT_DEBUG)
@@ -1922,35 +1954,10 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent
if (callSymbianEventFilters(symbianEvent))
return 1;
const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
- QWidget *w = QWidgetPrivate::mapper->value(control);
- QWidget *const window = w->window();
- if (!window->d_func()->maybeTopData())
- break;
- QRefCountedWidgetBackingStore &backingStore = window->d_func()->maybeTopData()->backingStore;
- if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) {
-#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
- S60->wsSession().SendEffectCommand(ETfxCmdDeallocateLayer);
-#endif
- // Decrement backing store reference count
- backingStore.deref();
- // 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) {
- if (backingStore.data()) {
- // Increment backing store reference count
- backingStore.ref();
- } else {
-#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
- S60->wsSession().SendEffectCommand(ETfxCmdRestoreLayer);
-#endif
- // Create backing store with an initial reference count of 1
- backingStore.create(window);
- backingStore.ref();
- w->d_func()->invalidateBuffer(w->rect());
- w->repaint();
- }
- }
+ if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible)
+ S60->controlVisibilityChanged(control, false);
+ else if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
+ S60->controlVisibilityChanged(control, true);
return 1;
}
break;
diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h
index a18ea07..ad6a99a 100644
--- a/src/gui/kernel/qt_s60_p.h
+++ b/src/gui/kernel/qt_s60_p.h
@@ -164,6 +164,7 @@ public:
static inline CEikButtonGroupContainer* buttonGroupContainer();
static void setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, bool buttonGroupVisible);
#endif
+ static void controlVisibilityChanged(CCoeControl *control, bool visible);
#ifdef Q_OS_SYMBIAN
TTrapHandler *s60InstalledTrapHandler;
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index aaa29a1..dad4848 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -162,47 +162,76 @@ static inline bool hasBackingStoreSupport()
extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp
extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
+/*!
+ \internal
+ \class QWidgetBackingStoreTracker
+ \brief Class which allows tracking of which widgets are using a given backing store
-QRefCountedWidgetBackingStore::QRefCountedWidgetBackingStore()
+ QWidgetBackingStoreTracker is a thin wrapper around a QWidgetBackingStore pointer,
+ which maintains a list of the QWidgets which are currently using the backing
+ store. This list is modified via the registerWidget and unregisterWidget functions.
+ */
+
+QWidgetBackingStoreTracker::QWidgetBackingStoreTracker()
: m_ptr(0)
- , m_count(0)
{
}
-QRefCountedWidgetBackingStore::~QRefCountedWidgetBackingStore()
+QWidgetBackingStoreTracker::~QWidgetBackingStoreTracker()
{
delete m_ptr;
}
-void QRefCountedWidgetBackingStore::create(QWidget *widget)
+/*!
+ \internal
+ Destroy the contained QWidgetBackingStore, if not null, and clear the list of
+ widgets using the backing store, then create a new QWidgetBackingStore, providing
+ the QWidget.
+ */
+void QWidgetBackingStoreTracker::create(QWidget *widget)
{
destroy();
m_ptr = new QWidgetBackingStore(widget);
- m_count = 0;
}
-void QRefCountedWidgetBackingStore::destroy()
+/*!
+ \internal
+ Destroy the contained QWidgetBackingStore, if not null, and clear the list of
+ widgets using the backing store.
+ */
+void QWidgetBackingStoreTracker::destroy()
{
delete m_ptr;
m_ptr = 0;
- m_count = 0;
+ m_widgets.clear();
}
-void QRefCountedWidgetBackingStore::ref()
+/*!
+ \internal
+ Add the widget to the list of widgets currently using the backing store.
+ If the widget was already in the list, this function is a no-op.
+ */
+void QWidgetBackingStoreTracker::registerWidget(QWidget *w)
{
Q_ASSERT(m_ptr);
- ++m_count;
+ Q_ASSERT(w->internalWinId());
+ Q_ASSERT(qt_widget_private(w)->maybeBackingStore() == m_ptr);
+ m_widgets.insert(w);
}
-void QRefCountedWidgetBackingStore::deref()
+/*!
+ \internal
+ Remove the widget from the list of widgets currently using the backing store.
+ If the widget was in the list, and removing it causes the list to be empty,
+ the backing store is deleted.
+ If the widget was not in the list, this function is a no-op.
+ */
+void QWidgetBackingStoreTracker::unregisterWidget(QWidget *w)
{
- if (m_count) {
- Q_ASSERT(m_ptr);
- if (0 == --m_count) {
- delete m_ptr;
- m_ptr = 0;
- }
+ if (m_widgets.remove(w) && m_widgets.isEmpty()) {
+ delete m_ptr;
+ m_ptr = 0;
}
}
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index 587d7fb..4a79dc7 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -110,17 +110,18 @@ class QWidgetItemV2;
class QStyle;
-class Q_AUTOTEST_EXPORT QRefCountedWidgetBackingStore
+class Q_AUTOTEST_EXPORT QWidgetBackingStoreTracker
{
+
public:
- QRefCountedWidgetBackingStore();
- ~QRefCountedWidgetBackingStore();
+ QWidgetBackingStoreTracker();
+ ~QWidgetBackingStoreTracker();
void create(QWidget *tlw);
void destroy();
- void ref();
- void deref();
+ void registerWidget(QWidget *w);
+ void unregisterWidget(QWidget *w);
inline QWidgetBackingStore* data()
{
@@ -143,11 +144,11 @@ public:
}
private:
- Q_DISABLE_COPY(QRefCountedWidgetBackingStore)
+ Q_DISABLE_COPY(QWidgetBackingStoreTracker)
private:
QWidgetBackingStore* m_ptr;
- int m_count;
+ QSet<QWidget *> m_widgets;
};
struct QTLWExtra {
@@ -156,7 +157,7 @@ struct QTLWExtra {
// Regular pointers (keep them together to avoid gaps on 64 bits architectures).
QIcon *icon; // widget icon
QPixmap *iconPixmap;
- QRefCountedWidgetBackingStore backingStore;
+ QWidgetBackingStoreTracker backingStore;
QWindowSurface *windowSurface;
QPainter *sharedPainter;
diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp
index 56349ad..319f330 100644
--- a/src/gui/kernel/qwidget_s60.cpp
+++ b/src/gui/kernel/qwidget_s60.cpp
@@ -684,6 +684,12 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
QSymbianControl *old_winid = static_cast<QSymbianControl *>(wasCreated ? data.winid : 0);
if ((q->windowType() == Qt::Desktop))
old_winid = 0;
+
+ // old_winid may not have received a 'not visible' visibility
+ // changed event before being destroyed; make sure that it is
+ // removed from the backing store's list of visible windows.
+ S60->controlVisibilityChanged(old_winid, false);
+
setWinId(0);
// hide and reparent our own window away. Otherwise we might get
diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp
index f722f89..ef05b91 100644
--- a/tests/auto/qwidget/tst_qwidget.cpp
+++ b/tests/auto/qwidget/tst_qwidget.cpp
@@ -9742,7 +9742,6 @@ void tst_QWidget::destroyBackingStoreWhenHidden()
QVERIFY(0 != backingStore(child));
// Parent is obscured, therefore its backing store should be destroyed
- QEXPECT_FAIL("", "QTBUG-12406", Continue);
QVERIFY(0 == backingStore(parent));
// Disable full screen
@@ -9758,6 +9757,80 @@ void tst_QWidget::destroyBackingStoreWhenHidden()
QVERIFY(0 != backingStore(parent));
QVERIFY(0 == backingStore(child));
}
+
+ // 6. Partial reveal followed by full reveal
+ {
+ QWidget upper;
+ upper.setAutoFillBackground(true);
+ upper.setPalette(Qt::red);
+ upper.setGeometry(50, 50, 100, 100);
+
+ QWidget lower;
+ lower.setAutoFillBackground(true);
+ lower.setPalette(Qt::green);
+ lower.setGeometry(50, 50, 100, 100);
+
+ lower.show();
+ QTest::qWaitForWindowShown(&lower);
+ upper.show();
+ QTest::qWaitForWindowShown(&upper);
+ upper.raise();
+
+ QVERIFY(0 != backingStore(upper));
+ QVERIFY(0 == backingStore(lower));
+
+ // Check that upper obscures lower
+ QVERIFY(lower.visibleRegion().subtracted(upper.visibleRegion()).isEmpty());
+
+ // Partially reveal lower
+ upper.move(100, 100);
+
+ // Completely reveal lower
+ upper.hide();
+
+ // Hide lower widget - this should cause its backing store to be deleted
+ lower.hide();
+
+ // Check that backing store was deleted
+ WAIT_AND_VERIFY(0 == backingStore(lower));
+ }
+
+ // 7. Reparenting of visible native child widget
+ {
+ QWidget parent1;
+ parent1.setAutoFillBackground(true);
+ parent1.setPalette(Qt::green);
+ parent1.setGeometry(50, 50, 100, 100);
+
+ QWidget *child = new QWidget(&parent1);
+ child->winId();
+ child->setAutoFillBackground(true);
+ child->setPalette(Qt::red);
+ child->setGeometry(10, 10, 30, 30);
+
+ QWidget parent2;
+ parent2.setAutoFillBackground(true);
+ parent2.setPalette(Qt::blue);
+ parent2.setGeometry(150, 150, 100, 100);
+
+ parent1.show();
+ QTest::qWaitForWindowShown(&parent1);
+ QVERIFY(0 != backingStore(parent1));
+
+ parent2.show();
+ QTest::qWaitForWindowShown(&parent2);
+ QVERIFY(0 != backingStore(parent2));
+
+ child->setParent(&parent2);
+ child->setGeometry(10, 10, 30, 30);
+ child->show();
+
+ parent1.hide();
+ WAIT_AND_VERIFY(0 == backingStore(parent1));
+
+ parent2.hide();
+ WAIT_AND_VERIFY(0 == backingStore(parent2));
+ }
}
#undef WAIT_AND_VERIFY