on 5aaeac8 help sign in
unity8/qml/OrientedShell.qml
246 lines 9.0 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 GSettings 1.0
22import "Components"
23import "Rotation"
24// Workaround https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1473471
25import Ubuntu.Components 1.3
27Rectangle {
28 id: root
29 color: "black"
31 implicitWidth: units.gu(40)
32 implicitHeight: units.gu(71)
34 DeviceConfiguration {
35 id: deviceConfiguration
36 name: applicationArguments.deviceName
37 }
39 property alias orientations: d.orientations
41 Item {
42 id: d
44 property Orientations orientations: Orientations {
45 id: orientations
46 // NB: native and primary orientations here don't map exactly to their QScreen counterparts
47 native_: root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
49 primary: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
50 ? native_ : deviceConfiguration.primaryOrientation
52 landscape: deviceConfiguration.landscapeOrientation
53 invertedLandscape: deviceConfiguration.invertedLandscapeOrientation
54 portrait: deviceConfiguration.portraitOrientation
55 invertedPortrait: deviceConfiguration.invertedPortraitOrientation
56 }
57 }
58 // to be overwritten by tests
59 property var unity8Settings: Unity8Settings {}
60 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
62 property int physicalOrientation: Screen.orientation
63 property bool orientationLocked: OrientationLock.enabled
64 property var orientationLock: OrientationLock
66 InputDeviceModel {
67 id: miceModel
68 deviceFilter: InputInfo.Mouse
69 }
71 InputDeviceModel {
72 id: touchPadModel
73 deviceFilter: InputInfo.TouchPad
74 }
76 InputDeviceModel {
77 id: keyboardsModel
78 deviceFilter: InputInfo.Keyboard
79 }
81 property int orientation
82 onPhysicalOrientationChanged: {
83 if (!orientationLocked) {
84 orientation = physicalOrientation;
85 }
86 }
87 onOrientationLockedChanged: {
88 if (orientationLocked) {
89 orientationLock.savedOrientation = physicalOrientation;
90 } else {
91 orientation = physicalOrientation;
92 }
93 }
94 Component.onCompleted: {
95 if (orientationLocked) {
96 orientation = orientationLock.savedOrientation;
97 }
98 // We need to manually update this on startup as the binding
99 // below doesn't seem to have any effect at that stage
100 oskSettings.stayHidden = keyboardsModel.count > 0
101 oskSettings.disableHeight = shell.usageScenario == "desktop"
102 }
104 // we must rotate to a supported orientation regardless of shell's preference
105 property bool orientationChangesEnabled:
106 (shell.orientation & supportedOrientations) === 0 ? true
107 : shell.orientationChangesEnabled
110 Binding {
111 target: oskSettings
112 property: "stayHidden"
113 value: keyboardsModel.count > 0
114 }
116 Binding {
117 target: oskSettings
118 property: "disableHeight"
119 value: shell.usageScenario == "desktop"
120 }
122 readonly property int supportedOrientations: shell.supportedOrientations
123 & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation
124 ? orientations.native_
125 : deviceConfiguration.supportedOrientations)
127 property int acceptedOrientationAngle: {
128 if (orientation & supportedOrientations) {
129 return Screen.angleBetween(orientations.native_, orientation);
130 } else if (shell.orientation & supportedOrientations) {
131 // stay where we are
132 return shell.orientationAngle;
133 } else if (angleToOrientation(shell.mainAppWindowOrientationAngle) & supportedOrientations) {
134 return shell.mainAppWindowOrientationAngle;
135 } else {
136 // rotate to some supported orientation as we can't stay where we currently are
137 // TODO: Choose the closest to the current one
138 if (supportedOrientations & Qt.PortraitOrientation) {
139 return Screen.angleBetween(orientations.native_, Qt.PortraitOrientation);
140 } else if (supportedOrientations & Qt.LandscapeOrientation) {
141 return Screen.angleBetween(orientations.native_, Qt.LandscapeOrientation);
142 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
143 return Screen.angleBetween(orientations.native_, Qt.InvertedPortraitOrientation);
144 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
145 return Screen.angleBetween(orientations.native_, Qt.InvertedLandscapeOrientation);
146 } else {
147 // if all fails, fallback to primary orientation
148 return Screen.angleBetween(orientations.native_, orientations.primary);
149 }
150 }
151 }
153 function angleToOrientation(angle) {
154 switch (angle) {
155 case 0:
156 return orientations.native_;
157 case 90:
158 return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
159 : Qt.PortraitOrientation;
160 case 180:
161 return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
162 : Qt.InvertedLandscapeOrientation;
163 case 270:
164 return orientations.native_ === Qt.PortraitOrientation ? Qt.LandscapeOrientation
165 : Qt.InvertedPortraitOrientation;
166 default:
167 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
168 return orientations.primary;
169 }
170 }
172 RotationStates {
173 id: rotationStates
174 objectName: "rotationStates"
175 orientedShell: root
176 shell: shell
177 shellCover: shellCover
178 windowScreenshot: windowScreenshot
179 }
181 Shell {
182 id: shell
183 objectName: "shell"
184 width: root.width
185 height: root.height
186 orientation: root.angleToOrientation(orientationAngle)
187 orientations: root.orientations
188 nativeWidth: root.width
189 nativeHeight: root.height
190 mode: applicationArguments.mode
191 hasMouse: miceModel.count + touchPadModel.count > 0
193 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
194 // what's the output device (eg: big TV, desktop monitor, phone display), etc.
195 usageScenario: {
196 if (root.unity8Settings.usageMode === "Windowed") {
197 return "desktop";
198 } else if (root.unity8Settings.usageMode === "Staged") {
199 if (deviceConfiguration.category === "phone") {
200 return "phone";
201 } else {
202 return "tablet";
203 }
204 } else { // automatic
205 if (miceModel.count + touchPadModel.count > 0) {
206 return "desktop";
207 } else {
208 return deviceConfiguration.category;
209 }
210 }
211 }
213 property real transformRotationAngle
214 property real transformOriginX
215 property real transformOriginY
217 transform: Rotation {
218 origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
219 angle: shell.transformRotationAngle
220 }
221 }
223 Rectangle {
224 id: shellCover
225 color: "black"
226 anchors.fill: parent
227 visible: false
228 }
230 WindowScreenshot {
231 id: windowScreenshot
232 visible: false
233 width: root.width
234 height: root.height
236 property real transformRotationAngle
237 property real transformOriginX
238 property real transformOriginY
240 transform: Rotation {
241 origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
242 axis { x: 0; y: 0; z: 1 }
243 angle: windowScreenshot.transformRotationAngle
244 }
245 }