summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@digia.com>2013-10-18 12:36:47 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-22 10:46:21 +0200
commit72a7882cec07a9ad187c9e1772fb08f59a4b9519 (patch)
tree40e57146d54e551837c0b1ff7ccac65a3a5a8d25 /src/widgets
parentc9ad904af9b6009205f5d02779c407fcd65b8d12 (diff)
Better QWindowContainer by not relying on native widgets.
We change the behavior slightly from the initial implementation in 5.1. Forcing the use of native child widgets is causing massive performance issues so instead, we attach the embedded QWindow directly to the root window. The only exception is QScrollArea and QMdiArea which still enforces native windows for the entire parent chain to make clipping and stacking work. Task-number: QTBUG-34138 Change-Id: If713637bd4dce630552ace2f8ad6b2e86c063721 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/widgets')
-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
4 files changed, 172 insertions, 23 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);