on xenial help sign in
merge with shellRotation
e01fa78Michael Zanetti
debian/control−4
@@ -169,12 +169,8 @@ Pre-Depends: ${misc:Pre-Depends},
169Depends: ${misc:Depends},
169Depends: ${misc:Depends},
170 ${shlibs:Depends},
170 ${shlibs:Depends},
171Provides: unity-application-impl,
171Provides: unity-application-impl,
172−<<<<<<< TREE
173 unity-application-impl-6,
172 unity-application-impl-6,
174−=======
175− unity-application-impl-4,
176Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
173Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
177−>>>>>>> MERGE-SOURCE
178Description: Fake environment for running Unity 8 shell
174Description: Fake environment for running Unity 8 shell
179 Provides fake implementations of some QML modules used by Unity 8 shell
175 Provides fake implementations of some QML modules used by Unity 8 shell
180 (e.g Ubuntu.Application) so that you can run it in a sandboxed environment.
176 (e.g Ubuntu.Application) so that you can run it in a sandboxed environment.
qml/Dash/DashApplication.qml+3−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014,2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -19,8 +19,8 @@ import Ubuntu.Components 1.0
19import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
19import Ubuntu.Thumbnailer 0.1 // Register support for image://thumbnailer/ and image://albumart/
20
20
21MainView {
21MainView {
22− width: applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
22+ implicitWidth: units.gu(40)
23− height: applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(68)
23+ implicitHeight: units.gu(68)
24
24
25 useDeprecatedToolbar: false
25 useDeprecatedToolbar: false
26
26
qml/OrientedShell.qml+3
@@ -25,6 +25,9 @@ Rectangle {
25 id: root
25 id: root
26 color: "black"
26 color: "black"
27
27
28+ implicitWidth: units.gu(40)
29+ implicitHeight: units.gu(71)
30+
28 // NB: native and primary orientations here don't map exactly to their QScreen counterparts
31 // NB: native and primary orientations here don't map exactly to their QScreen counterparts
29 readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
32 readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
30
33
qml/Rotation/RotationStates.qml+7
@@ -16,6 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 1.1
18import Ubuntu.Components 1.1
19+import Powerd 0.1
19
20
20// Why the state machine is done that way:
21// Why the state machine is done that way:
21// We cannot use regular PropertyChanges{} inside the State elements as steps in the
22// We cannot use regular PropertyChanges{} inside the State elements as steps in the
@@ -121,6 +122,12 @@ StateGroup {
121 // During start up, inital property values are still settling while we're still
122 // During start up, inital property values are still settling while we're still
122 // to render the very first frame
123 // to render the very first frame
123 d.animationType = d.noAnimation;
124 d.animationType = d.noAnimation;
125+ } else if (Powerd.status === Powerd.Off) {
126+ // There's no point in animating if the user can't see it (display is off).
127+ d.animationType = d.noAnimation;
128+ } else if (root.shell.showingGreeter) {
129+ // A rotating greeter looks weird.
130+ d.animationType = d.noAnimation;
124 } else {
131 } else {
125 if (!root.shell.mainApp) {
132 if (!root.shell.mainApp) {
126 // shouldn't happen but, anyway
133 // shouldn't happen but, anyway
qml/Shell.qml+2
@@ -70,6 +70,8 @@ Item {
70 && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
70 && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
71 && !greeter.animating
71 && !greeter.animating
72
72
73+ readonly property bool showingGreeter: greeter.shown
74+
73 property bool startingUp: true
75 property bool startingUp: true
74 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
76 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
75
77
qml/Stages/SpreadDelegate.qml+15−7
@@ -131,6 +131,14 @@ FocusScope {
131 }
131 }
132 }
132 }
133
133
134+ // Ensures the given angle is in the form (0,90,180,270)
135+ function normalizeAngle(angle) {
136+ while (angle < 0) {
137+ angle += 360;
138+ }
139+ return angle % 360;
140+ }
141+
134 states: [
142 states: [
135 // Sets the initial orientationAngle of the window, when it first slides into view
143 // Sets the initial orientationAngle of the window, when it first slides into view
136 // (with the splash screen likely being displayed). At that point we just try to
144 // (with the splash screen likely being displayed). At that point we just try to
@@ -172,16 +180,16 @@ FocusScope {
172 return Screen.angleBetween(root.nativeOrientation, chosenOrientation);
180 return Screen.angleBetween(root.nativeOrientation, chosenOrientation);
173 }
181 }
174
182
175− rotation: appWindowWithShadow.orientationAngle - root.shellOrientationAngle
183+ rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
176 width: {
184 width: {
177− if (rotation == 0 || Math.abs(rotation) == 180) {
185+ if (rotation == 0 || rotation == 180) {
178 return root.width;
186 return root.width;
179 } else {
187 } else {
180 return root.height;
188 return root.height;
181 }
189 }
182 }
190 }
183 height: {
191 height: {
184− if (rotation == 0 || Math.abs(rotation) == 180)
192+ if (rotation == 0 || rotation == 180)
185 return root.height;
193 return root.height;
186 else
194 else
187 return root.width;
195 return root.width;
@@ -201,16 +209,16 @@ FocusScope {
201 PropertyChanges {
209 PropertyChanges {
202 target: appWindowWithShadow
210 target: appWindowWithShadow
203 restoreEntryValues: false
211 restoreEntryValues: false
204− rotation: appWindowWithShadow.orientationAngle - root.shellOrientationAngle
212+ rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
205 width: {
213 width: {
206− if (rotation == 0 || Math.abs(rotation) == 180) {
214+ if (rotation == 0 || rotation == 180) {
207 return root.width;
215 return root.width;
208 } else {
216 } else {
209 return root.height;
217 return root.height;
210 }
218 }
211 }
219 }
212 height: {
220 height: {
213− if (rotation == 0 || Math.abs(rotation) == 180)
221+ if (rotation == 0 || rotation == 180)
214 return root.height;
222 return root.height;
215 else
223 else
216 return root.width;
224 return root.width;
@@ -229,7 +237,7 @@ FocusScope {
229 target: appWindowWithShadow
237 target: appWindowWithShadow
230 width: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.width : root.height
238 width: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.width : root.height
231 height: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.height : root.width
239 height: root.shellOrientationAngle == 0 || root.shellOrientationAngle == 180 ? root.height : root.width
232− rotation: -root.shellOrientationAngle
240+ rotation: normalizeAngle(-root.shellOrientationAngle)
233 }
241 }
234 PropertyChanges {
242 PropertyChanges {
235 target: appWindow
243 target: appWindow
qml/Stages/TabletStage.qml+1
@@ -728,6 +728,7 @@ Rectangle {
728
728
729 DirectionalDragArea {
729 DirectionalDragArea {
730 id: spreadDragArea
730 id: spreadDragArea
731+ objectName: "spreadDragArea"
731 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
732 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
732 width: root.dragAreaWidth
733 width: root.dragAreaWidth
733 direction: Direction.Leftwards
734 direction: Direction.Leftwards
qml/Stages/TransformedSpreadDelegate.qml+2−16
@@ -312,27 +312,13 @@ SpreadDelegate {
312 // non-fullscreen window when they're stacked on top of each other on the
312 // non-fullscreen window when they're stacked on top of each other on the
313 // far left of the spread.
313 // far left of the spread.
314 Translate {
314 Translate {
315− y: !fullscreen && Math.abs(appWindowRotation) === 180
315+ y: !fullscreen && appWindowRotation === 180
316 ? priv.topMarginProgress * maximizedAppTopMargin
316 ? priv.topMarginProgress * maximizedAppTopMargin
317 : 0
317 : 0
318 },
318 },
319 Scale {
319 Scale {
320 origin {
320 origin {
321− x: {
322− switch (appWindowRotation) {
321+ x: appWindowRotation === 270 ? spreadView.width : 0
323− case 0:
324− return 0;
325− break;
326− case 90:
327− return 0;
328− break;
329− case 270:
330− return spreadView.width;
331− break;
332− default: // 180
333− return 0;
334− }
335− }
336 y: spreadView.height
322 y: spreadView.height
337 }
323 }
338
324
src/ApplicationArguments.h−9
@@ -31,18 +31,9 @@ public:
31 ApplicationArguments(QObject *parent = nullptr);
31 ApplicationArguments(QObject *parent = nullptr);
32
32
33 void setDeviceName(QString deviceName) { m_deviceName = deviceName; }
33 void setDeviceName(QString deviceName) { m_deviceName = deviceName; }
34−
35− void setSize(const QSize &size) {
36− m_size = size;
37− }
38−
39− Q_INVOKABLE int width() const { return m_size.width(); }
40− Q_INVOKABLE int height() const { return m_size.height(); }
41−
42 QString deviceName() const { return m_deviceName; }
34 QString deviceName() const { return m_deviceName; }
43
35
44private:
36private:
45− QSize m_size;
46 QString m_deviceName;
37 QString m_deviceName;
47};
38};
48
39
src/Dash/main.cpp+12−6
@@ -61,12 +61,6 @@ int main(int argc, const char *argv[])
61 parser.process(*application);
61 parser.process(*application);
62
62
63 ApplicationArguments qmlArgs;
63 ApplicationArguments qmlArgs;
64− if (parser.isSet(windowGeometryOption) &&
65− parser.value(windowGeometryOption).split('x').size() == 2)
66− {
67− QStringList geom = parser.value(windowGeometryOption).split('x');
68− qmlArgs.setSize(QSize(geom.at(0).toInt(), geom.at(1).toInt()));
69− }
70
64
71 if (getenv("QT_LOAD_TESTABILITY")) {
65 if (getenv("QT_LOAD_TESTABILITY")) {
72 QLibrary testLib(QLatin1String("qttestability"));
66 QLibrary testLib(QLatin1String("qttestability"));
@@ -88,6 +82,18 @@ int main(int argc, const char *argv[])
88
82
89 QQuickView* view = new QQuickView();
83 QQuickView* view = new QQuickView();
90 view->setResizeMode(QQuickView::SizeRootObjectToView);
84 view->setResizeMode(QQuickView::SizeRootObjectToView);
85+
86+ if (parser.isSet(windowGeometryOption) &&
87+ parser.value(windowGeometryOption).split('x').size() == 2)
88+ {
89+ QStringList geom = parser.value(windowGeometryOption).split('x');
90+ QSize windowSize(geom.at(0).toInt(), geom.at(1).toInt());
91+ if (windowSize.isValid()) {
92+ view->setWidth(windowSize.width());
93+ view->setHeight(windowSize.height());
94+ }
95+ }
96+
91 view->setTitle("Scopes");
97 view->setTitle("Scopes");
92 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
98 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
93
99
src/main.cpp+6−1
@@ -54,7 +54,6 @@ int main(int argc, const char *argv[])
54 UnityCommandLineParser parser(*application);
54 UnityCommandLineParser parser(*application);
55
55
56 ApplicationArguments qmlArgs;
56 ApplicationArguments qmlArgs;
57− qmlArgs.setSize(parser.windowGeometry());
58
57
59 if (!parser.deviceName().isEmpty()) {
58 if (!parser.deviceName().isEmpty()) {
60 qmlArgs.setDeviceName(parser.deviceName());
59 qmlArgs.setDeviceName(parser.deviceName());
@@ -88,6 +87,12 @@ int main(int argc, const char *argv[])
88 view->setResizeMode(QQuickView::SizeRootObjectToView);
87 view->setResizeMode(QQuickView::SizeRootObjectToView);
89 view->setColor("black");
88 view->setColor("black");
90 view->setTitle("Unity8 Shell");
89 view->setTitle("Unity8 Shell");
90+
91+ if (parser.windowGeometry().isValid()) {
92+ view->setWidth(parser.windowGeometry().width());
93+ view->setHeight(parser.windowGeometry().height());
94+ }
95+
91 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
96 view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
92 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
97 view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
93 view->rootContext()->setContextProperty("shellMode", parser.mode());
98 view->rootContext()->setContextProperty("shellMode", parser.mode());
tests/qmltests/tst_OrientedShell.qml+59−5
@@ -22,6 +22,7 @@ import Ubuntu.Components.ListItems 1.0 as ListItem
22import Unity.Application 0.1
22import Unity.Application 0.1
23import Unity.Test 0.1
23import Unity.Test 0.1
24import LightDM 0.1 as LightDM
24import LightDM 0.1 as LightDM
25+import Powerd 0.1
25
26
26import "../../qml"
27import "../../qml"
27
28
@@ -161,8 +162,16 @@ Rectangle {
161 }
162 }
162
163
163 Rectangle {
164 Rectangle {
164− id: controls
165+ width: controls.width
166+ anchors {
167+ top: parent.top
168+ bottom: parent.bottom
169+ right: parent.right
170+ }
165 color: "darkgrey"
171 color: "darkgrey"
172+ }
173+ Flickable {
174+ id: controls
166 width: units.gu(30)
175 width: units.gu(30)
167 anchors {
176 anchors {
168 top: parent.top
177 top: parent.top
@@ -170,7 +179,11 @@ Rectangle {
170 right: parent.right
179 right: parent.right
171 }
180 }
172
181
182+ boundsBehavior: Flickable.StopAtBounds
183+ contentHeight: controlsColumn.height
184+
173 Column {
185 Column {
186+ id: controlsColumn
174 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
187 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
175 spacing: units.gu(1)
188 spacing: units.gu(1)
176 Button {
189 Button {
@@ -281,6 +294,17 @@ Rectangle {
281 anchors.verticalCenter: parent.verticalCenter
294 anchors.verticalCenter: parent.verticalCenter
282 }
295 }
283 }
296 }
297+ Button {
298+ text: Powerd.status === Powerd.On ? "Display ON" : "Display OFF"
299+ activeFocusOnPress: false
300+ onClicked: {
301+ if (Powerd.status === Powerd.On) {
302+ Powerd.status = Powerd.Off;
303+ } else {
304+ Powerd.status = Powerd.On;
305+ }
306+ }
307+ }
284 }
308 }
285 }
309 }
286
310
@@ -947,16 +971,31 @@ Rectangle {
947 // If we swipe too much we will trigger the spread mode
971 // If we swipe too much we will trigger the spread mode
948 // and we don't want that.
972 // and we don't want that.
949 var spreadView = findChild(shell, "spreadView");
973 var spreadView = findChild(shell, "spreadView");
950− var swipeLength = (spreadView.positionMarker1 * spreadView.width) * 0.5;
974+ verify(spreadView);
951
975
952 verify(ApplicationManager.count >= 2);
976 verify(ApplicationManager.count >= 2);
953 var previousApp = ApplicationManager.get(1);
977 var previousApp = ApplicationManager.get(1);
954
978
955 var touchStartX = shell.width - 1;
979 var touchStartX = shell.width - 1;
956 var touchStartY = shell.height / 2;
980 var touchStartY = shell.height / 2;
957− touchFlick(shell,
981+
982+ var condition;
983+ if (applicationArguments.deviceName === "phone") {
984+ condition = function() {
985+ return spreadView.shiftedContentX > units.gu(2) &&
986+ spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width;
987+ };
988+ } else {
989+ condition = function() {
990+ return spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker1
991+ && spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2;
992+ };
993+ }
994+
995+ touchDragUntil(shell,
958− touchStartX, touchStartY,
996+ touchStartX, touchStartY,
959− touchStartX - swipeLength, touchStartY);
997+ -units.gu(1), 0,
998+ condition);
960
999
961 // ensure the app switch animation has ended
1000 // ensure the app switch animation has ended
962 tryCompare(spreadView, "shiftedContentX", 0);
1001 tryCompare(spreadView, "shiftedContentX", 0);
@@ -1039,6 +1078,8 @@ Rectangle {
1039
1078
1040 waitUntilShellIsInOrientation(root.physicalOrientation0);
1079 waitUntilShellIsInOrientation(root.physicalOrientation0);
1041
1080
1081+ waitForGreeterToStabilize();
1082+
1042 swipeAwayGreeter();
1083 swipeAwayGreeter();
1043
1084
1044 var spreadRepeater = findChild(shell, "spreadRepeater");
1085 var spreadRepeater = findChild(shell, "spreadRepeater");
@@ -1047,6 +1088,19 @@ Rectangle {
1047 }
1088 }
1048 }
1089 }
1049
1090
1091+ function waitForGreeterToStabilize() {
1092+ var greeter = findChild(shell, "greeter");
1093+ verify(greeter);
1094+
1095+ var loginList = findChild(greeter, "loginList");
1096+ // Only present in WideView
1097+ if (loginList) {
1098+ var userList = findChild(loginList, "userList");
1099+ verify(userList);
1100+ tryCompare(userList, "movingInternally", false);
1101+ }
1102+ }
1103+
1050 // expectedAngle is in orientedShell's coordinate system
1104 // expectedAngle is in orientedShell's coordinate system
1051 function checkAppSurfaceOrientation(app, expectedAngle) {
1105 function checkAppSurfaceOrientation(app, expectedAngle) {
1052 var surface = app.session.surface;
1106 var surface = app.session.surface;
tests/utils/modules/Unity/Test/UnityTestCase.qml+42
@@ -308,6 +308,48 @@ TestCase {
308 }
308 }
309 }
309 }
310
310
311+ // perform a drag in the given direction until the given condition is true
312+ // The condition is a function to be evaluated after every step
313+ function touchDragUntil(item, startX, startY, stepX, stepY, condition) {
314+
315+ var root = fetchRootItem(item);
316+ var pos = item.mapToItem(root, startX, startY);
317+
318+ // convert step to scene coords
319+ {
320+ var stepStart = item.mapToItem(root, 0, 0);
321+ var stepEnd = item.mapToItem(root, stepX, stepY);
322+ }
323+ stepX = stepEnd.x - stepStart.x;
324+ stepY = stepEnd.y - stepStart.y;
325+
326+ var event = touchEvent(item)
327+ event.press(0 /* touchId */, pos.x, pos.y)
328+ event.commit()
329+
330+ // we have to stop at some point
331+ var maxSteps = 100;
332+ var stepsDone = 0;
333+
334+ while (!condition() && stepsDone < maxSteps) {
335+ wait(25);
336+ fakeDateTime.currentTimeMs += 25;
337+
338+ pos.x += stepX;
339+ pos.y += stepY;
340+
341+ event = touchEvent(item);
342+ event.move(0 /* touchId */, pos.x, pos.y);
343+ event.commit();
344+
345+ stepsDone += 1;
346+ }
347+
348+ event = touchEvent(item)
349+ event.release(0 /* touchId */, pos.x, pos.y)
350+ event.commit()
351+ }
352+
311 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
353 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
312 // Make sure the item is rendered
354 // Make sure the item is rendered
313 waitForRendering(item);
355 waitForRendering(item);