Unity 8
OrientedShell.qml
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  */
16 
17 import QtQuick 2.0
18 import QtQuick.Window 2.0
19 import Unity.Session 0.1
20 import GSettings 1.0
21 import "Components"
22 import "Components/UnityInputInfo"
23 import "Rotation"
24 // Backup Workaround https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1473471
25 // in case we remove the UnityInputInfo import
26 import Ubuntu.Components 1.2
27 
28 Rectangle {
29  id: root
30  color: "black"
31 
32  implicitWidth: units.gu(40)
33  implicitHeight: units.gu(71)
34 
35  // NB: native and primary orientations here don't map exactly to their QScreen counterparts
36  readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
37 
38  readonly property int primaryOrientation:
39  deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
40  ? nativeOrientation : deviceConfiguration.primaryOrientation
41 
42  DeviceConfiguration {
43  id: deviceConfiguration
44  name: applicationArguments.deviceName
45  }
46 
47 
48  // to be overwritten by tests
49  property var unity8Settings: Unity8Settings {}
50  property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
51 
52  property int physicalOrientation: Screen.orientation
53  property bool orientationLocked: OrientationLock.enabled
54  property var orientationLock: OrientationLock
55 
56  property int orientation
57  onPhysicalOrientationChanged: {
58  if (!orientationLocked) {
59  orientation = physicalOrientation;
60  }
61  }
62  onOrientationLockedChanged: {
63  if (orientationLocked) {
64  orientationLock.savedOrientation = physicalOrientation;
65  } else {
66  orientation = physicalOrientation;
67  }
68  }
69  Component.onCompleted: {
70  if (orientationLocked) {
71  orientation = orientationLock.savedOrientation;
72  }
73  // We need to manually update this on startup as the binding
74  // below doesn't seem to have any effect at that stage
75  oskSettings.stayHidden = UnityInputInfo.keyboards > 0
76  oskSettings.disableHeight = shell.usageScenario == "desktop"
77  }
78 
79  Binding {
80  target: oskSettings
81  property: "stayHidden"
82  value: UnityInputInfo.keyboards > 0
83  }
84 
85  Binding {
86  target: oskSettings
87  property: "disableHeight"
88  value: shell.usageScenario == "desktop"
89  }
90 
91  readonly property int supportedOrientations: shell.supportedOrientations
92  & deviceConfiguration.supportedOrientations
93  property int acceptedOrientationAngle: {
94  if (orientation & supportedOrientations) {
95  return Screen.angleBetween(nativeOrientation, orientation);
96  } else if (shell.orientation & supportedOrientations) {
97  // stay where we are
98  return shell.orientationAngle;
99  } else if (angleToOrientation(shell.mainAppWindowOrientationAngle) & supportedOrientations) {
100  return shell.mainAppWindowOrientationAngle;
101  } else {
102  // rotate to some supported orientation as we can't stay where we currently are
103  // TODO: Choose the closest to the current one
104  if (supportedOrientations & Qt.PortraitOrientation) {
105  return Screen.angleBetween(nativeOrientation, Qt.PortraitOrientation);
106  } else if (supportedOrientations & Qt.LandscapeOrientation) {
107  return Screen.angleBetween(nativeOrientation, Qt.LandscapeOrientation);
108  } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
109  return Screen.angleBetween(nativeOrientation, Qt.InvertedPortraitOrientation);
110  } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
111  return Screen.angleBetween(nativeOrientation, Qt.InvertedLandscapeOrientation);
112  } else {
113  // if all fails, fallback to primary orientation
114  return Screen.angleBetween(nativeOrientation, primaryOrientation);
115  }
116  }
117  }
118 
119  function angleToOrientation(angle) {
120  switch (angle) {
121  case 0:
122  return nativeOrientation;
123  case 90:
124  return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
125  : Qt.PortraitOrientation;
126  case 180:
127  return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
128  : Qt.InvertedLandscapeOrientation;
129  case 270:
130  return nativeOrientation === Qt.PortraitOrientation ? Qt.LandscapeOrientation
131  : Qt.InvertedPortraitOrientation;
132  default:
133  console.warn("angleToOrientation: Invalid orientation angle: " + angle);
134  return primaryOrientation;
135  }
136  }
137 
138  RotationStates {
139  id: rotationStates
140  objectName: "rotationStates"
141  orientedShell: root
142  shell: shell
143  shellCover: shellCover
144  windowScreenshot: windowScreenshot
145  }
146 
147  Shell {
148  id: shell
149  objectName: "shell"
150  width: root.width
151  height: root.height
152  orientation: root.angleToOrientation(orientationAngle)
153  primaryOrientation: root.primaryOrientation
154  nativeOrientation: root.nativeOrientation
155  nativeWidth: root.width
156  nativeHeight: root.height
157  mode: applicationArguments.mode
158  hasMouse: UnityInputInfo.mice > deviceConfiguration.ignoredMice
159 
160  // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
161  // what's the output device (eg: big TV, desktop monitor, phone display), etc.
162  usageScenario: {
163  if (root.unity8Settings.usageMode === "Windowed") {
164  return "desktop";
165  } else if (root.unity8Settings.usageMode === "Staged") {
166  if (deviceConfiguration.category === "phone") {
167  return "phone";
168  } else {
169  return "tablet";
170  }
171  } else { // automatic
172  if (UnityInputInfo.mice > deviceConfiguration.ignoredMice) {
173  return "desktop";
174  } else {
175  return deviceConfiguration.category;
176  }
177  }
178  }
179 
180  property real transformRotationAngle
181  property real transformOriginX
182  property real transformOriginY
183 
184  transform: Rotation {
185  origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
186  angle: shell.transformRotationAngle
187  }
188  }
189 
190  Rectangle {
191  id: shellCover
192  color: "black"
193  anchors.fill: parent
194  visible: false
195  }
196 
197  WindowScreenshot {
198  id: windowScreenshot
199  visible: false
200  width: root.width
201  height: root.height
202 
203  property real transformRotationAngle
204  property real transformOriginX
205  property real transformOriginY
206 
207  transform: Rotation {
208  origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
209  axis { x: 0; y: 0; z: 1 }
210  angle: windowScreenshot.transformRotationAngle
211  }
212  }
213 }