diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index f71e611303..3e999bee8d 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1796,6 +1796,20 @@ void QGuiApplicationPrivate::reportScreenOrientationChange(QWindowSystemInterfac QScreen *s = e->screen.data(); s->d_func()->orientation = e->orientation; + updateFilteredScreenOrientation(s); +} + +void QGuiApplicationPrivate::updateFilteredScreenOrientation(QScreen *s) +{ + Qt::ScreenOrientation o = s->d_func()->orientation; + if (o == Qt::PrimaryOrientation) + o = s->primaryOrientation(); + o = Qt::ScreenOrientation(o & s->orientationUpdateMask()); + if (o == Qt::PrimaryOrientation) + return; + if (o == s->d_func()->filteredOrientation) + return; + s->d_func()->filteredOrientation = o; reportScreenOrientationChange(s); } @@ -1820,7 +1834,6 @@ void QGuiApplicationPrivate::reportGeometryChange(QWindowSystemInterfacePrivate: s->d_func()->geometry = e->geometry; Qt::ScreenOrientation primaryOrientation = s->primaryOrientation(); - Qt::ScreenOrientation orientation = s->orientation(); s->d_func()->updatePrimaryOrientation(); emit s->sizeChanged(s->size()); @@ -1834,8 +1847,8 @@ void QGuiApplicationPrivate::reportGeometryChange(QWindowSystemInterfacePrivate: if (s->primaryOrientation() != primaryOrientation) emit s->primaryOrientationChanged(s->primaryOrientation()); - if (s->orientation() != orientation) - reportScreenOrientationChange(s); + if (s->d_func()->orientation == Qt::PrimaryOrientation) + updateFilteredScreenOrientation(s); } void QGuiApplicationPrivate::reportAvailableGeometryChange( diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index e79c2afdf2..d538c393d7 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -112,6 +112,7 @@ public: static void processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e); + static void updateFilteredScreenOrientation(QScreen *screen); static void reportScreenOrientationChange(QScreen *screen); static void reportScreenOrientationChange(QWindowSystemInterfacePrivate::ScreenOrientationEvent *e); static void reportGeometryChange(QWindowSystemInterfacePrivate::ScreenGeometryEvent *e); diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h index 4baf0f65fb..31d459dffe 100644 --- a/src/gui/kernel/qplatformscreen.h +++ b/src/gui/kernel/qplatformscreen.h @@ -103,6 +103,7 @@ public: virtual Qt::ScreenOrientation nativeOrientation() const; virtual Qt::ScreenOrientation orientation() const; + virtual void setOrientationUpdateMask(Qt::ScreenOrientations mask); virtual QWindow *topLevelAt(const QPoint &point) const; virtual QList virtualSiblings() const; diff --git a/src/gui/kernel/qplatformscreen_qpa.cpp b/src/gui/kernel/qplatformscreen_qpa.cpp index fdb5d32687..d946e4f240 100644 --- a/src/gui/kernel/qplatformscreen_qpa.cpp +++ b/src/gui/kernel/qplatformscreen_qpa.cpp @@ -195,6 +195,29 @@ Qt::ScreenOrientation QPlatformScreen::orientation() const return Qt::PrimaryOrientation; } +/* + Reimplement this function in subclass to filter out unneeded screen + orientation updates. + + The orientations will anyway be filtered before QScreen::orientationChanged() + is emitted, but the mask can be used by the platform plugin for example to + prevent having to have an accelerometer sensor running all the time, or to + improve the reported values. As an example of the latter, in case of only + Landscape | InvertedLandscape being set in the mask, on a platform that gets + its orientation readings from an accelerometer sensor embedded in a handheld + device, the platform can report transitions between the two even when the + device is held in an orientation that's closer to portrait. + + By default, the orientation update mask is empty, so unless this function + has been called with a non-empty mask the platform does not need to report + any orientation updates through + QWindowSystemInterface::handleScreenOrientationChange(). +*/ +void QPlatformScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) +{ + Q_UNUSED(mask); +} + QPlatformScreen * QPlatformScreen::platformScreenForWindow(const QWindow *window) { return window->screen()->handle(); diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index 2e0df43e66..fe8b15e9a0 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -344,6 +344,35 @@ QRect QScreen::availableVirtualGeometry() const return result; } +/*! + Sets the orientations that the application is interested in receiving + updates for in conjunction with this screen. + + For example, to receive orientation() updates and thus have + orientationChanged() signals being emitted for LandscapeOrientation and + InvertedLandscapeOrientation, call setOrientationUpdateMask() with the + argument Qt::LandscapeOrientation | Qt::InvertedLandscapeOrientation. + + The default, 0, means no orientationChanged() signals are fired. +*/ +void QScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) +{ + Q_D(QScreen); + d->orientationUpdateMask = mask; + d->platformScreen->setOrientationUpdateMask(mask); +} + +/*! + Returns the currently set orientation update mask. + + \sa setOrientationUpdateMask() +*/ +Qt::ScreenOrientations QScreen::orientationUpdateMask() const +{ + Q_D(const QScreen); + return d->orientationUpdateMask; +} + /*! \property QScreen::orientation \brief the screen orientation @@ -353,6 +382,11 @@ QRect QScreen::availableVirtualGeometry() const will change based on the device is being held, and a desktop display might be rotated so that it's in portrait mode. + Changes to this property will be filtered by orientationUpdateMask(), + so in order to receive orientation updates the application must first + call setOrientationUpdateMask() with a mask of the orientations it wants + to receive. + Qt::PrimaryOrientation is never returned. \sa primaryOrientation(), orientationChanged() @@ -360,7 +394,7 @@ QRect QScreen::availableVirtualGeometry() const Qt::ScreenOrientation QScreen::orientation() const { Q_D(const QScreen); - return d->orientation == Qt::PrimaryOrientation ? primaryOrientation() : d->orientation; + return d->filteredOrientation; } /*! diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h index 17f3cd3d43..6c142162fe 100644 --- a/src/gui/kernel/qscreen.h +++ b/src/gui/kernel/qscreen.h @@ -119,6 +119,9 @@ public: Qt::ScreenOrientation primaryOrientation() const; Qt::ScreenOrientation orientation() const; + Qt::ScreenOrientations orientationUpdateMask() const; + void setOrientationUpdateMask(Qt::ScreenOrientations mask); + int angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b) const; QTransform transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target) const; QRect mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect) const; diff --git a/src/gui/kernel/qscreen_p.h b/src/gui/kernel/qscreen_p.h index b0e1b8671a..ca29acdd08 100644 --- a/src/gui/kernel/qscreen_p.h +++ b/src/gui/kernel/qscreen_p.h @@ -58,6 +58,7 @@ class QScreenPrivate : public QObjectPrivate public: QScreenPrivate(QPlatformScreen *screen) : platformScreen(screen) + , orientationUpdateMask(0) { orientation = screen->orientation(); geometry = screen->geometry(); @@ -66,18 +67,24 @@ public: refreshRate = screen->refreshRate(); updatePrimaryOrientation(); + + filteredOrientation = orientation; + if (filteredOrientation == Qt::PrimaryOrientation) + filteredOrientation = primaryOrientation; } void updatePrimaryOrientation(); + QPlatformScreen *platformScreen; + + Qt::ScreenOrientations orientationUpdateMask; Qt::ScreenOrientation orientation; + Qt::ScreenOrientation filteredOrientation; Qt::ScreenOrientation primaryOrientation; QRect geometry; QRect availableGeometry; QDpi logicalDpi; qreal refreshRate; - - QPlatformScreen *platformScreen; }; QT_END_NAMESPACE diff --git a/tests/auto/gui/kernel/qscreen/tst_qscreen.cpp b/tests/auto/gui/kernel/qscreen/tst_qscreen.cpp index 475b6ca2a8..e6c28867c6 100644 --- a/tests/auto/gui/kernel/qscreen/tst_qscreen.cpp +++ b/tests/auto/gui/kernel/qscreen/tst_qscreen.cpp @@ -177,13 +177,26 @@ void tst_QScreen::transformBetween() void tst_QScreen::orientationChange() { + qRegisterMetaType("Qt::ScreenOrientation"); + QScreen *screen = QGuiApplication::primaryScreen(); + screen->setOrientationUpdateMask(Qt::LandscapeOrientation | Qt::PortraitOrientation); + QWindowSystemInterface::handleScreenOrientationChange(screen, Qt::LandscapeOrientation); QTRY_COMPARE(screen->orientation(), Qt::LandscapeOrientation); QWindowSystemInterface::handleScreenOrientationChange(screen, Qt::PortraitOrientation); QTRY_COMPARE(screen->orientation(), Qt::PortraitOrientation); + + QSignalSpy spy(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation))); + + QWindowSystemInterface::handleScreenOrientationChange(screen, Qt::InvertedLandscapeOrientation); + QWindowSystemInterface::handleScreenOrientationChange(screen, Qt::InvertedPortraitOrientation); + QWindowSystemInterface::handleScreenOrientationChange(screen, Qt::LandscapeOrientation); + + QTRY_COMPARE(screen->orientation(), Qt::LandscapeOrientation); + QCOMPARE(spy.count(), 1); } #include