on bbbdccd help sign in
unity8/qml/OrientedShell.qml
260 lines 9.8 kB history raw
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
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.
7 *
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.
12 *
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/>.
15 */
17import QtQuick 2.4
18import QtQuick.Window 2.2
19import Unity.InputInfo 0.1
20import Unity.Session 0.1
21import Unity.Screens 0.1
22import GSettings 1.0
23import "Components"
24import "Rotation"
25// Workaround https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1473471
26import Ubuntu.Components 1.3
28Rectangle {
29 id: root
30 color: "black"
32 implicitWidth: units.gu(40)
33 implicitHeight: units.gu(71)
35 DeviceConfiguration {
36 id: deviceConfiguration
37 name: applicationArguments.deviceName
38 }
40 property alias orientations: d.orientations
42 Item {
43 id: d
45 property Orientations orientations: Orientations {
46 id: orientations
47 // NB: native and primary orientations here don't map exactly to their QScreen counterparts
48 native_: root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
50 primary: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
51 ? native_ : deviceConfiguration.primaryOrientation
53 landscape: deviceConfiguration.landscapeOrientation
54 invertedLandscape: deviceConfiguration.invertedLandscapeOrientation
55 portrait: deviceConfiguration.portraitOrientation
56 invertedPortrait: deviceConfiguration.invertedPortraitOrientation
57 }
58 }
59 // to be overwritten by tests
60 property var unity8Settings: Unity8Settings {}
61 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
63 property int physicalOrientation: Screen.orientation
64 property bool orientationLocked: OrientationLock.enabled
65 property var orientationLock: OrientationLock
67 InputDeviceModel {
68 id: miceModel
69 deviceFilter: InputInfo.Mouse
70 }
72 InputDeviceModel {
73 id: touchPadModel
74 deviceFilter: InputInfo.TouchPad
75 }
77 InputDeviceModel {
78 id: keyboardsModel
79 deviceFilter: InputInfo.Keyboard
80 }
82 InputDeviceModel {
83 id: touchScreensModel
84 deviceFilter: InputInfo.TouchScreen
85 }
87 Screens {
88 id: screens
89 }
91 property int orientation
92 onPhysicalOrientationChanged: {
93 if (!orientationLocked) {
94 orientation = physicalOrientation;
95 }
96 }
97 onOrientationLockedChanged: {
98 if (orientationLocked) {
99 orientationLock.savedOrientation = physicalOrientation;
100 } else {
101 orientation = physicalOrientation;
102 }
103 }
104 Component.onCompleted: {
105 if (orientationLocked) {
106 orientation = orientationLock.savedOrientation;
107 }
108 // We need to manually update this on startup as the binding
109 // below doesn't seem to have any effect at that stage
110 oskSettings.disableHeight = !shell.oskEnabled || shell.usageScenario == "desktop"
111 }
113 // we must rotate to a supported orientation regardless of shell's preference
114 property bool orientationChangesEnabled:
115 (shell.orientation & supportedOrientations) === 0 ? true
116 : shell.orientationChangesEnabled
118 Binding {
119 target: oskSettings
120 property: "disableHeight"
121 value: !shell.oskEnabled || shell.usageScenario == "desktop"
122 }
124 readonly property int supportedOrientations: shell.supportedOrientations
125 & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation
126 ? orientations.native_
127 : deviceConfiguration.supportedOrientations)
129 property int acceptedOrientationAngle: {
130 if (orientation & supportedOrientations) {
131 return Screen.angleBetween(orientations.native_, orientation);
132 } else if (shell.orientation & supportedOrientations) {
133 // stay where we are
134 return shell.orientationAngle;
135 } else if (angleToOrientation(shell.mainAppWindowOrientationAngle) & supportedOrientations) {
136 return shell.mainAppWindowOrientationAngle;
137 } else {
138 // rotate to some supported orientation as we can't stay where we currently are
139 // TODO: Choose the closest to the current one
140 if (supportedOrientations & Qt.PortraitOrientation) {
141 return Screen.angleBetween(orientations.native_, Qt.PortraitOrientation);
142 } else if (supportedOrientations & Qt.LandscapeOrientation) {
143 return Screen.angleBetween(orientations.native_, Qt.LandscapeOrientation);
144 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
145 return Screen.angleBetween(orientations.native_, Qt.InvertedPortraitOrientation);
146 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
147 return Screen.angleBetween(orientations.native_, Qt.InvertedLandscapeOrientation);
148 } else {
149 // if all fails, fallback to primary orientation
150 return Screen.angleBetween(orientations.native_, orientations.primary);
151 }
152 }
153 }
155 function angleToOrientation(angle) {
156 switch (angle) {
157 case 0:
158 return orientations.native_;
159 case 90:
160 return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
161 : Qt.PortraitOrientation;
162 case 180:
163 return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
164 : Qt.InvertedLandscapeOrientation;
165 case 270:
166 return orientations.native_ === Qt.PortraitOrientation ? Qt.LandscapeOrientation
167 : Qt.InvertedPortraitOrientation;
168 default:
169 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
170 return orientations.primary;
171 }
172 }
174 RotationStates {
175 id: rotationStates
176 objectName: "rotationStates"
177 orientedShell: root
178 shell: shell
179 shellCover: shellCover
180 windowScreenshot: windowScreenshot
181 }
183 Shell {
184 id: shell
185 objectName: "shell"
186 width: root.width
187 height: root.height
188 orientation: root.angleToOrientation(orientationAngle)
189 orientations: root.orientations
190 nativeWidth: root.width
191 nativeHeight: root.height
192 mode: applicationArguments.mode
193 hasMouse: miceModel.count + touchPadModel.count > 0
194 // TODO: Factor in if the current screen is a touch screen and if the user wants to
195 // have multiple keyboards around. For now we only enable one keyboard at a time
196 // thus hiding it here if there is a physical one around or if we have a second
197 // screen (the virtual touchpad & osk on the phone) attached.
198 oskEnabled: keyboardsModel.count === 0 && screens.count === 1
200 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
201 // what's the output device (eg: big TV, desktop monitor, phone display), etc.
202 usageScenario: {
203 if (root.unity8Settings.usageMode === "Windowed") {
204 return "desktop";
205 } else if (root.unity8Settings.usageMode === "Staged") {
206 if (deviceConfiguration.category === "phone") {
207 return "phone";
208 } else {
209 return "tablet";
210 }
211 } else { // automatic
212 var longEdgeWidth = Math.max(root.width, root.height)
213 if (longEdgeWidth > units.gu(120)) {
214 if (keyboardsModel.count + miceModel.count + touchPadModel.count > 0) {
215 return "desktop";
216 }
217 } else if (longEdgeWidth > units.gu(90)){
218 if (miceModel.count + touchPadModel.count > 0) {
219 return "desktop";
220 }
221 }
223 return deviceConfiguration.category;
224 }
225 }
227 property real transformRotationAngle
228 property real transformOriginX
229 property real transformOriginY
231 transform: Rotation {
232 origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
233 angle: shell.transformRotationAngle
234 }
235 }
237 Rectangle {
238 id: shellCover
239 color: "black"
240 anchors.fill: parent
241 visible: false
242 }
244 WindowScreenshot {
245 id: windowScreenshot
246 visible: false
247 width: root.width
248 height: root.height
250 property real transformRotationAngle
251 property real transformOriginX
252 property real transformOriginY
254 transform: Rotation {
255 origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
256 axis { x: 0; y: 0; z: 1 }
257 angle: windowScreenshot.transformRotationAngle
258 }
259 }