Skip to content

Instantly share code, notes, and snippets.

@torarnv torarnv/orientation.md
Last active Aug 10, 2019

Embed
What would you like to do?

Orientation overview in Qt

Terms

  • Auto-rotation: the process where the platform will read sensor data about the physical screen orientation and apply that to the screen properties, so that eg. a screen in a physical landscape orientation will have an observable width > height.
  • Orientation-lock: More or less granular configuration of which orientations the platform is allowed to auto-rotate into

APIs

  • QScreen::nativeOrienation: the fixed standard-orientation of the physical screen, eg the orienation where the logo makes sense. Typically landscape for desktop screens. Never changes.
  • QScreen::primaryOrienation: the 'logical' orientation of the screen, computed from its geometry properties. Typically landscape or portrait, depending on the width and height ratio. A screen that auto-rotated due to sensor input of the physical screen will have a new primary orientation.
  • QScreen::orientation: the physical orientation of the screen, resulting from reading sensor data about the screen when the orientationUpdateMask has been been set.
  • QScreen::orientationUpdateMask: limits which orientations are reflected in the orientation property. The default value is 0, meaning the orientation property will not change. This allows Qt to tell the system that we are not interested in orientation sensor updates. If the system then does not require any sensor readings of its own (due to auto-rotation, eg), it can disable the sensor and save battery. This is why the default is 0.
  • QWindow::reportContentOrientation: allows the application to inform the system that the content is oriented differently then what you would expect fromQScreen::primaryOrienation, which allows the system to orient system-provided UI elements such as statusbars and system alert dialogs in the same orientation.

Note that we currenly have no API in Qt to configure auto-rotation (orientation-lock). This is partially because on both iOS and Android orientation-lock (or supported orientations) is a combination of build-system properties and runtime properties, which we haven't been able to unify as a single Qt API.

UC1: Application supports all orientations and will re-layout to available screen geometry

This scenario happens on eg. iOS, where the platform will by default auto-rotate to most orientations. During auto-rotation we reconfigure the QScreen, which then gets a new width and height (geometry), and in effect a new primaryOrientation.

The orientation property will stay static (based on what the orientation of the device was at startup), unless the orientationUpdateMask is set. If set (to match all orientations), the orientation property will start reporting the same value as primaryOrientation, since the two are in sync due to auto-rotation. This is convenience for using a QOrientationSensor.

If the auto-rotation (supported orientations) have been configured in eg. Xcode to limit to only portrait and landscape, not the inverse counterparts, the primaryOrientation property will only switch between the two former orientations, while the orientation property will report changes for all orientations that are part of the orientationUpdateMask.

UC2: Application supports only a single orientation

An application may be designed for only a single orientation, typically portrait on a mobile device. In this case the system APIs are used to lock the orientation (limit the supported orientations), eg using Xcode/Info.plist for iOS.

The primaryOrientation in this case stays in portrait, and never changes. The same goes for the orientation propery, as the orientationUpdateMask is by default 0. This allows the platform to ignore orientation sensor readings and possibly save battery.

UC3: Application supports multiple orientations, but want custom orientation transitions/animations

Auto-rotation by the system happens using system transitions/animations, typically a rotation of the whole window. In some cases (games eg.) it might be nicer to have a custom transition, eg. on individual items in the scene instead of the whole scene as one.

For this to work, step one is to disable auto-rotation, eg. by configuring supported orientation in Xcode/Info.plist for iOS, similar to #UC2. This means the primaryOrientation will be static (typically portrait).

Next, we set the orientationUpdateMask so that we start reciving changes to the orientation property. This could be done using QOrientationSensor as well. Once we know the current physical orientation of the device, we apply a rotation transform with animation transition to eg. the individual items in the scene.

At this point the content of our application will rotate to match the physicall device orientation (using a cool custom animation), but any system UI elements such as the statusbar or system alert dialogs will pop up in portrait mode, since as far as the system knows, the screen is in portrait mode, as reflected by the primaryOrientation property.

This is where reportContentOrientation enters the picture. By reporting the true orientation of the content back to the system, it can adjust its UI elements to match our content orientation.

Questions

  • Q1: Why does not orientation follow primaryOrientation when no orientationUpdateMask has been set? A change in primaryOrientation means the system internally is checking the orientation sensor, so even if the application doesn't explicitly request updates to the orientation, we can still assume that the orientation has also changed. Or can we? Are there other ways the primaryOrientation can change were the physical orientation of the device stays the same?
    A1: Discussed here: https://gist.github.com/torarnv/0c9d36108f838c7bac9c and here: https://codereview.qt-project.org/#/c/95661/.

  • Q2: What are the different states of the orientation property?
    A2: The property has the following behavior:

    1. When QScreenis constructed based on an added QPlatformScreen, the QScreenPrivate constructor will read out the orientation from the platform screen, and set that as the initial filteredOrientation (falling back to the effective primary orientation if the platform screen returns Qt::PrimaryOrientation). This initialization of filteredOrienation is not filtered by any orientation update mask, so the platform screen is allowed to initialize the orientation to the actual physical orientation of the device.
    2. After QScreen construction, the getter for the property in QScreen just returns the internal filteredOrientation, meaning the only way to update the orientation after a screen has been added is to call QWindowSystemInterface::handleOrientationChange(). The new orientation will then only be reflected if the orientationUpdateMask matches the new orientation.
    3. For every call to setOrientationUpdateMask the internal orientation of the screen will be re-evaluated against the mask, and filteredOrientation will possibly be updated and a change signal emitted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.