2 * Copyright (C) 2015 Canonical, Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 import QtQuick.Window 2.2
19 import Unity.InputInfo 0.1
20 import Unity.Session 0.1
21 import Unity.Screens 0.1
26 // Workaround https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1473471
27 import Ubuntu.Components 1.3
33 implicitWidth: units.gu(40)
34 implicitHeight: units.gu(71)
37 id: deviceConfiguration
38 name: applicationArguments.deviceName
41 property alias orientations: d.orientations
46 property Orientations orientations: Orientations {
48 // NB: native and primary orientations here don't map exactly to their QScreen counterparts
49 native_: root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
51 primary: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
52 ? native_ : deviceConfiguration.primaryOrientation
54 landscape: deviceConfiguration.landscapeOrientation
55 invertedLandscape: deviceConfiguration.invertedLandscapeOrientation
56 portrait: deviceConfiguration.portraitOrientation
57 invertedPortrait: deviceConfiguration.invertedPortraitOrientation
60 // to be overwritten by tests
61 property var unity8Settings: Unity8Settings {}
62 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
64 property int physicalOrientation: Screen.orientation
65 property bool orientationLocked: OrientationLock.enabled
66 property var orientationLock: OrientationLock
70 deviceFilter: InputInfo.Mouse
75 deviceFilter: InputInfo.TouchPad
80 deviceFilter: InputInfo.Keyboard
81 onDeviceAdded: forceOSKEnabled = autopilotDevicePresent();
82 onDeviceRemoved: forceOSKEnabled = autopilotDevicePresent();
87 deviceFilter: InputInfo.TouchScreen
90 /* FIXME: This exposes the NameRole as a work arround for lp:1542224.
91 * When QInputInfo exposes NameRole to QML, this should be removed.
93 property bool forceOSKEnabled: false
94 property var autopilotEmulatedDeviceNames: ["py-evdev-uinput"]
95 UnitySortFilterProxyModel {
100 function autopilotDevicePresent() {
101 for(var i = 0; i < autopilotDevices.count; i++) {
102 var device = autopilotDevices.get(i);
103 if (autopilotEmulatedDeviceNames.indexOf(device.name) != -1) {
104 console.warn("Forcing the OSK to be enabled as there is an autopilot eumlated device present.")
115 property int orientation
116 onPhysicalOrientationChanged: {
117 if (!orientationLocked) {
118 orientation = physicalOrientation;
121 onOrientationLockedChanged: {
122 if (orientationLocked) {
123 orientationLock.savedOrientation = physicalOrientation;
125 orientation = physicalOrientation;
128 Component.onCompleted: {
129 if (orientationLocked) {
130 orientation = orientationLock.savedOrientation;
132 // We need to manually update this on startup as the binding
133 // below doesn't seem to have any effect at that stage
134 oskSettings.disableHeight = !shell.oskEnabled || shell.usageScenario == "desktop"
137 // we must rotate to a supported orientation regardless of shell's preference
138 property bool orientationChangesEnabled:
139 (shell.orientation & supportedOrientations) === 0 ? true
140 : shell.orientationChangesEnabled
144 property: "disableHeight"
145 value: !shell.oskEnabled || shell.usageScenario == "desktop"
148 readonly property int supportedOrientations: shell.supportedOrientations
149 & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation
150 ? orientations.native_
151 : deviceConfiguration.supportedOrientations)
153 property int acceptedOrientationAngle: {
154 if (orientation & supportedOrientations) {
155 return Screen.angleBetween(orientations.native_, orientation);
156 } else if (shell.orientation & supportedOrientations) {
158 return shell.orientationAngle;
159 } else if (angleToOrientation(shell.mainAppWindowOrientationAngle) & supportedOrientations) {
160 return shell.mainAppWindowOrientationAngle;
162 // rotate to some supported orientation as we can't stay where we currently are
163 // TODO: Choose the closest to the current one
164 if (supportedOrientations & Qt.PortraitOrientation) {
165 return Screen.angleBetween(orientations.native_, Qt.PortraitOrientation);
166 } else if (supportedOrientations & Qt.LandscapeOrientation) {
167 return Screen.angleBetween(orientations.native_, Qt.LandscapeOrientation);
168 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
169 return Screen.angleBetween(orientations.native_, Qt.InvertedPortraitOrientation);
170 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
171 return Screen.angleBetween(orientations.native_, Qt.InvertedLandscapeOrientation);
173 // if all fails, fallback to primary orientation
174 return Screen.angleBetween(orientations.native_, orientations.primary);
179 function angleToOrientation(angle) {
182 return orientations.native_;
184 return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
185 : Qt.PortraitOrientation;
187 return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
188 : Qt.InvertedLandscapeOrientation;
190 return orientations.native_ === Qt.PortraitOrientation ? Qt.LandscapeOrientation
191 : Qt.InvertedPortraitOrientation;
193 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
194 return orientations.primary;
200 objectName: "rotationStates"
203 shellCover: shellCover
204 windowScreenshot: windowScreenshot
212 orientation: root.angleToOrientation(orientationAngle)
213 orientations: root.orientations
214 nativeWidth: root.width
215 nativeHeight: root.height
216 mode: applicationArguments.mode
217 hasMouse: miceModel.count + touchPadModel.count > 0
218 // TODO: Factor in if the current screen is a touch screen and if the user wants to
219 // have multiple keyboards around. For now we only enable one keyboard at a time
220 // thus hiding it here if there is a physical one around or if we have a second
221 // screen (the virtual touchpad & osk on the phone) attached.
222 oskEnabled: (keyboardsModel.count === 0 && screens.count === 1) ||
225 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
226 // what's the output device (eg: big TV, desktop monitor, phone display), etc.
228 if (root.unity8Settings.usageMode === "Windowed") {
230 } else if (root.unity8Settings.usageMode === "Staged") {
231 if (deviceConfiguration.category === "phone") {
236 } else { // automatic
237 var longEdgeWidth = Math.max(root.width, root.height)
238 if (longEdgeWidth > units.gu(120)) {
239 if (keyboardsModel.count + miceModel.count + touchPadModel.count > 0) {
242 } else if (longEdgeWidth > units.gu(90)){
243 if (miceModel.count + touchPadModel.count > 0) {
248 return deviceConfiguration.category;
252 property real transformRotationAngle
253 property real transformOriginX
254 property real transformOriginY
256 transform: Rotation {
257 origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
258 angle: shell.transformRotationAngle
275 property real transformRotationAngle
276 property real transformOriginX
277 property real transformOriginY
279 transform: Rotation {
280 origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
281 axis { x: 0; y: 0; z: 1 }
282 angle: windowScreenshot.transformRotationAngle