diff options
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r-- | src/widgets/kernel/qdesktopwidget.cpp | 99 | ||||
-rw-r--r-- | src/widgets/kernel/qdesktopwidget_p.h | 16 | ||||
-rw-r--r-- | src/widgets/kernel/qopenglwidget.cpp | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetbackingstore.cpp | 22 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetbackingstore_p.h | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 8 |
6 files changed, 106 insertions, 45 deletions
diff --git a/src/widgets/kernel/qdesktopwidget.cpp b/src/widgets/kernel/qdesktopwidget.cpp index fceb061867..ece673337a 100644 --- a/src/widgets/kernel/qdesktopwidget.cpp +++ b/src/widgets/kernel/qdesktopwidget.cpp @@ -46,6 +46,21 @@ QT_BEGIN_NAMESPACE +QDesktopScreenWidget::QDesktopScreenWidget(QScreen *screen, const QRect &geometry) + : QWidget(Q_NULLPTR, Qt::Desktop), m_screen(screen) +{ + setVisible(false); + if (QWindow *winHandle = windowHandle()) + winHandle->setScreen(screen); + setScreenGeometry(geometry); +} + +void QDesktopScreenWidget::setScreenGeometry(const QRect &geometry) +{ + m_geometry = geometry; + setGeometry(geometry); +} + int QDesktopScreenWidget::screenNumber() const { const QDesktopWidgetPrivate *desktopWidgetP @@ -80,54 +95,76 @@ const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const return rect; } +QDesktopScreenWidget *QDesktopWidgetPrivate::widgetForScreen(QScreen *qScreen) const +{ + foreach (QDesktopScreenWidget *widget, screens) { + if (widget->screen() == qScreen) + return widget; + } + return Q_NULLPTR; +} + void QDesktopWidgetPrivate::_q_updateScreens() { Q_Q(QDesktopWidget); const QList<QScreen *> screenList = QGuiApplication::screens(); const int targetLength = screenList.length(); - const int oldLength = screens.length(); - - // Add or remove screen widgets as necessary - while (screens.size() > targetLength) - delete screens.takeLast(); - - for (int currentLength = screens.size(); currentLength < targetLength; ++currentLength) { - QScreen *qScreen = screenList.at(currentLength); - QDesktopScreenWidget *screenWidget = new QDesktopScreenWidget; - screenWidget->setGeometry(qScreen->geometry()); - QObject::connect(qScreen, SIGNAL(geometryChanged(QRect)), - q, SLOT(_q_updateScreens()), Qt::QueuedConnection); - QObject::connect(qScreen, SIGNAL(availableGeometryChanged(QRect)), - q, SLOT(_q_availableGeometryChanged()), Qt::QueuedConnection); - QObject::connect(qScreen, SIGNAL(destroyed()), - q, SLOT(_q_updateScreens()), Qt::QueuedConnection); - screens.append(screenWidget); - } + bool screenCountChanged = false; + // Re-build our screens list. This is the easiest way to later compute which signals to emit. + // Create new screen widgets as necessary. While iterating, keep the old list in place so + // that widgetForScreen works. + // Furthermore, we note which screens have changed, and compute the overall virtual geometry. + QList<QDesktopScreenWidget *> newScreens; + QList<int> changedScreens; QRegion virtualGeometry; - // update the geometry of each screen widget, determine virtual geometry, - // set the new screen for window handle and emit change signals afterwards. - QList<int> changedScreens; - for (int i = 0; i < screens.length(); i++) { - QDesktopScreenWidget *screenWidget = screens.at(i); + for (int i = 0; i < targetLength; ++i) { QScreen *qScreen = screenList.at(i); - QWindow *winHandle = screenWidget->windowHandle(); - if (winHandle && winHandle->screen() != qScreen) - winHandle->setScreen(qScreen); const QRect screenGeometry = qScreen->geometry(); - if (screenGeometry != screenWidget->geometry()) { - screenWidget->setGeometry(screenGeometry); - changedScreens.push_back(i); + QDesktopScreenWidget *screenWidget = widgetForScreen(qScreen); + if (screenWidget) { + // an old screen. update geometry and remember the index in the *new* list + if (screenGeometry != screenWidget->screenGeometry()) { + screenWidget->setScreenGeometry(screenGeometry); + changedScreens.push_back(i); + } + } else { + // a new screen, create a widget and connect the signals. + screenWidget = new QDesktopScreenWidget(qScreen, screenGeometry); + QObject::connect(qScreen, SIGNAL(geometryChanged(QRect)), + q, SLOT(_q_updateScreens()), Qt::QueuedConnection); + QObject::connect(qScreen, SIGNAL(availableGeometryChanged(QRect)), + q, SLOT(_q_availableGeometryChanged()), Qt::QueuedConnection); + QObject::connect(qScreen, SIGNAL(destroyed()), + q, SLOT(_q_updateScreens()), Qt::QueuedConnection); + screenCountChanged = true; } + // record all the screens and the overall geometry. + newScreens.push_back(screenWidget); virtualGeometry += screenGeometry; } + // Now we apply the accumulated updates. + screens.swap(newScreens); // now [newScreens] is the old screen list + Q_ASSERT(screens.size() == targetLength); q->setGeometry(virtualGeometry.boundingRect()); - if (oldLength != targetLength) - emit q->screenCountChanged(targetLength); + // Delete the QDesktopScreenWidget that are not used any more. + foreach (QDesktopScreenWidget *screen, newScreens) { + if (!screens.contains(screen)) { + delete screen; + screenCountChanged = true; + } + } + // Finally, emit the signals. + if (screenCountChanged) { + // Notice that we trigger screenCountChanged even if a screen was removed and another one added, + // in which case the total number of screens did not change. This is the only way for applications + // to notice that a screen was swapped out against another one. + emit q->screenCountChanged(targetLength); + } foreach (int changedScreen, changedScreens) emit q->resized(changedScreen); } diff --git a/src/widgets/kernel/qdesktopwidget_p.h b/src/widgets/kernel/qdesktopwidget_p.h index 7c68ad9b31..a590024b7c 100644 --- a/src/widgets/kernel/qdesktopwidget_p.h +++ b/src/widgets/kernel/qdesktopwidget_p.h @@ -61,12 +61,19 @@ QT_BEGIN_NAMESPACE class QDesktopScreenWidget : public QWidget { Q_OBJECT public: - QDesktopScreenWidget() : QWidget(Q_NULLPTR, Qt::Desktop) - { - setVisible(false); - } + explicit QDesktopScreenWidget(QScreen *screen, const QRect &geometry); int screenNumber() const; + void setScreenGeometry(const QRect &geometry); + + QScreen *screen() const { return m_screen.data(); } + QRect screenGeometry() const { return m_geometry; } + +private: + // The widget updates its screen and geometry automatically. We need to save them separately + // to detect changes, and trigger the appropriate signals. + const QPointer<QScreen> m_screen; + QRect m_geometry; }; class QDesktopWidgetPrivate : public QWidgetPrivate { @@ -76,6 +83,7 @@ public: ~QDesktopWidgetPrivate() { qDeleteAll(screens); } void _q_updateScreens(); void _q_availableGeometryChanged(); + QDesktopScreenWidget *widgetForScreen(QScreen *qScreen) const; QList<QDesktopScreenWidget *> screens; }; diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 5071c56763..124c8c000a 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -910,8 +910,10 @@ void QOpenGLWidgetPrivate::resizeViewportFramebuffer() if (!initialized) return; - if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size()) + if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size()) { recreateFbo(); + q->update(); + } } /*! diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 7c9ac5571c..ecaba584f2 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -992,8 +992,18 @@ static QPlatformTextureList *widgetTexturesFor(QWidget *tlw, QWidget *widget) static bool switchableWidgetComposition = QGuiApplicationPrivate::instance()->platformIntegration() ->hasCapability(QPlatformIntegration::SwitchableWidgetComposition); - if (!switchableWidgetComposition) + if (!switchableWidgetComposition +// The Windows compositor handles fullscreen OpenGL window specially. Besides +// having trouble with popups, it also has issues with flip-flopping between +// OpenGL-based and normal flushing. Therefore, stick with GL for fullscreen +// windows. (QTBUG-53515) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE) + || tlw->windowState().testFlag(Qt::WindowFullScreen) +#endif + ) + { return qt_dummy_platformTextureList(); + } } return 0; @@ -1192,10 +1202,20 @@ void QWidgetBackingStore::doSync() // We know for sure that the widget isn't overlapped if 'isMoved' is true. if (!wd->isMoved) wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove); + + // Make a copy of the widget's dirty region, to restore it in case there is an opaque + // render-to-texture child that completely covers the widget, because otherwise the + // render-to-texture child won't be visible, due to its parent widget not being redrawn + // with a proper blending mask. + const QRegion dirtyBeforeSubtractedOpaqueChildren = wd->dirty; + // Scrolled and moved widgets must draw all children. if (!wd->isScrolled && !wd->isMoved) wd->subtractOpaqueChildren(wd->dirty, w->rect()); + if (wd->dirty.isEmpty() && wd->textureChildSeen) + wd->dirty = dirtyBeforeSubtractedOpaqueChildren; + if (wd->dirty.isEmpty()) { resetWidget(w); continue; diff --git a/src/widgets/kernel/qwidgetbackingstore_p.h b/src/widgets/kernel/qwidgetbackingstore_p.h index a7dbfafc05..dc20446047 100644 --- a/src/widgets/kernel/qwidgetbackingstore_p.h +++ b/src/widgets/kernel/qwidgetbackingstore_p.h @@ -116,7 +116,7 @@ public: inline bool isDirty() const { - return !(dirtyWidgets.isEmpty() && dirty.isEmpty()); + return !(dirtyWidgets.isEmpty() && dirty.isEmpty() && dirtyRenderToTextureWidgets.isEmpty()); } // ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 675d54f6b4..2a4f31babf 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -883,14 +883,8 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event) { if (isExposed()) { m_widget->setAttribute(Qt::WA_Mapped); - if (!event->region().isNull()) { - // Exposed native widgets need to be marked dirty to get them repainted correctly. - if (m_widget->internalWinId() && !m_widget->isWindow() && m_widget->isVisible() && m_widget->updatesEnabled()) { - if (QWidgetBackingStore *bs = m_widget->d_func()->maybeBackingStore()) - bs->markDirty(event->region(), m_widget); - } + if (!event->region().isNull()) m_widget->d_func()->syncBackingStore(event->region()); - } } else { m_widget->setAttribute(Qt::WA_Mapped, false); } |