diff options
author | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2014-05-19 11:51:31 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2014-06-18 20:06:27 +0200 |
commit | bcaf2f08d9189c6d677143cbb8455b2a7fe900b7 (patch) | |
tree | eabe20af458eda0267c67e6f6f8f2d9aed87cfe5 | |
parent | a29b65af05b4d501e6b1d8a72be50366666a3caa (diff) |
Fix screen handling for child windows.
Change the semantics of QWindowPrivate::screen to contain the screen of
top level window only. Child windows always return the screen of their
toplevel window by recursing up.
The QPA plugins then no longer need to report screen changes for child
windows.
Change setScreen() accordingly, bail out for child windows, and
emit screenChanged() recursively.
Also add a check to setParent() preventing screen changes.
Task-number: QTBUG-36659
Change-Id: I19c8e12217cba1513e947a027f2492abc7b98816
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 2 | ||||
-rw-r--r-- | src/gui/kernel/qwindow.cpp | 108 | ||||
-rw-r--r-- | src/gui/kernel/qwindow_p.h | 10 |
3 files changed, 83 insertions, 37 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index b49f5f00ce..5bbd5e709c 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1956,7 +1956,7 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf { if (QWindow *window = wse->window.data()) { if (QScreen *screen = wse->screen.data()) - window->d_func()->setScreen(screen, false /* recreate */); + window->d_func()->setTopLevelScreen(screen, false /* recreate */); else // Fall back to default behavior, and try to find some appropriate screen window->setScreen(0); } diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index bebf3ab6c4..5630199da9 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -156,9 +156,7 @@ QWindow::QWindow(QScreen *targetScreen) , QSurface(QSurface::Window) { Q_D(QWindow); - d->screen = targetScreen; - if (!d->screen) - d->screen = QGuiApplication::primaryScreen(); + d->connectToScreen(targetScreen ? targetScreen : QGuiApplication::primaryScreen()); d->init(); } @@ -178,10 +176,8 @@ QWindow::QWindow(QWindow *parent) { Q_D(QWindow); d->parentWindow = parent; - if (parent) - d->screen = parent->screen(); - if (!d->screen) - d->screen = QGuiApplication::primaryScreen(); + if (!parent) + d->connectToScreen(QGuiApplication::primaryScreen()); d->init(); } @@ -203,10 +199,8 @@ QWindow::QWindow(QWindowPrivate &dd, QWindow *parent) { Q_D(QWindow); d->parentWindow = parent; - if (parent) - d->screen = parent->screen(); - if (!d->screen) - d->screen = QGuiApplication::primaryScreen(); + if (!parent) + d->connectToScreen(QGuiApplication::primaryScreen()); d->init(); } @@ -231,11 +225,10 @@ void QWindowPrivate::init() // If your application aborts here, you are probably creating a QWindow // before the screen list is populated. - if (!screen) { + if (!parentWindow && !topLevelScreen) { qFatal("Cannot create window: no screens available"); exit(1); } - QObject::connect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*))); QGuiApplicationPrivate::window_list.prepend(q); } @@ -353,23 +346,57 @@ void QWindowPrivate::updateVisibility() emit q->visibilityChanged(visibility); } -void QWindowPrivate::setScreen(QScreen *newScreen, bool recreate) +inline bool QWindowPrivate::windowRecreationRequired(QScreen *newScreen) const +{ + Q_Q(const QWindow); + const QScreen *oldScreen = q->screen(); + return oldScreen != newScreen && platformWindow + && !(oldScreen && oldScreen->virtualSiblings().contains(newScreen)); +} + +inline void QWindowPrivate::disconnectFromScreen() +{ + if (topLevelScreen) { + Q_Q(QWindow); + QObject::disconnect(topLevelScreen, &QObject::destroyed, q, &QWindow::screenDestroyed); + topLevelScreen = 0; + } +} + +void QWindowPrivate::connectToScreen(QScreen *screen) +{ + Q_Q(QWindow); + disconnectFromScreen(); + topLevelScreen = screen; + if (topLevelScreen) + QObject::connect(topLevelScreen, &QObject::destroyed, q, &QWindow::screenDestroyed); +} + +void QWindowPrivate::emitScreenChangedRecursion(QScreen *newScreen) +{ + Q_Q(QWindow); + emit q->screenChanged(newScreen); + foreach (QObject *child, q->children()) { + if (child->isWindowType()) + static_cast<QWindow *>(child)->d_func()->emitScreenChangedRecursion(newScreen); + } +} + +void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate) { Q_Q(QWindow); - if (newScreen != screen) { - const bool shouldRecreate = recreate && platformWindow != 0 - && !(screen && screen->virtualSiblings().contains(newScreen)); + if (parentWindow) { + qWarning() << this << Q_FUNC_INFO << '(' << newScreen << "): Attempt to set a screen on a child window."; + return; + } + if (newScreen != topLevelScreen) { + const bool shouldRecreate = recreate && windowRecreationRequired(newScreen); if (shouldRecreate) q->destroy(); - if (screen) - q->disconnect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*))); - screen = newScreen; - if (newScreen) { - q->connect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*))); - if (shouldRecreate) - q->create(); - } - emit q->screenChanged(newScreen); + connectToScreen(newScreen); + if (newScreen && shouldRecreate) + q->create(); + emitScreenChangedRecursion(newScreen); } } @@ -552,8 +579,20 @@ QWindow *QWindow::parent() const void QWindow::setParent(QWindow *parent) { Q_D(QWindow); + if (d->parentWindow == parent) + return; + + QScreen *newScreen = parent ? parent->screen() : screen(); + if (d->windowRecreationRequired(newScreen)) { + qWarning() << this << Q_FUNC_INFO << '(' << parent << "): Cannot change screens (" << screen() << newScreen << ')'; + return; + } QObject::setParent(parent); + if (parent) + d->disconnectFromScreen(); + else + d->connectToScreen(newScreen); if (d->platformWindow) { if (parent && parent->d_func()->platformWindow) { @@ -1606,15 +1645,14 @@ bool QWindow::setMouseGrabEnabled(bool grab) /*! Returns the screen on which the window is shown. - The value returned will not change when the window is moved - between virtual screens (as returned by QScreen::virtualSiblings()). + For child windows, this returns the screen of the corresponding top level window. \sa setScreen(), QScreen::virtualSiblings() */ QScreen *QWindow::screen() const { Q_D(const QWindow); - return d->screen; + return d->parentWindow ? d->parentWindow->screen() : d->topLevelScreen; } /*! @@ -1625,6 +1663,8 @@ QScreen *QWindow::screen() const Note that if the screen is part of a virtual desktop of multiple screens, the window can appear on any of the screens returned by QScreen::virtualSiblings(). + This function only works for top level windows. + \sa screen(), QScreen::virtualSiblings() */ void QWindow::setScreen(QScreen *newScreen) @@ -1632,13 +1672,15 @@ void QWindow::setScreen(QScreen *newScreen) Q_D(QWindow); if (!newScreen) newScreen = QGuiApplication::primaryScreen(); - d->setScreen(newScreen, true /* recreate */); + d->setTopLevelScreen(newScreen, true /* recreate */); } void QWindow::screenDestroyed(QObject *object) { Q_D(QWindow); - if (object == static_cast<QObject *>(d->screen)) { + if (d->parentWindow) + return; + if (object == static_cast<QObject *>(d->topLevelScreen)) { const bool wasVisible = isVisible(); setScreen(0); // destroy() might have hidden our window, show it again. @@ -2326,7 +2368,7 @@ void QWindowPrivate::setCursor(const QCursor *newCursor) hasCursor = false; } // Only attempt to set cursor and emit signal if there is an actual platform cursor - if (screen->handle()->cursor()) { + if (q->screen()->handle()->cursor()) { applyCursor(); QEvent event(QEvent::CursorChange); QGuiApplication::sendEvent(q, &event); @@ -2337,7 +2379,7 @@ void QWindowPrivate::applyCursor() { Q_Q(QWindow); if (platformWindow) { - if (QPlatformCursor *platformCursor = screen->handle()->cursor()) { + if (QPlatformCursor *platformCursor = q->screen()->handle()->cursor()) { QCursor *c = QGuiApplication::overrideCursor(); if (!c && hasCursor) c = &cursor; diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 4305edea51..0c58745735 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -95,7 +95,7 @@ public: , modality(Qt::NonModal) , blockedByModalWindow(false) , transientParent(0) - , screen(0) + , topLevelScreen(0) #ifndef QT_NO_CURSOR , cursor(Qt::ArrowCursor) , hasCursor(false) @@ -131,7 +131,11 @@ public: void updateVisibility(); void _q_clearAlert(); - void setScreen(QScreen *newScreen, bool recreate); + bool windowRecreationRequired(QScreen *newScreen) const; + void setTopLevelScreen(QScreen *newScreen, bool recreate); + void connectToScreen(QScreen *topLevelScreen); + void disconnectFromScreen(); + void emitScreenChangedRecursion(QScreen *newScreen); virtual void clearFocusObject(); @@ -165,7 +169,7 @@ public: bool blockedByModalWindow; QPointer<QWindow> transientParent; - QScreen *screen; + QScreen *topLevelScreen; #ifndef QT_NO_CURSOR QCursor cursor; |