on xenial help sign in
Desktop stage rotates only to follow screen orientation Fixes: #1515977
78d1cfaDaniel d'Andrada
qml/Shell.qml+3−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013-2015 Canonical, Ltd.
2+ * Copyright (C) 2013-2016 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
@@ -84,8 +84,8 @@ Item {
84 return Qt.PrimaryOrientation;
84 return Qt.PrimaryOrientation;
85 } else if (greeter && greeter.shown) {
85 } else if (greeter && greeter.shown) {
86 return Qt.PrimaryOrientation;
86 return Qt.PrimaryOrientation;
87− } else if (mainApp) {
87+ } else if (applicationsDisplayLoader.item) {
88− return shell.orientations.map(mainApp.supportedOrientations);
88+ return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
89 } else {
89 } else {
90 // we just don't care
90 // we just don't care
91 return Qt.PortraitOrientation
91 return Qt.PortraitOrientation
qml/Stages/AbstractStage.qml+5−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 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
@@ -44,6 +44,10 @@ Rectangle {
44 property var mainApp: null
44 property var mainApp: null
45 property int mainAppWindowOrientationAngle
45 property int mainAppWindowOrientationAngle
46 property bool orientationChangesEnabled
46 property bool orientationChangesEnabled
47+ property int supportedOrientations: Qt.PortraitOrientation
48+ | Qt.LandscapeOrientation
49+ | Qt.InvertedPortraitOrientation
50+ | Qt.InvertedLandscapeOrientation
47
51
48 // Shared code for use in stage implementations
52 // Shared code for use in stage implementations
49 GSettings {
53 GSettings {
qml/Stages/DesktopStage.qml+6−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 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
@@ -40,6 +40,11 @@ AbstractStage {
40 ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
40 ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
41 : null
41 : null
42
42
43+ // application windows never rotate independently
44+ mainAppWindowOrientationAngle: shellOrientationAngle
45+
46+ orientationChangesEnabled: true
47+
43 Connections {
48 Connections {
44 target: ApplicationManager
49 target: ApplicationManager
45 onApplicationAdded: {
50 onApplicationAdded: {
qml/Stages/PhoneStage.qml+5−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 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
@@ -83,6 +83,10 @@ AbstractStage {
83 && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
83 && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
84 && spreadView.phase === 0
84 && spreadView.phase === 0
85
85
86+ supportedOrientations: mainApp ? mainApp.supportedOrientations
87+ : (Qt.PortraitOrientation | Qt.LandscapeOrientation
88+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation)
89+
86 // How far left the stage has been dragged
90 // How far left the stage has been dragged
87 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
91 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
88
92
qml/Stages/TabletStage.qml+5−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 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
@@ -72,6 +72,10 @@ AbstractStage {
72
72
73 orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
73 orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
74
74
75+ supportedOrientations: mainApp ? mainApp.supportedOrientations
76+ : (Qt.PortraitOrientation | Qt.LandscapeOrientation
77+ | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation)
78+
75 onWidthChanged: {
79 onWidthChanged: {
76 spreadView.selectedIndex = -1;
80 spreadView.selectedIndex = -1;
77 spreadView.phase = 0;
81 spreadView.phase = 0;
tests/qmltests/tst_OrientedShell.qml+66−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 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
@@ -292,6 +292,9 @@ Rectangle {
292 activeFocusOnPress: false
292 activeFocusOnPress: false
293 text: "Usage Mode"
293 text: "Usage Mode"
294 model: ["Staged", "Windowed", "Automatic"]
294 model: ["Staged", "Windowed", "Automatic"]
295+ function selectStaged() {selectedIndex = 0;}
296+ function selectWindowed() {selectedIndex = 1;}
297+ function selectAutomatic() {selectedIndex = 2;}
295 }
298 }
296 MouseTouchEmulationCheckbox {
299 MouseTouchEmulationCheckbox {
297 checked: true
300 checked: true
@@ -393,7 +396,7 @@ Rectangle {
393 activeFocusOnPress: false
396 activeFocusOnPress: false
394 property string prevDevName: "mako"
397 property string prevDevName: "mako"
395 onClicked: {
398 onClicked: {
396− usageModeSelector.selectedIndex = 2; // "Automatic"
399+ usageModeSelector.selectAutomatic();
397
400
398 if (applicationArguments.deviceName === "desktop") {
401 if (applicationArguments.deviceName === "desktop") {
399 applicationArguments.deviceName = prevDevName;
402 applicationArguments.deviceName = prevDevName;
@@ -457,6 +460,8 @@ Rectangle {
457 signalSpy.signalName = "";
460 signalSpy.signalName = "";
458
461
459 LightDM.Greeter.authenticate(""); // reset greeter
462 LightDM.Greeter.authenticate(""); // reset greeter
463+
464+ usageModeSelector.selectStaged();
460 }
465 }
461
466
462 function cleanup() {
467 function cleanup() {
@@ -997,7 +1002,7 @@ Rectangle {
997 }
1002 }
998
1003
999 function test_attachRemoveInputDevices() {
1004 function test_attachRemoveInputDevices() {
1000− usageModeSelector.selectedIndex = 2;
1005+ usageModeSelector.selectAutomatic();
1001 tryCompare(mockUnity8Settings, "usageMode", "Automatic")
1006 tryCompare(mockUnity8Settings, "usageMode", "Automatic")
1002
1007
1003 loadShell("mako")
1008 loadShell("mako")
@@ -1140,6 +1145,61 @@ Rectangle {
1140 tryCompare(shell, "transformRotationAngle" , 0);
1145 tryCompare(shell, "transformRotationAngle" , 0);
1141 }
1146 }
1142
1147
1148+ /*
1149+ Regression test for https://launchpad.net/bugs/1515977
1150+
1151+ Preconditions:
1152+ UI in Desktop mode and landscape
1153+
1154+ Steps:
1155+ - Launch a portrait-only application
1156+
1157+ Expected outcome:
1158+ - Shell stays in landscape
1159+
1160+ Buggy outcome:
1161+ - Shell would rotate to portrait as the newly-focused app doesn't support landscape
1162+ */
1163+ function test_portraitOnlyAppInLandscapeDesktop_data() {
1164+ return [
1165+ {tag: "mako", deviceName: "mako"},
1166+ {tag: "manta", deviceName: "manta"},
1167+ {tag: "flo", deviceName: "flo"}
1168+ ];
1169+ }
1170+ function test_portraitOnlyAppInLandscapeDesktop(data) {
1171+ loadShell(data.deviceName);
1172+
1173+ ////
1174+ // setup preconditions (put shell in Desktop mode and landscape)
1175+
1176+ usageModeSelector.selectWindowed();
1177+
1178+ orientedShell.physicalOrientation = orientedShell.orientations.landscape;
1179+ waitUntilShellIsInOrientation(orientedShell.orientations.landscape);
1180+ waitForRotationAnimationsToFinish();
1181+
1182+ ////
1183+ // Launch a portrait-only application
1184+
1185+ var dialerApp = ApplicationManager.startApplication("dialer-app");
1186+ verify(dialerApp);
1187+
1188+ // ensure the mock dialer-app is as we expect
1189+ compare(dialerApp.rotatesWindowContents, false);
1190+ compare(dialerApp.supportedOrientations, Qt.PortraitOrientation | Qt.InvertedPortraitOrientation);
1191+
1192+ waitUntilAppSurfaceShowsUp("dialer-app");
1193+ waitUntilAppWindowCanRotate("dialer-app");
1194+ verify(isAppSurfaceFocused("dialer-app"));
1195+
1196+ ////
1197+ // check outcome (shell should stay in landscape)
1198+
1199+ waitForRotationAnimationsToFinish();
1200+ compare(shell.orientation, orientedShell.orientations.landscape);
1201+ }
1202+
1143 // angle - rotation angle in degrees clockwise, relative to the primary orientation.
1203 // angle - rotation angle in degrees clockwise, relative to the primary orientation.
1144 function rotateTo(angle) {
1204 function rotateTo(angle) {
1145 switch (angle) {
1205 switch (angle) {
@@ -1158,7 +1218,10 @@ Rectangle {
1158 default:
1218 default:
1159 verify(false);
1219 verify(false);
1160 }
1220 }
1221+ waitForRotationAnimationsToFinish();
1222+ }
1161
1223
1224+ function waitForRotationAnimationsToFinish() {
1162 var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
1225 var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
1163 verify(rotationStates.d);
1226 verify(rotationStates.d);
1164 verify(rotationStates.d.stateUpdateTimer);
1227 verify(rotationStates.d.stateUpdateTimer);