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
32 implicitWidth: units.gu(40)
33 implicitHeight: units.gu(71)
35 onWidthChanged: calculateUsageMode();
38 id: deviceConfiguration
39 name: applicationArguments.deviceName
42 property alias orientations: d.orientations
47 property Orientations orientations: Orientations {
49 // NB: native and primary orientations here don't map exactly to their QScreen counterparts
50 native_: root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
52 primary: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
53 ? native_ : deviceConfiguration.primaryOrientation
55 landscape: deviceConfiguration.landscapeOrientation
56 invertedLandscape: deviceConfiguration.invertedLandscapeOrientation
57 portrait: deviceConfiguration.portraitOrientation
58 invertedPortrait: deviceConfiguration.invertedPortraitOrientation
64 schema.id: "com.canonical.Unity8"
69 objectName: "oskSettings"
70 schema.id: "com.canonical.keyboard.maliit"
73 property int physicalOrientation: Screen.orientation
74 property bool orientationLocked: OrientationLock.enabled
75 property var orientationLock: OrientationLock
79 deviceFilter: InputInfo.Mouse
80 property int oldCount: 0
85 deviceFilter: InputInfo.TouchPad
86 property int oldCount: 0
91 deviceFilter: InputInfo.Keyboard
92 onDeviceAdded: forceOSKEnabled = autopilotDevicePresent();
93 onDeviceRemoved: forceOSKEnabled = autopilotDevicePresent();
98 deviceFilter: InputInfo.TouchScreen
101 readonly property int pointerInputDevices: miceModel.count + touchPadModel.count
102 onPointerInputDevicesChanged: calculateUsageMode()
104 function calculateUsageMode() {
105 if (unity8Settings.usageMode === undefined)
106 return; // gsettings isn't loaded yet, we'll try again in Component.onCompleted
108 console.log("Calculating new usage mode. Pointer devices:", pointerInputDevices, "current mode:", unity8Settings.usageMode, "old device count", miceModel.oldCount + touchPadModel.oldCount, "root width:", root.width / units.gu(1), "height:", root.height / units.gu(1))
109 if (unity8Settings.usageMode === "Windowed") {
110 if (Math.min(root.width, root.height) > units.gu(60)) {
111 if (pointerInputDevices === 0) {
112 // All pointer devices have been unplugged. Move to staged.
113 unity8Settings.usageMode = "Staged";
116 // The display is not large enough, use staged.
117 unity8Settings.usageMode = "Staged";
120 if (Math.min(root.width, root.height) > units.gu(60)) {
121 if (pointerInputDevices > 0 && pointerInputDevices > miceModel.oldCount + touchPadModel.oldCount) {
122 unity8Settings.usageMode = "Windowed";
125 // Make sure we initialize to something sane
126 unity8Settings.usageMode = "Staged";
129 miceModel.oldCount = miceModel.count;
130 touchPadModel.oldCount = touchPadModel.count;
133 /* FIXME: This exposes the NameRole as a work arround for lp:1542224.
134 * When QInputInfo exposes NameRole to QML, this should be removed.
136 property bool forceOSKEnabled: false
137 property var autopilotEmulatedDeviceNames: ["py-evdev-uinput"]
138 UnitySortFilterProxyModel {
140 model: keyboardsModel
143 function autopilotDevicePresent() {
144 for(var i = 0; i < autopilotDevices.count; i++) {
145 var device = autopilotDevices.get(i);
146 if (autopilotEmulatedDeviceNames.indexOf(device.name) != -1) {
147 console.warn("Forcing the OSK to be enabled as there is an autopilot eumlated device present.")
158 property int orientation
159 onPhysicalOrientationChanged: {
160 if (!orientationLocked) {
161 orientation = physicalOrientation;
164 onOrientationLockedChanged: {
165 if (orientationLocked) {
166 orientationLock.savedOrientation = physicalOrientation;
168 orientation = physicalOrientation;
171 Component.onCompleted: {
172 if (orientationLocked) {
173 orientation = orientationLock.savedOrientation;
176 calculateUsageMode();
178 // We need to manually update this on startup as the binding
179 // below doesn't seem to have any effect at that stage
180 oskSettings.disableHeight = !shell.oskEnabled || shell.usageScenario == "desktop"
183 // we must rotate to a supported orientation regardless of shell's preference
184 property bool orientationChangesEnabled:
185 (shell.orientation & supportedOrientations) === 0 ? true
186 : shell.orientationChangesEnabled
190 property: "disableHeight"
191 value: !shell.oskEnabled || shell.usageScenario == "desktop"
194 readonly property int supportedOrientations: shell.supportedOrientations
195 & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation
196 ? orientations.native_
197 : deviceConfiguration.supportedOrientations)
199 property int acceptedOrientationAngle: {
200 if (orientation & supportedOrientations) {
201 return Screen.angleBetween(orientations.native_, orientation);
202 } else if (shell.orientation & supportedOrientations) {
204 return shell.orientationAngle;
205 } else if (angleToOrientation(shell.mainAppWindowOrientationAngle) & supportedOrientations) {
206 return shell.mainAppWindowOrientationAngle;
208 // rotate to some supported orientation as we can't stay where we currently are
209 // TODO: Choose the closest to the current one
210 if (supportedOrientations & Qt.PortraitOrientation) {
211 return Screen.angleBetween(orientations.native_, Qt.PortraitOrientation);
212 } else if (supportedOrientations & Qt.LandscapeOrientation) {
213 return Screen.angleBetween(orientations.native_, Qt.LandscapeOrientation);
214 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
215 return Screen.angleBetween(orientations.native_, Qt.InvertedPortraitOrientation);
216 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
217 return Screen.angleBetween(orientations.native_, Qt.InvertedLandscapeOrientation);
219 // if all fails, fallback to primary orientation
220 return Screen.angleBetween(orientations.native_, orientations.primary);
225 function angleToOrientation(angle) {
228 return orientations.native_;
230 return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
231 : Qt.PortraitOrientation;
233 return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
234 : Qt.InvertedLandscapeOrientation;
236 return orientations.native_ === Qt.PortraitOrientation ? Qt.LandscapeOrientation
237 : Qt.InvertedPortraitOrientation;
239 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
240 return orientations.primary;
246 objectName: "rotationStates"
249 shellCover: shellCover
250 shellSnapshot: shellSnapshot
258 orientation: root.angleToOrientation(orientationAngle)
259 orientations: root.orientations
260 nativeWidth: root.width
261 nativeHeight: root.height
262 mode: applicationArguments.mode
263 hasMouse: miceModel.count + touchPadModel.count > 0
264 // TODO: Factor in if the current screen is a touch screen and if the user wants to
265 // have multiple keyboards around. For now we only enable one keyboard at a time
266 // thus hiding it here if there is a physical one around or if we have a second
267 // screen (the virtual touchpad & osk on the phone) attached.
268 oskEnabled: (keyboardsModel.count === 0 && screens.count === 1) ||
272 if (unity8Settings.usageMode === "Windowed") {
275 if (deviceConfiguration.category === "phone") {
283 property real transformRotationAngle
284 property real transformOriginX
285 property real transformOriginY
287 transform: Rotation {
288 origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
289 angle: shell.transformRotationAngle
307 property real transformRotationAngle
308 property real transformOriginX
309 property real transformOriginY
311 transform: Rotation {
312 origin.x: shellSnapshot.transformOriginX; origin.y: shellSnapshot.transformOriginY;
313 axis { x: 0; y: 0; z: 1 }
314 angle: shellSnapshot.transformRotationAngle