on xenial help sign in
added some tests
d690862Michael Zanetti
qml/Components/PhysicalKeysMapper.qml+7−6
@@ -35,6 +35,7 @@ import Powerd 0.1
35
35
36Item {
36Item {
37 id: root
37 id: root
38+ objectName: "physicalKeysMapper"
38
39
39 signal powerKeyLongPressed;
40 signal powerKeyLongPressed;
40 signal volumeDownTriggered;
41 signal volumeDownTriggered;
@@ -47,6 +48,10 @@ Item {
47
48
48 property int powerKeyLongPressTime: 2000
49 property int powerKeyLongPressTime: 2000
49
50
51+ // For testing. If running windowed (e.g. tryShell), Alt+Tab is taken by the
52+ // running desktop, set this to true to use Ctrl+Tab instead.
53+ property bool controlInsteadOfAlt: false
54+
50 QtObject {
55 QtObject {
51 id: d
56 id: d
52
57
@@ -100,15 +105,12 @@ Item {
100 }
105 }
101 d.volumeUpKeyPressed = true;
106 d.volumeUpKeyPressed = true;
102 }
107 }
103− } else if (event.key == Qt.Key_Control) {
108+ } else if (event.key == Qt.Key_Alt || (root.controlInsteadOfAlt && event.key == Qt.Key_Control)) {
104− print("controll pressed");
105 d.altPressed = true;
109 d.altPressed = true;
106 } else if (event.key == Qt.Key_Tab) {
110 } else if (event.key == Qt.Key_Tab) {
107− print("tab pressed")
108 if (d.altPressed && !d.altTabPressed) {
111 if (d.altPressed && !d.altTabPressed) {
109 d.altTabPressed = true;
112 d.altTabPressed = true;
110 } else if (d.altTabPressed) {
113 } else if (d.altTabPressed) {
111− print("alttabnext")
112 root.altTabNext(event.isAutoRepeat);
114 root.altTabNext(event.isAutoRepeat);
113 }
115 }
114 } else if (event.key == Qt.Key_Backtab) {
116 } else if (event.key == Qt.Key_Backtab) {
@@ -117,7 +119,6 @@ Item {
117 }
119 }
118 } else if (event.key == Qt.Key_Left) {
120 } else if (event.key == Qt.Key_Left) {
119 if (d.altTabPressed) {
121 if (d.altTabPressed) {
120− print("alttabprevious")
121 root.altTabPrevious(event.isAutoRepeat);
122 root.altTabPrevious(event.isAutoRepeat);
122 event.accpeted = true;
123 event.accpeted = true;
123 }
124 }
@@ -141,7 +142,7 @@ Item {
141 if (!d.ignoreVolumeEvents) root.volumeUpTriggered();
142 if (!d.ignoreVolumeEvents) root.volumeUpTriggered();
142 d.volumeUpKeyPressed = false;
143 d.volumeUpKeyPressed = false;
143 if (!d.volumeDownKeyPressed) d.ignoreVolumeEvents = false;
144 if (!d.volumeDownKeyPressed) d.ignoreVolumeEvents = false;
144− } else if (event.key == Qt.Key_Control) {
145+ } else if (event.key == Qt.Key_Alt || (root.controlInsteadOfAlt && event.key == Qt.Key_Control)) {
145 d.altPressed = false;
146 d.altPressed = false;
146 if (d.altTabPressed) {
147 if (d.altTabPressed) {
147 d.altTabPressed = false;
148 d.altTabPressed = false;
qml/Stages/ApplicationWindow.qml+3
@@ -135,6 +135,9 @@ FocusScope {
135 onSurfaceChanged: {
135 onSurfaceChanged: {
136 if (sessionContainer.surface) {
136 if (sessionContainer.surface) {
137 surfaceInitTimer.start();
137 surfaceInitTimer.start();
138+ if (ApplicationManager.focusedApplicationId == application.appId) {
139+ root.forceActiveFocus();
140+ }
138 } else {
141 } else {
139 d.surfaceInitialized = false;
142 d.surfaceInitialized = false;
140 }
143 }
qml/Stages/DesktopStage.qml+15−15
@@ -56,25 +56,20 @@ Rectangle {
56 property bool altTabPressed: false
56 property bool altTabPressed: false
57
57
58 onAltTabPressedChanged: {
58 onAltTabPressedChanged: {
59− print("Alt+Tab pressed:", altTabPressed)
60− if (altTabPressed) {
59+ if (!altTabPressed && root.state == "altTab") {
61− appRepeater.highlightedIndex = Math.min(ApplicationManager.count - 1, 1);
62− } else {
63− if (root.state == "altTab") {
64− print("focusing app", appRepeater.highlightedIndex)
65− ApplicationManager.requestFocusApplication(ApplicationManager.get(appRepeater.highlightedIndex).appId)
60+ ApplicationManager.requestFocusApplication(ApplicationManager.get(appRepeater.highlightedIndex).appId)
66− }
67 }
61 }
68 }
62 }
69
63
70 function altTabNext(isAutoRepeat) {
64 function altTabNext(isAutoRepeat) {
71 if (root.altTabPressed) {
65 if (root.altTabPressed) {
72− print("should tab next")
66+ print("should tab next", isAutoRepeat, "highlightedIndex is", appRepeater.highlightedIndex)
73 if (isAutoRepeat && appRepeater.highlightedIndex >= ApplicationManager.count -1) {
67 if (isAutoRepeat && appRepeater.highlightedIndex >= ApplicationManager.count -1) {
74 return; // AutoRepeat is not allowed to wrap around
68 return; // AutoRepeat is not allowed to wrap around
75 }
69 }
76
70
77 appRepeater.highlightedIndex = (appRepeater.highlightedIndex + 1) % ApplicationManager.count;
71 appRepeater.highlightedIndex = (appRepeater.highlightedIndex + 1) % ApplicationManager.count;
72+ print("new highlighted index", appRepeater.highlightedIndex)
78 var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, appRepeater.highlightedIndex - 3));
73 var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, appRepeater.highlightedIndex - 3));
79 if (spreadFlickable.contentX < newContentX || appRepeater.highlightedIndex == 0) {
74 if (spreadFlickable.contentX < newContentX || appRepeater.highlightedIndex == 0) {
80 spreadFlickable.snapTo(newContentX)
75 spreadFlickable.snapTo(newContentX)
@@ -90,6 +85,7 @@ Rectangle {
90 }
85 }
91
86
92 var newIndex = appRepeater.highlightedIndex - 1 >= 0 ? appRepeater.highlightedIndex - 1 : ApplicationManager.count - 1;
87 var newIndex = appRepeater.highlightedIndex - 1 >= 0 ? appRepeater.highlightedIndex - 1 : ApplicationManager.count - 1;
88+ print("setting highlighted to", newIndex)
93 appRepeater.highlightedIndex = newIndex;
89 appRepeater.highlightedIndex = newIndex;
94 var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, appRepeater.highlightedIndex - 1));
90 var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, appRepeater.highlightedIndex - 1));
95 if (spreadFlickable.contentX > newContentX || newIndex == ApplicationManager.count -1) {
91 if (spreadFlickable.contentX > newContentX || newIndex == ApplicationManager.count -1) {
@@ -174,8 +170,12 @@ Rectangle {
174 Repeater {
170 Repeater {
175 id: appRepeater
171 id: appRepeater
176 model: ApplicationManager
172 model: ApplicationManager
173+ objectName: "appRepeater"
177
174
178 property int highlightedIndex: -1
175 property int highlightedIndex: -1
176+ onHighlightedIndexChanged: {
177+ print("****** changed:", highlightedIndex)
178+ }
179
179
180 delegate: FocusScope {
180 delegate: FocusScope {
181 id: appDelegate
181 id: appDelegate
@@ -321,6 +321,7 @@ Rectangle {
321 onMouseYChanged: evaluateContainsMouse()
321 onMouseYChanged: evaluateContainsMouse()
322 function evaluateContainsMouse() {
322 function evaluateContainsMouse() {
323 if (containsMouse) {
323 if (containsMouse) {
324+ print("setting highlighted to", index)
324 appRepeater.highlightedIndex = index
325 appRepeater.highlightedIndex = index
325 }
326 }
326
327
@@ -370,7 +371,7 @@ Rectangle {
370 spacing: units.gu(1)
371 spacing: units.gu(1)
371
372
372 UbuntuShape {
373 UbuntuShape {
373− Layout.preferredHeight: units.gu(6)
374+ Layout.preferredHeight: Math.min(units.gu(6), root.height * .05)
374 Layout.preferredWidth: height
375 Layout.preferredWidth: height
375 image: Image {
376 image: Image {
376 anchors.fill: parent
377 anchors.fill: parent
@@ -380,7 +381,7 @@ Rectangle {
380 Label {
381 Label {
381 Layout.fillWidth: true
382 Layout.fillWidth: true
382 Layout.preferredHeight: units.gu(6)
383 Layout.preferredHeight: units.gu(6)
383− text: model.name
384+ text: model.name + " -- " + index + appRepeater.highlightedIndex
384 wrapMode: Text.WordWrap
385 wrapMode: Text.WordWrap
385 maximumLineCount: 2
386 maximumLineCount: 2
386 }
387 }
@@ -503,9 +504,6 @@ Rectangle {
503 }
504 }
504
505
505 states: [
506 states: [
506− State {
507− name: "windowed"
508− },
509 State {
507 State {
510 name: "altTab"; when: root.altTabPressed
508 name: "altTab"; when: root.altTabPressed
511 PropertyChanges { target: workspaceSelector; visible: true }
509 PropertyChanges { target: workspaceSelector; visible: true }
@@ -549,7 +547,9 @@ Rectangle {
549 right: parent.right
547 right: parent.right
550 bottom: parent.bottom
548 bottom: parent.bottom
551 }
549 }
550+ // TODO: Make this a push to edge thing like the launcher when we can,
552− width: 1 // yes, we want 1 pixel, regardless of the scaling
551+ // for now, yes, we want 1 pixel, regardless of the scaling
552+ width: 1
553 hoverEnabled: true
553 hoverEnabled: true
554 onContainsMouseChanged: {
554 onContainsMouseChanged: {
555 if (containsMouse) {
555 if (containsMouse) {
tests/qmltests/tst_Shell.qml+157
@@ -109,6 +109,7 @@ Rectangle {
109 property bool itemDestroyed: false
109 property bool itemDestroyed: false
110 sourceComponent: Component {
110 sourceComponent: Component {
111 Shell {
111 Shell {
112+ id: __shell
112 property string shellMode: "full-greeter" /* default */
113 property string shellMode: "full-greeter" /* default */
113
114
114 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
115 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
@@ -118,6 +119,10 @@ Rectangle {
118 Component.onDestruction: {
119 Component.onDestruction: {
119 shellLoader.itemDestroyed = true;
120 shellLoader.itemDestroyed = true;
120 }
121 }
122+ Component.onCompleted: {
123+ var keyMapper = testCase.findChild(__shell, "physicalKeysMapper");
124+ keyMapper.controlInsteadOfAlt = true;
125+ }
121 }
126 }
122 }
127 }
123 }
128 }
@@ -327,6 +332,20 @@ Rectangle {
327 waitForGreeterToStabilize();
332 waitForGreeterToStabilize();
328 }
333 }
329
334
335+ function loadDesktopShellWithApps() {
336+ loadShell("desktop");
337+ shell.usageScenario = "desktop"
338+ waitForRendering(root)
339+ var app1 = ApplicationManager.startApplication("dialer-app")
340+ var app2 = ApplicationManager.startApplication("webbrowser-app")
341+ var app3 = ApplicationManager.startApplication("camera-app")
342+ var app4 = ApplicationManager.startApplication("facebook-webapp")
343+ var app5 = ApplicationManager.startApplication("calendar-app")
344+ var app6 = ApplicationManager.startApplication("gallery-app")
345+ var app7 = ApplicationManager.startApplication("camera-app")
346+ waitUntilAppWindowIsFullyLoaded(app7);
347+ }
348+
330 function waitForGreeterToStabilize() {
349 function waitForGreeterToStabilize() {
331 var greeter = findChild(shell, "greeter");
350 var greeter = findChild(shell, "greeter");
332 verify(greeter);
351 verify(greeter);
@@ -1287,5 +1306,143 @@ Rectangle {
1287 var launcher = findChild(shell, "launcher");
1306 var launcher = findChild(shell, "launcher");
1288 compare(launcher.inverted, data.launcherInverted);
1307 compare(launcher.inverted, data.launcherInverted);
1289 }
1308 }
1309+
1310+ function test_altTabSwitchesFocus() {
1311+ loadShell("desktop");
1312+ shell.usageScenario = "desktop"
1313+ waitForRendering(root)
1314+
1315+ var desktopStage = findChild(shell, "stage");
1316+ verify(desktopStage != null)
1317+
1318+ var app1 = ApplicationManager.startApplication("dialer-app")
1319+ waitUntilAppWindowIsFullyLoaded(app1);
1320+ var app2 = ApplicationManager.startApplication("webbrowser-app")
1321+ waitUntilAppWindowIsFullyLoaded(app2);
1322+ var app3 = ApplicationManager.startApplication("camera-app")
1323+ waitUntilAppWindowIsFullyLoaded(app3);
1324+
1325+ // Do a quick alt-tab and see if focus changes
1326+ tryCompare(app3.session.surface, "activeFocus", true)
1327+ keyClick(Qt.Key_Tab, Qt.ControlModifier)
1328+ tryCompare(app2.session.surface, "activeFocus", true)
1329+
1330+
1331+ tryCompare(desktopStage, "state", "")
1332+
1333+ // Just press Alt, make sure the spread comes up
1334+ keyPress(Qt.Key_Control);
1335+ keyClick(Qt.Key_Tab);
1336+ tryCompare(desktopStage, "state", "altTab")
1337+
1338+ // Release control, check if spread disappears
1339+ keyRelease(Qt.Key_Control)
1340+ tryCompare(desktopStage, "state", "")
1341+
1342+ // Focus should have switched back now
1343+ tryCompare(app3.session.surface, "activeFocus", true)
1344+ }
1345+
1346+ function test_altTabWrapAround() {
1347+ loadDesktopShellWithApps();
1348+
1349+ var desktopStage = findChild(shell, "stage");
1350+ verify(desktopStage !== null)
1351+
1352+ var appRepeater = findInvisibleChild(shell, "appRepeater")
1353+ verify(appRepeater !== null)
1354+
1355+ // remember the focused appId
1356+ var focused = ApplicationManager.get(ApplicationManager.findApplication(ApplicationManager.focusedApplicationId));
1357+
1358+ tryCompare(desktopStage, "state", "")
1359+
1360+ // Just press Alt, make sure the spread comes up
1361+ keyPress(Qt.Key_Control);
1362+ keyClick(Qt.Key_Tab);
1363+ tryCompare(desktopStage, "state", "altTab")
1364+ tryCompare(appRepeater, "highlightedIndex", 1)
1365+ waitForRendering(shell)
1366+
1367+ // Now press and hold Tab, make sure the highlight moves all the way but stops at the last one
1368+ // We can't simulate a pressed key with keyPress() currently, so let's inject the events
1369+ // at API level. Jump for 10 times, verify that it's still at the last one and didn't wrap around.
1370+ for (var i = 0; i < 10; i++) {
1371+ desktopStage.altTabNext(true);
1372+ wait(0); // Trigger the event loop to make sure all the things happen
1373+ }
1374+ tryCompare(appRepeater, "highlightedIndex", 6)
1375+
1376+ // Now release it once, and verify that it does wrap around with an additional Tab press
1377+ keyRelease(Qt.Key_Tab);
1378+ keyClick(Qt.Key_Tab);
1379+ tryCompare(appRepeater, "highlightedIndex", 0)
1380+
1381+ // Release control, check if spread disappears
1382+ keyRelease(Qt.Key_Control)
1383+ tryCompare(desktopStage, "state", "")
1384+
1385+ // Make sure that after wrapping around once, we have the same one focused as at the beginning
1386+ tryCompare(focused.session.surface, "activeFocus", true)
1387+ }
1388+
1389+ function test_altBackTabNavigation() {
1390+ loadDesktopShellWithApps();
1391+
1392+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1393+ verify(appRepeater !== null);
1394+
1395+ keyPress(Qt.Key_Control)
1396+ keyClick(Qt.Key_Tab);
1397+ tryCompare(appRepeater, "highlightedIndex", 1);
1398+
1399+ keyClick(Qt.Key_Tab);
1400+ tryCompare(appRepeater, "highlightedIndex", 2);
1401+
1402+ keyClick(Qt.Key_Tab);
1403+ tryCompare(appRepeater, "highlightedIndex", 3);
1404+
1405+ keyClick(Qt.Key_Tab);
1406+ tryCompare(appRepeater, "highlightedIndex", 4);
1407+
1408+ keyClick(Qt.Key_Backtab);
1409+ tryCompare(appRepeater, "highlightedIndex", 3);
1410+
1411+ keyClick(Qt.Key_Backtab);
1412+ tryCompare(appRepeater, "highlightedIndex", 2);
1413+
1414+ keyClick(Qt.Key_Backtab);
1415+ tryCompare(appRepeater, "highlightedIndex", 1);
1416+
1417+ keyRelease(Qt.Key_Control);
1418+ }
1419+
1420+ function test_highlightFollowsMouse() {
1421+ loadDesktopShellWithApps()
1422+
1423+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1424+ verify(appRepeater !== null);
1425+
1426+ keyPress(Qt.Key_Control)
1427+ keyClick(Qt.Key_Tab);
1428+
1429+ tryCompare(appRepeater, "highlightedIndex", 1);
1430+
1431+ var x = 0;
1432+ var y = shell.height * .75;
1433+ mouseMove(shell, x, y)
1434+
1435+ for (var i = 0; i < 7; i++) {
1436+ while (appRepeater.highlightedIndex != i && x <= 4000) {
1437+ x+=10;
1438+ mouseMove(shell, x, y)
1439+ waitForRendering(shell)
1440+ }
1441+ }
1442+
1443+ verify(y < 4000);
1444+
1445+ keyRelease(Qt.Key_Control);
1446+ }
1290 }
1447 }
1291}
1448}