summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/widgets/kernel/qwidget.cpp16
-rw-r--r--src/widgets/kernel/qwidget_p.h1
-rw-r--r--src/widgets/kernel/qwindowcontainer.cpp173
-rw-r--r--src/widgets/kernel/qwindowcontainer_p.h5
-rw-r--r--tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp62
5 files changed, 230 insertions, 27 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index f439edcf2e..abba2b455a 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1594,6 +1594,7 @@ void QWidgetPrivate::createExtra()
extra->autoFillBackground = 0;
extra->nativeChildrenForced = 0;
extra->inRenderWithPainter = 0;
+ extra->hasWindowContainer = false;
extra->hasMask = 0;
createSysExtra();
#ifdef QWIDGET_EXTRA_DEBUG
@@ -6543,6 +6544,9 @@ void QWidget::move(const QPoint &p)
data->crect.moveTopLeft(p); // no frame yet
setAttribute(Qt::WA_PendingMoveEvent);
}
+
+ if (d->extra && d->extra->hasWindowContainer)
+ QWindowContainer::parentWasMoved(this);
}
/*! \fn void QWidget::resize(int w, int h)
@@ -6581,6 +6585,9 @@ void QWidget::setGeometry(const QRect &r)
setAttribute(Qt::WA_PendingMoveEvent);
setAttribute(Qt::WA_PendingResizeEvent);
}
+
+ if (d->extra && d->extra->hasWindowContainer)
+ QWindowContainer::parentWasMoved(this);
}
/*!
@@ -9715,6 +9722,9 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
ancestorProxy->d_func()->embedSubWindow(this);
}
#endif
+
+ if (d->extra && d->extra->hasWindowContainer)
+ QWindowContainer::parentWasChanged(this);
}
/*!
@@ -10747,6 +10757,9 @@ void QWidget::raise()
if (testAttribute(Qt::WA_WState_Created))
d->raise_sys();
+ if (d->extra && d->extra->hasWindowContainer)
+ QWindowContainer::parentWasRaised(this);
+
QEvent e(QEvent::ZOrderChange);
QApplication::sendEvent(this, &e);
}
@@ -10781,6 +10794,9 @@ void QWidget::lower()
if (testAttribute(Qt::WA_WState_Created))
d->lower_sys();
+ if (d->extra && d->extra->hasWindowContainer)
+ QWindowContainer::parentWasLowered(this);
+
QEvent e(QEvent::ZOrderChange);
QApplication::sendEvent(this, &e);
}
diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
index cc740034fc..df40908c00 100644
--- a/src/widgets/kernel/qwidget_p.h
+++ b/src/widgets/kernel/qwidget_p.h
@@ -254,6 +254,7 @@ struct QWExtra {
uint nativeChildrenForced : 1;
uint inRenderWithPainter : 1;
uint hasMask : 1;
+ uint hasWindowContainer : 1;
// *************************** Platform specific values (bit fields first) **********
#if defined(Q_WS_WIN) // <----------------------------------------------------------- WIN
diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp
index b02b05552f..6914f64f8e 100644
--- a/src/widgets/kernel/qwindowcontainer.cpp
+++ b/src/widgets/kernel/qwindowcontainer.cpp
@@ -42,6 +42,10 @@
#include "qwindowcontainer_p.h"
#include "qwidget_p.h"
#include <QtGui/qwindow.h>
+#include <QDebug>
+
+#include <QMdiSubWindow>
+#include <QAbstractScrollArea>
QT_BEGIN_NAMESPACE
@@ -50,11 +54,67 @@ class QWindowContainerPrivate : public QWidgetPrivate
public:
Q_DECLARE_PUBLIC(QWindowContainer)
- QWindowContainerPrivate() : window(0), oldFocusWindow(0) { }
+ QWindowContainerPrivate()
+ : window(0)
+ , oldFocusWindow(0)
+ , usesNativeWidgets(false)
+ {
+ }
+
~QWindowContainerPrivate() { }
+ static QWindowContainerPrivate *get(QWidget *w) {
+ QWindowContainer *wc = qobject_cast<QWindowContainer *>(w);
+ if (wc)
+ return wc->d_func();
+ return 0;
+ }
+
+ void updateGeometry() {
+ Q_Q(QWindowContainer);
+ if (usesNativeWidgets)
+ window->setGeometry(q->rect());
+ else
+ window->setGeometry(QRect(q->mapTo(q->window(), QPoint()), q->size()));
+ }
+
+ void updateUsesNativeWidgets()
+ {
+ if (usesNativeWidgets || window->parent() == 0)
+ return;
+ Q_Q(QWindowContainer);
+ QWidget *p = q->parentWidget();
+ while (p) {
+ if (qobject_cast<QMdiSubWindow *>(p) != 0
+ || qobject_cast<QAbstractScrollArea *>(p) != 0) {
+ q->winId();
+ usesNativeWidgets = true;
+ break;
+ }
+ p = p->parentWidget();
+ }
+ }
+
+ void markParentChain() {
+ Q_Q(QWindowContainer);
+ QWidget *p = q;
+ while (p) {
+ QWidgetPrivate *d = static_cast<QWidgetPrivate *>(QWidgetPrivate::get(p));
+ d->createExtra();
+ d->extra->hasWindowContainer = true;
+ p = p->parentWidget();
+ }
+ }
+
+ bool isStillAnOrphan() const {
+ return window->parent() == &fakeParent;
+ }
+
QPointer<QWindow> window;
QWindow *oldFocusWindow;
+ QWindow fakeParent;
+
+ uint usesNativeWidgets : 1;
};
@@ -78,6 +138,14 @@ public:
be removed from the window container with a call to
QWindow::setParent().
+ The window container is attached as a native child window to the
+ toplevel window it is a child of. When a window container is used
+ as a child of a QAbstractScrollArea or QMdiArea, it will
+ create a \l {Native Widgets vs Alien Widgets} {native window} for
+ every widget in its parent chain to allow for proper stacking and
+ clipping in this use case. Applications with many native child
+ windows may suffer from performance issues.
+
The window container has a number of known limitations:
\list
@@ -86,11 +154,6 @@ public:
widget hierarchy as an opaque box. The stacking order of multiple
overlapping window container instances is undefined.
- \li Window Handles; The window container will explicitly invoke
- winId() which will force the use of native window handles
- inside the application. See \l {Native Widgets vs Alien Widgets}
- {QWidget documentation} for more details.
-
\li Rendering Integration; The window container does not interoperate
with QGraphicsProxyWidget, QWidget::render() or similar functionality.
@@ -132,13 +195,7 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt:
}
d->window = embeddedWindow;
-
- // We force this window to become a native window and reparent the
- // window directly to it. This is done so that the order in which
- // the QWindowContainer is added to a QWidget tree and when it
- // gets a window does not matter.
- winId();
- d->window->setParent(windowHandle());
+ d->window->setParent(&d->fakeParent);
connect(QGuiApplication::instance(), SIGNAL(focusWindowChanged(QWindow *)), this, SLOT(focusWindowChanged(QWindow *)));
}
@@ -167,8 +224,6 @@ void QWindowContainer::focusWindowChanged(QWindow *focusWindow)
d->oldFocusWindow = focusWindow;
}
-
-
/*!
\internal
*/
@@ -190,22 +245,38 @@ bool QWindowContainer::event(QEvent *e)
// The only thing we are interested in is making sure our sizes stay
// in sync, so do a catch-all case.
case QEvent::Resize:
+ d->updateGeometry();
+ break;
case QEvent::Move:
+ d->updateGeometry();
+ break;
case QEvent::PolishRequest:
- d->window->setGeometry(0, 0, width(), height());
+ d->updateGeometry();
break;
case QEvent::Show:
- d->window->show();
+ d->updateUsesNativeWidgets();
+ if (d->isStillAnOrphan()) {
+ d->window->setParent(d->usesNativeWidgets
+ ? windowHandle()
+ : window()->windowHandle());
+ }
+ if (d->window->parent()) {
+ d->markParentChain();
+ d->window->show();
+ }
break;
case QEvent::Hide:
- d->window->hide();
+ if (d->window->parent())
+ d->window->hide();
break;
case QEvent::FocusIn:
- if (d->oldFocusWindow != d->window) {
- d->window->requestActivate();
- } else {
- QWidget *next = nextInFocusChain();
- next->setFocus();
+ if (d->window->parent()) {
+ if (d->oldFocusWindow != d->window) {
+ d->window->requestActivate();
+ } else {
+ QWidget *next = nextInFocusChain();
+ next->setFocus();
+ }
}
break;
default:
@@ -215,4 +286,60 @@ bool QWindowContainer::event(QEvent *e)
return QWidget::event(e);
}
+typedef void (*qwindowcontainer_traverse_callback)(QWidget *parent);
+static void qwindowcontainer_traverse(QWidget *parent, qwindowcontainer_traverse_callback callback)
+{
+ const QObjectList &children = parent->children();
+ for (int i=0; i<children.size(); ++i) {
+ QWidget *w = qobject_cast<QWidget *>(children.at(i));
+ if (w) {
+ QWidgetPrivate *wd = static_cast<QWidgetPrivate *>(QWidgetPrivate::get(w));
+ if (wd->extra && wd->extra->hasWindowContainer)
+ callback(w);
+ }
+ }
+}
+
+void QWindowContainer::parentWasChanged(QWidget *parent)
+{
+ if (QWindowContainerPrivate *d = QWindowContainerPrivate::get(parent)) {
+ if (d->window->parent()) {
+ d->updateUsesNativeWidgets();
+ d->markParentChain();
+ d->window->setParent(d->usesNativeWidgets
+ ? parent->windowHandle()
+ : parent->window()->windowHandle());
+ d->updateGeometry();
+ }
+ }
+ qwindowcontainer_traverse(parent, parentWasChanged);
+}
+
+void QWindowContainer::parentWasMoved(QWidget *parent)
+{
+ if (QWindowContainerPrivate *d = QWindowContainerPrivate::get(parent)) {
+ if (d->window->parent())
+ d->updateGeometry();
+ }
+ qwindowcontainer_traverse(parent, parentWasMoved);
+}
+
+void QWindowContainer::parentWasRaised(QWidget *parent)
+{
+ if (QWindowContainerPrivate *d = QWindowContainerPrivate::get(parent)) {
+ if (d->window->parent())
+ d->window->raise();
+ }
+ qwindowcontainer_traverse(parent, parentWasRaised);
+}
+
+void QWindowContainer::parentWasLowered(QWidget *parent)
+{
+ if (QWindowContainerPrivate *d = QWindowContainerPrivate::get(parent)) {
+ if (d->window->parent())
+ d->window->lower();
+ }
+ qwindowcontainer_traverse(parent, parentWasLowered);
+}
+
QT_END_NAMESPACE
diff --git a/src/widgets/kernel/qwindowcontainer_p.h b/src/widgets/kernel/qwindowcontainer_p.h
index 37c023fc1d..e2446bef42 100644
--- a/src/widgets/kernel/qwindowcontainer_p.h
+++ b/src/widgets/kernel/qwindowcontainer_p.h
@@ -57,6 +57,11 @@ public:
explicit QWindowContainer(QWindow *embeddedWindow, QWidget *parent = 0, Qt::WindowFlags f = 0);
~QWindowContainer();
+ static void parentWasChanged(QWidget *parent);
+ static void parentWasMoved(QWidget *parent);
+ static void parentWasRaised(QWidget *parent);
+ static void parentWasLowered(QWidget *parent);
+
protected:
bool event(QEvent *ev);
diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
index 2d9cb98e27..c17a03e058 100644
--- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
+++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
@@ -68,8 +68,6 @@ public:
int numberOfObscures;
};
-
-
class tst_QWindowContainer: public QObject
{
Q_OBJECT
@@ -81,6 +79,7 @@ private slots:
void testBehindTheScenesDeletion();
void testUnparenting();
void testActivation();
+ void testAncestorChange();
};
@@ -188,6 +187,7 @@ void tst_QWindowContainer::testActivation()
root.show();
root.activateWindow();
+ QVERIFY(QTest::qWaitForWindowExposed(&root));
QVERIFY(QTest::qWaitForWindowActive(root.windowHandle()));
QVERIFY(QGuiApplication::focusWindow() == root.windowHandle());
@@ -204,8 +204,7 @@ void tst_QWindowContainer::testActivation()
QTest::qWait(100);
window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window));
- QVERIFY(QGuiApplication::focusWindow() == window);
+ QTRY_VERIFY(QGuiApplication::focusWindow() == window);
// Verify that all states in the root widget still indicate it is active
QVERIFY(root.windowHandle()->isActive());
@@ -231,6 +230,61 @@ void tst_QWindowContainer::testUnparenting()
QVERIFY(!window->isVisible());
}
+void tst_QWindowContainer::testAncestorChange()
+{
+ QWidget root;
+ QWidget *left = new QWidget(&root);
+ QWidget *right = new QWidget(&root);
+
+ root.setGeometry(0, 0, 200, 100);
+ left->setGeometry(0, 0, 100, 100);
+ right->setGeometry(100, 0, 100, 100);
+
+ QWindow *window = new QWindow();
+ QWidget *container = QWidget::createWindowContainer(window, left);
+ container->setGeometry(0, 0, 100, 100);
+
+ // Root
+ // + left
+ // | + container
+ // | + window
+ // + right
+ root.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&root));
+ QCOMPARE(window->geometry(), QRect(0, 0, 100, 100));
+
+ container->setParent(right);
+ // Root
+ // + left
+ // + right
+ // + container
+ // + window
+ QCOMPARE(window->geometry(), QRect(100, 0, 100, 100));
+
+ QWidget *newRoot = new QWidget(&root);
+ newRoot->setGeometry(50, 50, 200, 200);
+ right->setParent(newRoot);
+ // Root
+ // + left
+ // + newRoot
+ // + right
+ // + container
+ // + window
+ QCOMPARE(window->geometry(), QRect(150, 50, 100, 100));
+ newRoot->move(0, 0);
+ QCOMPARE(window->geometry(), QRect(100, 0, 100, 100));
+
+ newRoot->setParent(0);
+ newRoot->setGeometry(100, 100, 200, 200);
+ newRoot->show();
+ QVERIFY(QTest::qWaitForWindowExposed(newRoot));
+ // newRoot
+ // + right
+ // + container
+ // + window
+ QCOMPARE(window->geometry(), QRect(100, 0, 100, 100));
+}
+
QTEST_MAIN(tst_QWindowContainer)
#include "tst_qwindowcontainer.moc"