Merge lp:~mzanetti/unity8/edgebarrier-click-transparent into lp:unity8

Proposed by Michael Zanetti
Status: Merged
Approved by: Michael Zanetti
Approved revision: 2143
Merged at revision: 2188
Proposed branch: lp:~mzanetti/unity8/edgebarrier-click-transparent
Merge into: lp:unity8
Diff against target: 2600 lines (+1253/-362)
17 files modified
data/com.canonical.Unity8.gschema.xml (+11/-0)
qml/Components/EdgeBarrierController.qml (+2/-0)
qml/Components/PhysicalKeysMapper.qml (+24/-0)
qml/Launcher/Launcher.qml (+143/-11)
qml/Launcher/LauncherDelegate.qml (+54/-20)
qml/Launcher/LauncherPanel.qml (+122/-51)
qml/Launcher/graphics/launcher-app-focus-ring.svg (+12/-0)
qml/Shell.qml (+51/-1)
qml/Stages/AbstractStage.qml (+2/-0)
qml/Stages/DesktopStage.qml (+231/-225)
tests/mocks/GSettings.1.0/fake_gsettings.cpp (+64/-0)
tests/mocks/GSettings.1.0/fake_gsettings.h (+18/-0)
tests/mocks/Unity/Application/MirSurfaceItem.cpp (+6/-0)
tests/mocks/Unity/Application/MirSurfaceItem.h (+14/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+2/-0)
tests/qmltests/Launcher/tst_Launcher.qml (+244/-18)
tests/qmltests/tst_Shell.qml (+253/-36)
To merge this branch: bzr merge lp:~mzanetti/unity8/edgebarrier-click-transparent
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
PS Jenkins bot (community) continuous-integration Needs Fixing
Albert Astals Cid (community) Approve
Review via email: mp+283735@code.launchpad.net

Commit message

Don't eat mouse events in the edgebarrer

Description of the change

 * Are there any related MPs required for this MP to build/function as expected? Please list.
nope
 * Did you perform an exploratory manual test run of your code change and any related functionality?
yes
 * Did you make sure that your branch does not contain spurious tags?
yes
 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
n/a
 * If you changed the UI, has there been a design review?
n/a

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2142
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/188/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/188/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:2142
http://jenkins.qa.ubuntu.com/job/unity8-ci/7145/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6171
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/560/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1850
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/553
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1745
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1745
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/552
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/551
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4761
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6182
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6182/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26993
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/291/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/558
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/558/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26992

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/7145/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Does a test make sense here?

Revision history for this message
Michael Zanetti (mzanetti) wrote :

I was thinking no at first because there isn't an obvious mousearea here. It seemed like adding tests for randomly clicking on the screen and testing if the thing doesn't catch fire. But thinking about it more, I realized that we have so much stuff going on the edges that it does make sense indeed to make sure nothing ever appears on the edges that intercepts regular mouse clicks in any way. Will add them.

2143. By Michael Zanetti

add tests to make sure nothing intercepts input events around the edges

Revision history for this message
Michael Zanetti (mzanetti) wrote :

Done

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2143
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/194/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/194/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass?
Passed locally, waiting for run before top-approval

 * Did you make sure that the branch does not contain spurious tags?
Yes

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:2143
http://jenkins.qa.ubuntu.com/job/unity8-ci/7151/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6183
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/566/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1856
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/559
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1751
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1751
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/558
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/557
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4770
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6194
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6194/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27015
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/295/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/564
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/564/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27014

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/7151/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2143
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/242/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/242/rebuild

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/com.canonical.Unity8.gschema.xml'
2--- data/com.canonical.Unity8.gschema.xml 2015-11-24 17:44:18 +0000
3+++ data/com.canonical.Unity8.gschema.xml 2016-02-02 22:18:26 +0000
4@@ -27,6 +27,17 @@
5 <summary>Maximum push needed to overcome edge barrier</summary>
6 <description>How much you have to push (in grid units) the mouse against an edge barrier when sensibility is 1.</description>
7 </key>
8+ <key type="b" name="autohide-launcher">
9+ <default>false</default>
10+ <summary>Autohide the launcher</summary>
11+ <description>This will only be applied in windowed mode. In staged mode, the launcher will always hide.</description>
12+ </key>
13+ <key type="u" name="launcher-width">
14+ <default>8</default>
15+ <range min="6" max="12"/>
16+ <summary>Width of the launcher in grid units.</summary>
17+ <description>Changes the width of the launcher in all usage modes.</description>
18+ </key>
19 </schema>
20
21 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
22
23=== modified file 'qml/Components/EdgeBarrierController.qml'
24--- qml/Components/EdgeBarrierController.qml 2015-11-24 17:44:18 +0000
25+++ qml/Components/EdgeBarrierController.qml 2016-02-02 22:18:26 +0000
26@@ -30,6 +30,8 @@
27 // Should trigger the action associated with this edge
28 signal passed()
29
30+ onPressed: mouse.accepted = false;
31+
32 function push(amount) {
33 if (!root._containsMouse) {
34 return;
35
36=== modified file 'qml/Components/PhysicalKeysMapper.qml'
37--- qml/Components/PhysicalKeysMapper.qml 2016-01-13 18:43:34 +0000
38+++ qml/Components/PhysicalKeysMapper.qml 2016-02-02 22:18:26 +0000
39@@ -42,12 +42,15 @@
40 signal screenshotTriggered;
41
42 readonly property bool altTabPressed: d.altTabPressed
43+ readonly property bool superPressed: d.superPressed
44+ readonly property bool superTabPressed: d.superTabPressed
45
46 property int powerKeyLongPressTime: 2000
47
48 // For testing. If running windowed (e.g. tryShell), Alt+Tab is taken by the
49 // running desktop, set this to true to use Ctrl+Tab instead.
50 property bool controlInsteadOfAlt: false
51+ property bool controlInsteadOfSuper: false
52
53 QtObject {
54 id: d
55@@ -59,6 +62,9 @@
56 property bool altPressed: false
57 property bool altTabPressed: false
58
59+ property bool superPressed: false
60+ property bool superTabPressed: false
61+
62 property var powerButtonPressStart: 0
63
64 // We need to eat ALT presses until we know what they're for (Alt+Tab or going to the app?)
65@@ -119,11 +125,23 @@
66 event.accepted = true;
67 d.altPressInjected = false;
68 }
69+
70+ // Adding MetaModifier here because that's what keyboards do. Pressing Super_L actually gives
71+ // Super_L + MetaModifier. This helps to make sure we only invoke superPressed if no other
72+ // Modifier is pressed too.
73+ } else if (((event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R) && event.modifiers === Qt.MetaModifier)
74+ || (root.controlInsteadOfSuper && event.key == Qt.Key_Control)
75+ ) {
76+ d.superPressed = true;
77 } else if (event.key == Qt.Key_Tab) {
78 if (d.altPressed && !d.altTabPressed) {
79 d.altTabPressed = true;
80 event.accepted = true;
81 }
82+ if (d.superPressed && !d.superTabPressed) {
83+ d.superTabPressed = true;
84+ event.accepted = true;
85+ }
86 }
87 }
88
89@@ -154,6 +172,12 @@
90 if (d.altTabPressed) {
91 event.accepted = true;
92 }
93+ } else if (event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R || (root.controlInsteadOfSuper && event.key == Qt.Key_Control)) {
94+ d.superPressed = false;
95+ if (d.superTabPressed) {
96+ d.superTabPressed = false;
97+ event.accepted = true;
98+ }
99 }
100 }
101 }
102
103=== modified file 'qml/Launcher/Launcher.qml'
104--- qml/Launcher/Launcher.qml 2016-01-19 15:26:15 +0000
105+++ qml/Launcher/Launcher.qml 2016-02-02 22:18:26 +0000
106@@ -19,21 +19,26 @@
107 import Ubuntu.Components 1.3
108 import Ubuntu.Gestures 0.1
109 import Unity.Launcher 0.1
110+import GlobalShortcut 1.0
111
112-Item {
113+FocusScope {
114 id: root
115
116 property bool autohideEnabled: false
117+ property bool lockedVisible: false
118 property bool available: true // can be used to disable all interactions
119 property alias inverted: panel.inverted
120 property bool shadeBackground: true // can be used to disable background shade when launcher is visible
121
122- property int panelWidth: units.gu(8)
123+ property int panelWidth: units.gu(10)
124 property int dragAreaWidth: units.gu(1)
125 property int minimizeDistance: units.gu(26)
126 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
127 (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
128
129+ property bool superPressed: false
130+ property bool superTabPressed: false
131+
132 readonly property bool dragging: dragArea.dragging
133 readonly property real dragDistance: dragArea.dragging ? dragArea.touchX : 0
134 readonly property real visibleWidth: panel.width + panel.x
135@@ -57,12 +62,55 @@
136 }
137 }
138
139+ onSuperPressedChanged: {
140+ if (superPressed) {
141+ superPressTimer.start();
142+ superLongPressTimer.start();
143+ } else {
144+ superPressTimer.stop();
145+ superLongPressTimer.stop();
146+ launcher.switchToNextState("");
147+ panel.shortcutHintsShown = false;
148+ }
149+ }
150+
151+ onSuperTabPressedChanged: {
152+ if (superTabPressed) {
153+ switchToNextState("visible")
154+ panel.highlightIndex = -1;
155+ root.focus = true;
156+ superPressTimer.stop();
157+ superLongPressTimer.stop();
158+ } else {
159+ if (panel.highlightIndex == -1) {
160+ showDashHome();
161+ } else if (panel.highlightIndex >= 0){
162+ launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
163+ }
164+ panel.highlightIndex = -2;
165+ switchToNextState("");
166+ root.focus = false;
167+ }
168+ }
169+
170+ onLockedVisibleChanged: {
171+ if (lockedVisible && state == "") {
172+ panel.dismissTimer.stop();
173+ fadeOutAnimation.stop();
174+ switchToNextState("visible")
175+ } else if (!lockedVisible && state == "visible") {
176+ hide();
177+ }
178+ }
179+
180 function hide() {
181 switchToNextState("")
182 }
183
184 function fadeOut() {
185- fadeOutAnimation.start();
186+ if (!root.lockedVisible) {
187+ fadeOutAnimation.start();
188+ }
189 }
190
191 function switchToNextState(state) {
192@@ -90,6 +138,76 @@
193 }
194 }
195
196+ function openForKeyboardNavigation() {
197+ panel.highlightIndex = -1; // The BFB
198+ root.focus = true;
199+ switchToNextState("visible")
200+ }
201+
202+ Keys.onPressed: {
203+ switch (event.key) {
204+ case Qt.Key_Backtab:
205+ panel.highlightPrevious();
206+ event.accepted = true;
207+ break;
208+ case Qt.Key_Up:
209+ if (root.inverted) {
210+ panel.highlightNext()
211+ } else {
212+ panel.highlightPrevious();
213+ }
214+ event.accepted = true;
215+ break;
216+ case Qt.Key_Tab:
217+ panel.highlightNext();
218+ event.accepted = true;
219+ break;
220+ case Qt.Key_Down:
221+ if (root.inverted) {
222+ panel.highlightPrevious();
223+ } else {
224+ panel.highlightNext();
225+ }
226+ event.accepted = true;
227+ break;
228+ case Qt.Key_Right:
229+ panel.openQuicklist(panel.highlightIndex)
230+ event.accepted = true;
231+ break;
232+ case Qt.Key_Escape:
233+ panel.highlightIndex = -2
234+ // Falling through intentionally
235+ case Qt.Key_Enter:
236+ case Qt.Key_Return:
237+ case Qt.Key_Space:
238+ if (panel.highlightIndex == -1) {
239+ showDashHome();
240+ } else if (panel.highlightIndex >= 0) {
241+ launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
242+ }
243+ root.hide();
244+ event.accepted = true;
245+ root.focus = false;
246+ }
247+ }
248+
249+ Timer {
250+ id: superPressTimer
251+ interval: 200
252+ onTriggered: {
253+ switchToNextState("visible")
254+ }
255+ }
256+
257+ Timer {
258+ id: superLongPressTimer
259+ interval: 1000
260+ onTriggered: {
261+ switchToNextState("visible")
262+ panel.shortcutHintsShown = true;
263+ }
264+ }
265+
266 Timer {
267 id: teaseTimer
268 interval: mode == "teasing" ? 200 : 300
269@@ -106,6 +224,13 @@
270 interval: 1
271 property string nextState: ""
272 onTriggered: {
273+ if (root.lockedVisible && nextState == "") {
274+ // Due to binding updates when switching between modes
275+ // it could happen that our request to show will be overwritten
276+ // with a hide request. Rewrite it when we know hiding is not allowed.
277+ nextState = "visible"
278+ }
279+
280 // switching to an intermediate state here to make sure all the
281 // values are restored, even if we were already in the target state
282 root.state = "tmp"
283@@ -151,7 +276,7 @@
284
285 MouseArea {
286 id: launcherDragArea
287- enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary")
288+ enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary") && !root.lockedVisible
289 anchors.fill: panel
290 anchors.rightMargin: -units.gu(2)
291 drag {
292@@ -172,9 +297,10 @@
293 InverseMouseArea {
294 id: closeMouseArea
295 anchors.fill: panel
296- enabled: root.shadeBackground && root.state == "visible"
297+ enabled: root.shadeBackground && root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1)
298 visible: enabled
299 onPressed: {
300+ panel.highlightIndex = -2
301 root.hide();
302 }
303 }
304@@ -183,7 +309,7 @@
305 id: backgroundShade
306 anchors.fill: parent
307 color: "black"
308- opacity: root.shadeBackground && root.state == "visible" ? 0.6 : 0
309+ opacity: root.shadeBackground && root.state == "visible" && !root.lockedVisible ? 0.6 : 0
310
311 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
312 }
313@@ -227,11 +353,11 @@
314 Connections {
315 target: panel.dismissTimer
316 onTriggered: {
317- if (root.autohideEnabled) {
318+ if (root.autohideEnabled && !root.lockedVisible) {
319 if (!panel.preventHiding) {
320- root.state = ""
321+ root.hide();
322 } else {
323- panel.dismissTimer.restart()
324+ dismissTimer.restart()
325 }
326 }
327 }
328@@ -240,11 +366,11 @@
329 property bool animate: true
330
331 onApplicationSelected: {
332- root.state = ""
333+ root.hide();
334 launcherApplicationSelected(appId)
335 }
336 onShowDashHome: {
337- root.state = ""
338+ root.hide();
339 root.showDashHome();
340 }
341
342@@ -254,6 +380,12 @@
343 }
344 }
345
346+ onKbdNavigationCancelled: {
347+ panel.highlightIndex = -2;
348+ root.hide();
349+ root.focus = false;
350+ }
351+
352 Behavior on x {
353 enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate;
354 NumberAnimation {
355
356=== modified file 'qml/Launcher/LauncherDelegate.qml'
357--- qml/Launcher/LauncherDelegate.qml 2015-11-19 16:55:31 +0000
358+++ qml/Launcher/LauncherDelegate.qml 2016-02-02 22:18:26 +0000
359@@ -20,6 +20,7 @@
360 Item {
361 id: root
362
363+ property int itemIndex: 0
364 property string iconName
365 property int count: 0
366 property bool countVisible: false
367@@ -29,10 +30,12 @@
368 property real maxAngle: 0
369 property bool inverted: false
370 property bool alerting: false
371- readonly property alias wiggling: wiggleAnim.running
372+ property bool highlighted: false
373+ property bool shortcutHintShown: false
374
375 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
376 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
377+ readonly property alias wiggling: wiggleAnim.running
378
379 property int itemWidth
380 property int itemHeight
381@@ -121,14 +124,25 @@
382
383 Item {
384 id: iconItem
385- width: parent.itemWidth + units.gu(1)
386+ width: root.width
387 height: parent.itemHeight + units.gu(1)
388 anchors.centerIn: parent
389
390+ Image {
391+ objectName: "focusRing"
392+ anchors.centerIn: iconShape
393+ height: width * 15 / 16
394+ width: iconShape.width + units.gu(1)
395+ source: "graphics/launcher-app-focus-ring.svg"
396+ sourceSize.width: width
397+ sourceSize.height: height
398+ visible: root.highlighted
399+ }
400+
401 ProportionalShape {
402 id: iconShape
403 anchors.centerIn: parent
404- width: parent.width - units.gu(2)
405+ width: root.itemWidth
406 aspect: UbuntuShape.DropShadow
407 source: Image {
408 id: iconImage
409@@ -144,7 +158,8 @@
410 anchors {
411 right: parent.right
412 bottom: parent.bottom
413- margins: units.dp(3)
414+ rightMargin: (iconItem.width - root.itemWidth) / 2 - units.dp(2)
415+ margins: units.dp(5)
416 }
417 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
418 height: units.gu(2)
419@@ -172,16 +187,11 @@
420 id: progressOverlay
421 objectName: "progressOverlay"
422
423- anchors {
424- left: iconItem.left
425- right: iconItem.right
426- verticalCenter: parent.verticalCenter
427- leftMargin: units.gu(1.5)
428- rightMargin: units.gu(1.5)
429- }
430+ anchors.centerIn: parent
431+ width: root.itemWidth * .8
432 height: units.gu(1)
433 visible: root.progress > -1
434- color: UbuntuColors.darkGrey
435+ backgroundColor: UbuntuColors.darkGrey
436 borderSource: "none"
437
438 Item {
439@@ -199,32 +209,56 @@
440 top: parent.top
441 bottom: parent.bottom
442 }
443- color: "white"
444+ backgroundColor: "white"
445 borderSource: "none"
446 width: progressOverlay.width
447 }
448 }
449 }
450
451- Image {
452- objectName: "runningHighlight"
453+ Column {
454 anchors {
455 left: parent.left
456 verticalCenter: parent.verticalCenter
457 }
458- visible: root.itemRunning
459- rotation: 180
460- source: "graphics/focused_app_arrow.png"
461+ spacing: units.gu(.5)
462+ Repeater {
463+ model: 1 // TODO: This should be "Math.min(3, app.surfaceCount)" once we have multiple surfaces
464+ Rectangle {
465+ objectName: "runningHighlight" + index
466+ width: units.gu(0.25)
467+ height: units.gu(.5)
468+ color: "white"
469+ visible: root.itemRunning
470+ }
471+ }
472 }
473
474- Image {
475+ Rectangle {
476 objectName: "focusedHighlight"
477 anchors {
478 right: parent.right
479 verticalCenter: parent.verticalCenter
480 }
481+ width: units.gu(0.25)
482+ height: units.gu(.5)
483+ color: "white"
484 visible: root.itemFocused
485- source: "graphics/focused_app_arrow.png"
486+ }
487+
488+ Rectangle {
489+ objectName: "shortcutHint"
490+ anchors.centerIn: parent
491+ width: units.gu(3)
492+ height: width
493+ color: "#E0292929"
494+ visible: root.shortcutHintShown
495+ Label {
496+ anchors.centerIn: parent
497+ text: (itemIndex + 1) % 10
498+ color: "white"
499+ font.weight: Font.DemiBold
500+ }
501 }
502 }
503
504
505=== modified file 'qml/Launcher/LauncherPanel.qml'
506--- qml/Launcher/LauncherPanel.qml 2016-01-11 17:38:19 +0000
507+++ qml/Launcher/LauncherPanel.qml 2016-02-02 22:18:26 +0000
508@@ -19,12 +19,13 @@
509 import Ubuntu.Components.ListItems 1.3 as ListItems
510 import Unity.Launcher 0.1
511 import Ubuntu.Components.Popups 1.3
512+import GlobalShortcut 1.0
513 import "../Components/ListItems"
514 import "../Components/"
515
516 Rectangle {
517 id: root
518- color: "#B2000000"
519+ color: "#E0292929"
520
521 rotation: inverted ? 180 : 0
522
523@@ -33,11 +34,13 @@
524 property bool dragging: false
525 property bool moving: launcherListView.moving || launcherListView.flicking
526 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
527- || mouseEventEater.containsMouse || dashItem.hovered
528- property int highlightIndex: -1
529+ || mouseEventEater.containsMouse || dashItem.hovered
530+ property int highlightIndex: -2
531+ property bool shortcutHintsShown: false
532
533 signal applicationSelected(string appId)
534 signal showDashHome()
535+ signal kbdNavigationCancelled()
536
537 onXChanged: {
538 if (quickList.state == "open") {
539@@ -45,6 +48,26 @@
540 }
541 }
542
543+ function highlightNext() {
544+ highlightIndex++;
545+ if (highlightIndex >= launcherListView.count) {
546+ highlightIndex = -1;
547+ }
548+ launcherListView.moveToIndex(Math.max(highlightIndex, 0));
549+ }
550+ function highlightPrevious() {
551+ highlightIndex--;
552+ if (highlightIndex <= -2) {
553+ highlightIndex = launcherListView.count - 1;
554+ }
555+ launcherListView.moveToIndex(Math.max(highlightIndex, 0));
556+ }
557+ function openQuicklist(index) {
558+ quickList.open(index);
559+ quickList.selectedIndex = 0;
560+ quickList.focus = true;
561+ }
562+
563 MouseArea {
564 id: mouseEventEater
565 anchors.fill: parent
566@@ -57,24 +80,16 @@
567 fill: parent
568 }
569
570- Item {
571+ Rectangle {
572 objectName: "buttonShowDashHome"
573 width: parent.width
574- height: units.gu(7)
575- clip: true
576-
577- UbuntuShape {
578- anchors {
579- fill: parent
580- topMargin: -units.gu(2)
581- }
582- aspect: UbuntuShape.Flat
583- backgroundColor: UbuntuColors.orange
584- }
585+ height: width * .9
586+ color: UbuntuColors.orange
587+ readonly property bool highlighted: root.highlightIndex == -1;
588
589 Image {
590 objectName: "dashItem"
591- width: units.gu(5)
592+ width: parent.width * .6
593 height: width
594 anchors.centerIn: parent
595 source: "graphics/home.png"
596@@ -85,6 +100,14 @@
597 anchors.fill: parent
598 onClicked: root.showDashHome()
599 }
600+ Rectangle {
601+ objectName: "bfbFocusHighlight"
602+ anchors.fill: parent
603+ border.color: "white"
604+ border.width: units.dp(1)
605+ color: "transparent"
606+ visible: parent.highlighted
607+ }
608 }
609
610 Item {
611@@ -102,10 +125,8 @@
612 objectName: "launcherListView"
613 anchors {
614 fill: parent
615- topMargin: -extensionSize + units.gu(0.5)
616- bottomMargin: -extensionSize + units.gu(1)
617- leftMargin: units.gu(0.5)
618- rightMargin: units.gu(0.5)
619+ topMargin: -extensionSize + width * .15
620+ bottomMargin: -extensionSize + width * .15
621 }
622 topMargin: extensionSize
623 bottomMargin: extensionSize
624@@ -140,11 +161,11 @@
625 }
626
627 // The height of the area where icons start getting folded
628- property int foldingStartHeight: units.gu(6.5)
629+ property int foldingStartHeight: itemHeight
630 // The height of the area where the items reach the final folding angle
631 property int foldingStopHeight: foldingStartHeight - itemHeight - spacing
632- property int itemWidth: units.gu(7)
633- property int itemHeight: units.gu(6.5)
634+ property int itemWidth: width * .75
635+ property int itemHeight: itemWidth * 15 / 16 + units.gu(1)
636 property int clickFlickSpeed: units.gu(60)
637 property int draggedIndex: dndArea.draggedIndex
638 property real realContentY: contentY - originY + topMargin
639@@ -172,12 +193,24 @@
640
641 UbuntuNumberAnimation {
642 id: moveAnimation
643+ objectName: "moveAnimation"
644 target: launcherListView
645 property: "contentY"
646 function moveTo(contentY) {
647 from = launcherListView.contentY;
648 to = contentY;
649- start();
650+ restart();
651+ }
652+ }
653+ function moveToIndex(index) {
654+ var totalItemHeight = launcherListView.itemHeight + launcherListView.spacing
655+ var itemPosition = index * totalItemHeight;
656+ var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
657+ var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : totalItemHeight
658+ if (itemPosition + totalItemHeight + distanceToEnd > launcherListView.contentY + launcherListView.originY + launcherListView.topMargin + height) {
659+ moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd - launcherListView.originY);
660+ } else if (itemPosition - distanceToEnd < launcherListView.contentY - launcherListView.originY + launcherListView.topMargin) {
661+ moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin + launcherListView.originY);
662 }
663 }
664
665@@ -192,9 +225,10 @@
666 // the right app when running autopilot tests for
667 // multiple apps.
668 readonly property string appId: model.appId
669+ itemIndex: index
670 itemHeight: launcherListView.itemHeight
671 itemWidth: launcherListView.itemWidth
672- width: itemWidth
673+ width: parent.width
674 height: itemHeight
675 iconName: model.icon
676 count: model.count
677@@ -204,6 +238,8 @@
678 itemFocused: model.focused
679 inverted: root.inverted
680 alerting: model.alerting
681+ highlighted: root.highlightIndex == index
682+ shortcutHintShown: root.shortcutHintsShown && index <= 9
683 z: -Math.abs(offset)
684 maxAngle: 55
685 property bool dragging: false
686@@ -241,14 +277,7 @@
687 onAlertingChanged: {
688 if(alerting) {
689 if (!dragging && (launcherListView.peekingIndex === -1 || launcher.visibleWidth > 0)) {
690- var itemPosition = index * launcherListView.itemHeight;
691- var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
692- var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : launcherListView.itemHeight
693- if (itemPosition + launcherListView.itemHeight + distanceToEnd > launcherListView.contentY + launcherListView.topMargin + height) {
694- moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd);
695- } else if (itemPosition - distanceToEnd < launcherListView.contentY + launcherListView.topMargin) {
696- moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin);
697- }
698+ launcherListView.moveToIndex(index)
699 if (!dragging && launcher.state !== "visible") {
700 peekingAnimation.start()
701 }
702@@ -402,10 +431,7 @@
703
704 if (mouse.button & Qt.RightButton) { // context menu
705 // Opening QuickList
706- quickList.item = clickedItem;
707- quickList.model = launcherListView.model.get(index).quickList;
708- quickList.appId = launcherListView.model.get(index).appId;
709- quickList.state = "open";
710+ quickList.open(index);
711 return;
712 }
713
714@@ -413,10 +439,8 @@
715
716 // First/last item do the scrolling at more than 12 degrees
717 if (index == 0 || index == launcherListView.count - 1) {
718- if (clickedItem.angle > 12) {
719- launcherListView.flick(0, -launcherListView.clickFlickSpeed);
720- } else if (clickedItem.angle < -12) {
721- launcherListView.flick(0, launcherListView.clickFlickSpeed);
722+ if (clickedItem.angle > 12 || clickedItem.angle < -12) {
723+ launcherListView.moveToIndex(index);
724 } else {
725 root.applicationSelected(LauncherModel.get(index).appId);
726 }
727@@ -424,10 +448,8 @@
728 }
729
730 // the rest launches apps up to an angle of 30 degrees
731- if (clickedItem.angle > 30) {
732- launcherListView.flick(0, -launcherListView.clickFlickSpeed);
733- } else if (clickedItem.angle < -30) {
734- launcherListView.flick(0, launcherListView.clickFlickSpeed);
735+ if (clickedItem.angle > 30 || clickedItem.angle < -30) {
736+ launcherListView.moveToIndex(index);
737 } else {
738 root.applicationSelected(LauncherModel.get(index).appId);
739 }
740@@ -481,11 +503,7 @@
741
742 draggedIndex = Math.floor((mouse.y + launcherListView.realContentY) / launcherListView.realItemHeight);
743
744- // Opening QuickList
745- quickList.item = selectedItem;
746- quickList.model = launcherListView.model.get(draggedIndex).quickList;
747- quickList.appId = launcherListView.model.get(draggedIndex).appId;
748- quickList.state = "open";
749+ quickList.open(draggedIndex)
750
751 launcherListView.interactive = false
752
753@@ -644,7 +662,9 @@
754 enabled: quickList.state == "open" || pressed
755
756 onClicked: {
757- quickList.state = ""
758+ quickList.state = "";
759+ quickList.focus = false;
760+ root.kbdNavigationCancelled();
761 }
762
763 // Forward for dragging to work when quickList is open
764@@ -693,12 +713,60 @@
765 property var model
766 property string appId
767 property var item
768+ property int selectedIndex: -1
769+
770+ Keys.onPressed: {
771+ switch (event.key) {
772+ case Qt.Key_Down:
773+ selectedIndex++;
774+ if (selectedIndex >= popoverRepeater.count) {
775+ selectedIndex = 0;
776+ }
777+ event.accepted = true;
778+ break;
779+ case Qt.Key_Up:
780+ selectedIndex--;
781+ if (selectedIndex < 0) {
782+ selectedIndex = popoverRepeater.count - 1;
783+ }
784+ event.accepted = true;
785+ break;
786+ case Qt.Key_Left:
787+ case Qt.Key_Escape:
788+ quickList.selectedIndex = -1;
789+ quickList.focus = false;
790+ quickList.state = ""
791+ event.accepted = true;
792+ break;
793+ case Qt.Key_Enter:
794+ case Qt.Key_Return:
795+ case Qt.Key_Space:
796+ if (quickList.selectedIndex >= 0) {
797+ LauncherModel.quickListActionInvoked(quickList.appId, quickList.selectedIndex)
798+ }
799+ quickList.selectedIndex = -1;
800+ quickList.focus = false;
801+ quickList.state = ""
802+ root.kbdNavigationCancelled();
803+ event.accepted = true;
804+ break;
805+ }
806+ }
807
808 // internal
809 property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) + quickList.item.offset : units.gu(1)
810 property int offset: itemCenter + (height/2) + units.gu(1) > parent.height ? -itemCenter - (height/2) - units.gu(1) + parent.height :
811 itemCenter - (height/2) < units.gu(1) ? (height/2) - itemCenter + units.gu(1) : 0
812
813+ function open(index) {
814+ var itemPosition = index * launcherListView.itemHeight;
815+ var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
816+ item = launcherListView.itemAt(launcherListView.width / 2, itemPosition + launcherListView.itemHeight / 2);
817+ quickList.model = launcherListView.model.get(index).quickList;
818+ quickList.appId = launcherListView.model.get(index).appId;
819+ quickList.state = "open";
820+ }
821+
822 Column {
823 id: quickListColumn
824 width: parent.width
825@@ -712,6 +780,7 @@
826 objectName: "quickListEntry" + index
827 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
828 highlightWhenPressed: model.clickable
829+ selected: index === quickList.selectedIndex
830
831 // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
832 // ListItems don't know that they are sitting in a themed Popover where the color
833@@ -727,6 +796,8 @@
834 // Unsetting model to prevent showing changing entries during fading out
835 // that may happen because of triggering an action.
836 LauncherModel.quickListActionInvoked(quickList.appId, index);
837+ quickList.focus = false;
838+ root.kbdNavigationCancelled();
839 quickList.model = undefined;
840 }
841 }
842
843=== added file 'qml/Launcher/graphics/launcher-app-focus-ring.svg'
844--- qml/Launcher/graphics/launcher-app-focus-ring.svg 1970-01-01 00:00:00 +0000
845+++ qml/Launcher/graphics/launcher-app-focus-ring.svg 2016-02-02 22:18:26 +0000
846@@ -0,0 +1,12 @@
847+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
848+<svg width="172px" height="163px" viewBox="0 0 172 163" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
849+ <!-- Generator: Sketch 3.4.4 (17249) - http://www.bohemiancoding.com/sketch -->
850+ <title>Shape</title>
851+ <desc>Created with Sketch.</desc>
852+ <defs></defs>
853+ <g id="•-Launcher" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
854+ <g id="Artboard-9" sketch:type="MSArtboardGroup" transform="translate(-163.000000, -1436.000000)" fill="#E95420">
855+ <path d="M221.983432,1440 L221.983432,1440 C195.6127,1440 184.708233,1442.4723 177.107949,1450.10734 C169.476819,1457.77336 167,1468.79245 167,1495.3481 L167,1538.9019 C167,1565.45755 169.476819,1576.47664 177.107949,1584.14266 C184.708233,1591.7777 195.6127,1594.25 221.983432,1594.25 L276.016868,1594.25 C302.387595,1594.25 313.291998,1591.77771 320.892221,1584.14264 C328.523252,1576.47663 331,1565.45769 331,1538.9019 L331,1495.3481 C331,1468.79231 328.523252,1457.77337 320.892221,1450.10736 C313.291998,1442.47229 302.387595,1440 276.016868,1440 L221.983432,1440 Z M221.983432,1436 L276.016868,1436 C302.345315,1436 314.848953,1438.36655 323.727108,1447.2854 C332.633306,1456.23243 335,1468.85167 335,1495.3481 L335,1538.9019 C335,1565.39833 332.633306,1578.01757 323.727108,1586.9646 C314.848953,1595.88345 302.345315,1598.25 276.016868,1598.25 L221.983432,1598.25 C195.654985,1598.25 183.151291,1595.88345 174.273077,1586.96463 C165.366772,1578.0176 163,1565.39822 163,1538.9019 L163,1495.3481 C163,1468.85178 165.366772,1456.2324 174.273077,1447.28537 C183.151291,1438.36655 195.654985,1436 221.983432,1436 L221.983432,1436 Z" id="Shape" sketch:type="MSShapeGroup"></path>
856+ </g>
857+ </g>
858+</svg>
859\ No newline at end of file
860
861=== modified file 'qml/Shell.qml'
862--- qml/Shell.qml 2016-01-28 18:25:14 +0000
863+++ qml/Shell.qml 2016-02-02 22:18:26 +0000
864@@ -25,6 +25,7 @@
865 import Unity.Connectivity 0.1
866 import Unity.Launcher 0.1
867 import GlobalShortcut 1.0 // has to be before Utils, because of WindowKeysFilter
868+import GSettings 1.0
869 import Utils 0.1
870 import Powerd 0.1
871 import SessionBroadcast 0.1
872@@ -187,6 +188,11 @@
873 }
874 }
875
876+ GSettings {
877+ id: settings
878+ schema.id: "com.canonical.Unity8"
879+ }
880+
881 Item {
882 id: stages
883 objectName: "stages"
884@@ -343,6 +349,11 @@
885 property: "altTabPressed"
886 value: physicalKeysMapper.altTabPressed
887 }
888+ Binding {
889+ target: applicationsDisplayLoader.item
890+ property: "leftMargin"
891+ value: launcher.lockedVisible ? launcher.panelWidth: 0
892+ }
893 }
894
895 Tutorial {
896@@ -373,7 +384,11 @@
897 InputMethod {
898 id: inputMethod
899 objectName: "inputMethod"
900- anchors { fill: parent; topMargin: panel.panelHeight }
901+ anchors {
902+ fill: parent
903+ topMargin: panel.panelHeight
904+ leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
905+ }
906 z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
907 }
908
909@@ -557,6 +572,10 @@
910 && !greeter.hasLockedApp
911 inverted: shell.usageScenario !== "desktop"
912 shadeBackground: !tutorial.running
913+ superPressed: physicalKeysMapper.superPressed
914+ superTabPressed: physicalKeysMapper.superTabPressed
915+ panelWidth: units.gu(settings.launcherWidth)
916+ lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
917
918 onShowDashHome: showHome()
919 onDash: showDash()
920@@ -576,6 +595,37 @@
921 panel.indicators.hide()
922 }
923 }
924+ onFocusChanged: {
925+ if (!focus) {
926+ applicationsDisplayLoader.focus = true;
927+ }
928+ }
929+
930+ GlobalShortcut {
931+ shortcut: Qt.AltModifier | Qt.Key_F1
932+ onTriggered: {
933+ launcher.openForKeyboardNavigation();
934+ }
935+ }
936+ GlobalShortcut {
937+ shortcut: Qt.MetaModifier | Qt.Key_0
938+ onTriggered: {
939+ if (LauncherModel.get(9)) {
940+ activateApplication(LauncherModel.get(9).appId);
941+ }
942+ }
943+ }
944+ Repeater {
945+ model: 9
946+ GlobalShortcut {
947+ shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
948+ onTriggered: {
949+ if (LauncherModel.get(index)) {
950+ activateApplication(LauncherModel.get(index).appId);
951+ }
952+ }
953+ }
954+ }
955 }
956
957 Wizard {
958
959=== modified file 'qml/Stages/AbstractStage.qml'
960--- qml/Stages/AbstractStage.qml 2016-01-14 13:03:20 +0000
961+++ qml/Stages/AbstractStage.qml 2016-02-02 22:18:26 +0000
962@@ -39,6 +39,8 @@
963 property int shellOrientationAngle
964 property bool spreadEnabled: true // If false, animations and right edge will be disabled
965 property bool suspended
966+ // A Stage should paint a wallpaper etc over its full size but not use the margins for window placement
967+ property int leftMargin: 0
968
969 // To be read from outside
970 property var mainApp: null
971
972=== modified file 'qml/Stages/DesktopStage.qml'
973--- qml/Stages/DesktopStage.qml 2016-01-14 13:03:20 +0000
974+++ qml/Stages/DesktopStage.qml 2016-02-02 22:18:26 +0000
975@@ -224,11 +224,9 @@
976 PanelState.dropShadow = false;
977 }
978
979- FocusScope {
980- id: appContainer
981- objectName: "appContainer"
982+ Item {
983+ id: stageContainer
984 anchors.fill: parent
985- focus: spread.state !== "altTab"
986
987 CrossFadeImage {
988 id: wallpaper
989@@ -238,230 +236,238 @@
990 fillMode: Image.PreserveAspectCrop
991 }
992
993- Repeater {
994- id: appRepeater
995- model: ApplicationManager
996- objectName: "appRepeater"
997-
998- delegate: FocusScope {
999- id: appDelegate
1000- objectName: "appDelegate_" + appId
1001- // z might be overriden in some cases by effects, but we need z ordering
1002- // to calculate occlusion detection
1003- property int normalZ: ApplicationManager.count - index
1004- z: normalZ
1005- y: PanelState.panelHeight
1006- focus: appId === priv.focusedAppId
1007- width: decoratedWindow.width
1008- height: decoratedWindow.height
1009- property alias requestedWidth: decoratedWindow.requestedWidth
1010- property alias requestedHeight: decoratedWindow.requestedHeight
1011-
1012- QtObject {
1013- id: appDelegatePrivate
1014- property bool maximized: false
1015- property bool maximizedLeft: false
1016- property bool maximizedRight: false
1017- property bool minimized: false
1018- }
1019- readonly property alias maximized: appDelegatePrivate.maximized
1020- readonly property alias maximizedLeft: appDelegatePrivate.maximizedLeft
1021- readonly property alias maximizedRight: appDelegatePrivate.maximizedRight
1022- readonly property alias minimized: appDelegatePrivate.minimized
1023-
1024- readonly property string appId: model.appId
1025- property bool animationsEnabled: true
1026- property alias title: decoratedWindow.title
1027- readonly property string appName: model.name
1028- property bool visuallyMaximized: false
1029- property bool visuallyMinimized: false
1030-
1031- onFocusChanged: {
1032- if (focus && ApplicationManager.focusedApplicationId !== appId) {
1033+ FocusScope {
1034+ id: appContainer
1035+ objectName: "appContainer"
1036+ anchors.fill: parent
1037+ anchors.leftMargin: root.leftMargin
1038+ focus: spread.state !== "altTab"
1039+
1040+ Repeater {
1041+ id: appRepeater
1042+ model: ApplicationManager
1043+ objectName: "appRepeater"
1044+
1045+ delegate: FocusScope {
1046+ id: appDelegate
1047+ objectName: "appDelegate_" + appId
1048+ // z might be overriden in some cases by effects, but we need z ordering
1049+ // to calculate occlusion detection
1050+ property int normalZ: ApplicationManager.count - index
1051+ z: normalZ
1052+ y: PanelState.panelHeight
1053+ focus: appId === priv.focusedAppId
1054+ width: decoratedWindow.width
1055+ height: decoratedWindow.height
1056+ property alias requestedWidth: decoratedWindow.requestedWidth
1057+ property alias requestedHeight: decoratedWindow.requestedHeight
1058+
1059+ QtObject {
1060+ id: appDelegatePrivate
1061+ property bool maximized: false
1062+ property bool maximizedLeft: false
1063+ property bool maximizedRight: false
1064+ property bool minimized: false
1065+ }
1066+ readonly property alias maximized: appDelegatePrivate.maximized
1067+ readonly property alias maximizedLeft: appDelegatePrivate.maximizedLeft
1068+ readonly property alias maximizedRight: appDelegatePrivate.maximizedRight
1069+ readonly property alias minimized: appDelegatePrivate.minimized
1070+
1071+ readonly property string appId: model.appId
1072+ property bool animationsEnabled: true
1073+ property alias title: decoratedWindow.title
1074+ readonly property string appName: model.name
1075+ property bool visuallyMaximized: false
1076+ property bool visuallyMinimized: false
1077+
1078+ onFocusChanged: {
1079+ if (focus && ApplicationManager.focusedApplicationId !== appId) {
1080+ ApplicationManager.focusApplication(appId);
1081+ }
1082+ }
1083+
1084+ onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
1085+
1086+ visible: !visuallyMinimized &&
1087+ !greeter.fullyShown &&
1088+ (priv.foregroundMaximizedAppZ === -1 || priv.foregroundMaximizedAppZ <= z) ||
1089+ (spread.state == "altTab" && index === spread.highlightedIndex)
1090+
1091+ Binding {
1092+ target: ApplicationManager.get(index)
1093+ property: "requestedState"
1094+ // TODO: figure out some lifecycle policy, like suspending minimized apps
1095+ // if running on a tablet or something.
1096+ // TODO: If the device has a dozen suspended apps because it was running
1097+ // in staged mode, when it switches to Windowed mode it will suddenly
1098+ // resume all those apps at once. We might want to avoid that.
1099+ value: ApplicationInfoInterface.RequestedRunning // Always running for now
1100+ }
1101+
1102+ function maximize(animated) {
1103+ animationsEnabled = (animated === undefined) || animated;
1104+ appDelegatePrivate.minimized = false;
1105+ appDelegatePrivate.maximized = true;
1106+ appDelegatePrivate.maximizedLeft = false;
1107+ appDelegatePrivate.maximizedRight = false;
1108+ }
1109+ function maximizeLeft() {
1110+ appDelegatePrivate.minimized = false;
1111+ appDelegatePrivate.maximized = false;
1112+ appDelegatePrivate.maximizedLeft = true;
1113+ appDelegatePrivate.maximizedRight = false;
1114+ }
1115+ function maximizeRight() {
1116+ appDelegatePrivate.minimized = false;
1117+ appDelegatePrivate.maximized = false;
1118+ appDelegatePrivate.maximizedLeft = false;
1119+ appDelegatePrivate.maximizedRight = true;
1120+ }
1121+ function minimize(animated) {
1122+ animationsEnabled = (animated === undefined) || animated;
1123+ appDelegatePrivate.minimized = true;
1124+ }
1125+ function restoreFromMaximized(animated) {
1126+ animationsEnabled = (animated === undefined) || animated;
1127+ appDelegatePrivate.minimized = false;
1128+ appDelegatePrivate.maximized = false;
1129+ appDelegatePrivate.maximizedLeft = false;
1130+ appDelegatePrivate.maximizedRight = false;
1131+ }
1132+ function restore(animated) {
1133+ animationsEnabled = (animated === undefined) || animated;
1134+ appDelegatePrivate.minimized = false;
1135+ if (maximized)
1136+ maximize();
1137+ else if (maximizedLeft)
1138+ maximizeLeft();
1139+ else if (maximizedRight)
1140+ maximizeRight();
1141 ApplicationManager.focusApplication(appId);
1142 }
1143- }
1144-
1145- onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
1146-
1147- visible: !visuallyMinimized &&
1148- !greeter.fullyShown &&
1149- (priv.foregroundMaximizedAppZ === -1 || priv.foregroundMaximizedAppZ <= z) ||
1150- (spread.state == "altTab" && index === spread.highlightedIndex)
1151-
1152- Binding {
1153- target: ApplicationManager.get(index)
1154- property: "requestedState"
1155- // TODO: figure out some lifecycle policy, like suspending minimized apps
1156- // if running on a tablet or something.
1157- // TODO: If the device has a dozen suspended apps because it was running
1158- // in staged mode, when it switches to Windowed mode it will suddenly
1159- // resume all those apps at once. We might want to avoid that.
1160- value: ApplicationInfoInterface.RequestedRunning // Always running for now
1161- }
1162-
1163- function maximize(animated) {
1164- animationsEnabled = (animated === undefined) || animated;
1165- appDelegatePrivate.minimized = false;
1166- appDelegatePrivate.maximized = true;
1167- appDelegatePrivate.maximizedLeft = false;
1168- appDelegatePrivate.maximizedRight = false;
1169- }
1170- function maximizeLeft() {
1171- appDelegatePrivate.minimized = false;
1172- appDelegatePrivate.maximized = false;
1173- appDelegatePrivate.maximizedLeft = true;
1174- appDelegatePrivate.maximizedRight = false;
1175- }
1176- function maximizeRight() {
1177- appDelegatePrivate.minimized = false;
1178- appDelegatePrivate.maximized = false;
1179- appDelegatePrivate.maximizedLeft = false;
1180- appDelegatePrivate.maximizedRight = true;
1181- }
1182- function minimize(animated) {
1183- animationsEnabled = (animated === undefined) || animated;
1184- appDelegatePrivate.minimized = true;
1185- }
1186- function restoreFromMaximized(animated) {
1187- animationsEnabled = (animated === undefined) || animated;
1188- appDelegatePrivate.minimized = false;
1189- appDelegatePrivate.maximized = false;
1190- appDelegatePrivate.maximizedLeft = false;
1191- appDelegatePrivate.maximizedRight = false;
1192- }
1193- function restore(animated) {
1194- animationsEnabled = (animated === undefined) || animated;
1195- appDelegatePrivate.minimized = false;
1196- if (maximized)
1197- maximize();
1198- else if (maximizedLeft)
1199- maximizeLeft();
1200- else if (maximizedRight)
1201- maximizeRight();
1202- ApplicationManager.focusApplication(appId);
1203- }
1204-
1205- states: [
1206- State {
1207- name: "fullscreen"; when: decoratedWindow.fullscreen
1208- extend: "maximized"
1209- PropertyChanges {
1210- target: appDelegate;
1211- y: -PanelState.panelHeight
1212- }
1213- },
1214- State {
1215- name: "normal";
1216- when: !appDelegate.maximized && !appDelegate.minimized
1217- && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
1218- PropertyChanges {
1219- target: appDelegate;
1220- visuallyMinimized: false;
1221- visuallyMaximized: false
1222- }
1223- },
1224- State {
1225- name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1226- PropertyChanges {
1227- target: appDelegate;
1228- x: 0; y: 0;
1229- requestedWidth: root.width; requestedHeight: root.height;
1230- visuallyMinimized: false;
1231- visuallyMaximized: true
1232- }
1233- },
1234- State {
1235- name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
1236- PropertyChanges { target: appDelegate; x: 0; y: PanelState.panelHeight;
1237- requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
1238- },
1239- State {
1240- name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
1241- PropertyChanges { target: appDelegate; x: root.width/2; y: PanelState.panelHeight;
1242- requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
1243- },
1244- State {
1245- name: "minimized"; when: appDelegate.minimized
1246- PropertyChanges {
1247- target: appDelegate;
1248- x: -appDelegate.width / 2;
1249- scale: units.gu(5) / appDelegate.width;
1250- opacity: 0
1251- visuallyMinimized: true;
1252- visuallyMaximized: false
1253- }
1254- }
1255- ]
1256- transitions: [
1257- Transition {
1258- to: "normal"
1259- enabled: appDelegate.animationsEnabled
1260- PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1261- UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
1262- },
1263- Transition {
1264- to: "minimized"
1265- enabled: appDelegate.animationsEnabled
1266- PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1267- SequentialAnimation {
1268+
1269+ states: [
1270+ State {
1271+ name: "fullscreen"; when: decoratedWindow.fullscreen
1272+ extend: "maximized"
1273+ PropertyChanges {
1274+ target: appDelegate;
1275+ y: -PanelState.panelHeight
1276+ }
1277+ },
1278+ State {
1279+ name: "normal";
1280+ when: !appDelegate.maximized && !appDelegate.minimized
1281+ && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
1282+ PropertyChanges {
1283+ target: appDelegate;
1284+ visuallyMinimized: false;
1285+ visuallyMaximized: false
1286+ }
1287+ },
1288+ State {
1289+ name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1290+ PropertyChanges {
1291+ target: appDelegate;
1292+ x: 0; y: 0;
1293+ requestedWidth: appContainer.width; requestedHeight: appContainer.height;
1294+ visuallyMinimized: false;
1295+ visuallyMaximized: true
1296+ }
1297+ },
1298+ State {
1299+ name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
1300+ PropertyChanges { target: appDelegate; x: 0; y: PanelState.panelHeight;
1301+ requestedWidth: appContainer.width/2; requestedHeight: appContainer.height - PanelState.panelHeight }
1302+ },
1303+ State {
1304+ name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
1305+ PropertyChanges { target: appDelegate; x: appContainer.width/2; y: PanelState.panelHeight;
1306+ requestedWidth: appContainer.width/2; requestedHeight: appContainer.height - PanelState.panelHeight }
1307+ },
1308+ State {
1309+ name: "minimized"; when: appDelegate.minimized
1310+ PropertyChanges {
1311+ target: appDelegate;
1312+ x: -appDelegate.width / 2;
1313+ scale: units.gu(5) / appDelegate.width;
1314+ opacity: 0
1315+ visuallyMinimized: true;
1316+ visuallyMaximized: false
1317+ }
1318+ }
1319+ ]
1320+ transitions: [
1321+ Transition {
1322+ to: "normal"
1323+ enabled: appDelegate.animationsEnabled
1324+ PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1325 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
1326- PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1327- ScriptAction {
1328- script: {
1329- if (appDelegate.minimized) {
1330- priv.focusNext();
1331+ },
1332+ Transition {
1333+ to: "minimized"
1334+ enabled: appDelegate.animationsEnabled
1335+ PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1336+ SequentialAnimation {
1337+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
1338+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1339+ ScriptAction {
1340+ script: {
1341+ if (appDelegate.minimized) {
1342+ priv.focusNext();
1343+ }
1344 }
1345 }
1346 }
1347- }
1348- },
1349- Transition {
1350- to: "*" //maximized and fullscreen
1351- enabled: appDelegate.animationsEnabled
1352- PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1353- SequentialAnimation {
1354- UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
1355- PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1356- }
1357- }
1358- ]
1359-
1360- Binding {
1361- id: previewBinding
1362- target: appDelegate
1363- property: "z"
1364- value: ApplicationManager.count + 1
1365- when: index == spread.highlightedIndex && blurLayer.ready
1366- }
1367-
1368- WindowResizeArea {
1369- objectName: "windowResizeArea"
1370- target: appDelegate
1371- minWidth: units.gu(10)
1372- minHeight: units.gu(10)
1373- borderThickness: units.gu(2)
1374- windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
1375- screenWidth: root.width
1376- screenHeight: root.height
1377-
1378- onPressed: { ApplicationManager.focusApplication(model.appId) }
1379- }
1380-
1381- DecoratedWindow {
1382- id: decoratedWindow
1383- objectName: "decoratedWindow"
1384- anchors.left: appDelegate.left
1385- anchors.top: appDelegate.top
1386- application: ApplicationManager.get(index)
1387- active: ApplicationManager.focusedApplicationId === model.appId
1388- focus: true
1389-
1390- onClose: ApplicationManager.stopApplication(model.appId)
1391- onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
1392- ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
1393- onMinimize: appDelegate.minimize()
1394- onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
1395+ },
1396+ Transition {
1397+ to: "*" //maximized and fullscreen
1398+ enabled: appDelegate.animationsEnabled
1399+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1400+ SequentialAnimation {
1401+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
1402+ PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1403+ }
1404+ }
1405+ ]
1406+
1407+ Binding {
1408+ id: previewBinding
1409+ target: appDelegate
1410+ property: "z"
1411+ value: ApplicationManager.count + 1
1412+ when: index == spread.highlightedIndex && blurLayer.ready
1413+ }
1414+
1415+ WindowResizeArea {
1416+ objectName: "windowResizeArea"
1417+ target: appDelegate
1418+ minWidth: units.gu(10)
1419+ minHeight: units.gu(10)
1420+ borderThickness: units.gu(2)
1421+ windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
1422+ screenWidth: appContainer.width
1423+ screenHeight: appContainer.height
1424+
1425+ onPressed: { ApplicationManager.focusApplication(model.appId) }
1426+ }
1427+
1428+ DecoratedWindow {
1429+ id: decoratedWindow
1430+ objectName: "decoratedWindow"
1431+ anchors.left: appDelegate.left
1432+ anchors.top: appDelegate.top
1433+ application: ApplicationManager.get(index)
1434+ active: ApplicationManager.focusedApplicationId === model.appId
1435+ focus: true
1436+
1437+ onClose: ApplicationManager.stopApplication(model.appId)
1438+ onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
1439+ ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
1440+ onMinimize: appDelegate.minimize()
1441+ onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
1442+ }
1443 }
1444 }
1445 }
1446@@ -469,8 +475,8 @@
1447
1448 BlurLayer {
1449 id: blurLayer
1450- anchors.fill: parent
1451- source: appContainer
1452+ anchors.fill: stageContainer
1453+ source: stageContainer
1454 visible: false
1455 }
1456
1457@@ -521,7 +527,7 @@
1458 DesktopSpread {
1459 id: spread
1460 objectName: "spread"
1461- anchors.fill: parent
1462+ anchors.fill: stageContainer
1463 workspace: appContainer
1464 focus: state == "altTab"
1465 altTabPressed: root.altTabPressed
1466
1467=== modified file 'tests/mocks/GSettings.1.0/fake_gsettings.cpp'
1468--- tests/mocks/GSettings.1.0/fake_gsettings.cpp 2015-09-29 20:19:56 +0000
1469+++ tests/mocks/GSettings.1.0/fake_gsettings.cpp 2016-02-02 22:18:26 +0000
1470@@ -22,6 +22,8 @@
1471
1472 GSettingsControllerQml::GSettingsControllerQml()
1473 : m_usageMode("Staged")
1474+ , m_autohideLauncher(false)
1475+ , m_launcherWidth(8)
1476 {
1477 }
1478
1479@@ -88,6 +90,32 @@
1480 }
1481 }
1482
1483+bool GSettingsControllerQml::autohideLauncher() const
1484+{
1485+ return m_autohideLauncher;
1486+}
1487+
1488+void GSettingsControllerQml::setAutohideLauncher(bool autohideLauncher)
1489+{
1490+ if (m_autohideLauncher != autohideLauncher) {
1491+ m_autohideLauncher = autohideLauncher;
1492+ Q_EMIT autohideLauncherChanged(autohideLauncher);
1493+ }
1494+}
1495+
1496+int GSettingsControllerQml::launcherWidth() const
1497+{
1498+ return m_launcherWidth;
1499+}
1500+
1501+void GSettingsControllerQml::setLauncherWidth(int launcherWidth)
1502+{
1503+ if (m_launcherWidth != launcherWidth) {
1504+ m_launcherWidth = launcherWidth;
1505+ Q_EMIT launcherWidthChanged(launcherWidth);
1506+ }
1507+}
1508+
1509 GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
1510 }
1511
1512@@ -129,6 +157,10 @@
1513 this, &GSettingsQml::lockedOutTimeChanged);
1514 connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::lifecycleExemptAppidsChanged,
1515 this, &GSettingsQml::lifecycleExemptAppidsChanged);
1516+ connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::autohideLauncherChanged,
1517+ this, &GSettingsQml::autohideLauncherChanged);
1518+ connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::launcherWidthChanged,
1519+ this, &GSettingsQml::launcherWidthChanged);
1520 }
1521
1522 GSettingsSchemaQml * GSettingsQml::schema() const {
1523@@ -192,9 +224,41 @@
1524 }
1525 }
1526
1527+bool GSettingsQml::autohideLauncher() const
1528+{
1529+ if (m_schema->id() == "com.canonical.Unity8") {
1530+ return GSettingsControllerQml::instance()->autohideLauncher();
1531+ } else {
1532+ return false;
1533+ }
1534+}
1535+
1536+int GSettingsQml::launcherWidth() const
1537+{
1538+ if (m_schema->id() == "com.canonical.Unity8") {
1539+ return GSettingsControllerQml::instance()->launcherWidth();
1540+ } else {
1541+ return false;
1542+ }
1543+}
1544+
1545 void GSettingsQml::setLifecycleExemptAppids(const QStringList &appIds)
1546 {
1547 if (m_schema->id() == "com.canonical.qtmir") {
1548 GSettingsControllerQml::instance()->setLifecycleExemptAppids(appIds);
1549 }
1550 }
1551+
1552+void GSettingsQml::setAutohideLauncher(bool autohideLauncher)
1553+{
1554+ if (m_schema->id() == "com.canonical.Unity8") {
1555+ GSettingsControllerQml::instance()->setAutohideLauncher(autohideLauncher);
1556+ }
1557+}
1558+
1559+void GSettingsQml::setLauncherWidth(int launcherWidth)
1560+{
1561+ if (m_schema->id() == "com.canonical.Unity8") {
1562+ GSettingsControllerQml::instance()->setLauncherWidth(launcherWidth);
1563+ }
1564+}
1565
1566=== modified file 'tests/mocks/GSettings.1.0/fake_gsettings.h'
1567--- tests/mocks/GSettings.1.0/fake_gsettings.h 2015-09-29 20:19:56 +0000
1568+++ tests/mocks/GSettings.1.0/fake_gsettings.h 2016-02-02 22:18:26 +0000
1569@@ -50,6 +50,8 @@
1570 Q_PROPERTY(QString usageMode READ usageMode WRITE setUsageMode NOTIFY usageModeChanged)
1571 Q_PROPERTY(qint64 lockedOutTime READ lockedOutTime WRITE setLockedOutTime NOTIFY lockedOutTimeChanged)
1572 Q_PROPERTY(QStringList lifecycleExemptAppids READ lifecycleExemptAppids WRITE setLifecycleExemptAppids NOTIFY lifecycleExemptAppidsChanged)
1573+ Q_PROPERTY(bool autohideLauncher READ autohideLauncher WRITE setAutohideLauncher NOTIFY autohideLauncherChanged)
1574+ Q_PROPERTY(int launcherWidth READ launcherWidth WRITE setLauncherWidth NOTIFY launcherWidthChanged)
1575
1576 public:
1577 GSettingsQml(QObject *parent = nullptr);
1578@@ -59,11 +61,15 @@
1579 QString usageMode() const;
1580 qint64 lockedOutTime() const;
1581 QStringList lifecycleExemptAppids() const;
1582+ bool autohideLauncher() const;
1583+ int launcherWidth() const;
1584
1585 void setPictureUri(const QString &str);
1586 void setUsageMode(const QString &usageMode);
1587 void setLockedOutTime(qint64 timestamp);
1588 void setLifecycleExemptAppids(const QStringList &appIds);
1589+ void setAutohideLauncher(bool autohideLauncher);
1590+ void setLauncherWidth(int launcherWidth);
1591
1592 Q_SIGNALS:
1593 void schemaChanged();
1594@@ -71,6 +77,8 @@
1595 void usageModeChanged(const QString&);
1596 void lockedOutTimeChanged(qint64);
1597 void lifecycleExemptAppidsChanged(const QStringList &);
1598+ void autohideLauncherChanged(bool);
1599+ void launcherWidthChanged(int launcherWidth);
1600
1601 private:
1602 GSettingsSchemaQml* m_schema;
1603@@ -98,11 +106,19 @@
1604 QStringList lifecycleExemptAppids() const;
1605 Q_INVOKABLE void setLifecycleExemptAppids(const QStringList &appIds);
1606
1607+ bool autohideLauncher() const;
1608+ Q_INVOKABLE void setAutohideLauncher(bool autohideLauncher);
1609+
1610+ int launcherWidth() const;
1611+ Q_INVOKABLE void setLauncherWidth(int launcherWidth);
1612+
1613 Q_SIGNALS:
1614 void pictureUriChanged(const QString&);
1615 void usageModeChanged(const QString&);
1616 void lockedOutTimeChanged(qint64 timestamp);
1617 void lifecycleExemptAppidsChanged(const QStringList&);
1618+ void autohideLauncherChanged(bool autohideLauncher);
1619+ void launcherWidthChanged(int launcherWidth);
1620
1621 private:
1622 GSettingsControllerQml();
1623@@ -111,6 +127,8 @@
1624 QString m_usageMode;
1625 qint64 m_lockedOutTime;
1626 QStringList m_lifecycleExemptAppids;
1627+ bool m_autohideLauncher;
1628+ int m_launcherWidth;
1629
1630 static GSettingsControllerQml* s_controllerInstance;
1631 QList<GSettingsQml *> m_registeredGSettings;
1632
1633=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp'
1634--- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2015-11-30 12:18:40 +0000
1635+++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2016-02-02 22:18:26 +0000
1636@@ -37,6 +37,8 @@
1637 , m_surfaceHeight(0)
1638 , m_touchPressCount(0)
1639 , m_touchReleaseCount(0)
1640+ , m_mousePressCount(0)
1641+ , m_mouseReleaseCount(0)
1642 {
1643 // qDebug() << "MirSurfaceItem::MirSurfaceItem() " << (void*)(this) << name();
1644 setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
1645@@ -165,6 +167,8 @@
1646
1647 void MirSurfaceItem::mousePressEvent(QMouseEvent * event)
1648 {
1649+ m_mousePressCount++;
1650+ Q_EMIT mousePressCountChanged(m_mousePressCount);
1651 event->accept();
1652 }
1653
1654@@ -175,6 +179,8 @@
1655
1656 void MirSurfaceItem::mouseReleaseEvent(QMouseEvent * event)
1657 {
1658+ m_mouseReleaseCount++;
1659+ Q_EMIT mouseReleaseCountChanged(m_mouseReleaseCount);
1660 event->accept();
1661 }
1662
1663
1664=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h'
1665--- tests/mocks/Unity/Application/MirSurfaceItem.h 2015-12-01 10:35:15 +0000
1666+++ tests/mocks/Unity/Application/MirSurfaceItem.h 2016-02-02 22:18:26 +0000
1667@@ -36,6 +36,10 @@
1668 Q_PROPERTY(int touchReleaseCount READ touchReleaseCount WRITE setTouchReleaseCount
1669 NOTIFY touchReleaseCountChanged DESIGNABLE false)
1670
1671+ Q_PROPERTY(int mousePressCount READ mousePressCount WRITE setMousePressCount
1672+ NOTIFY mousePressCountChanged)
1673+ Q_PROPERTY(int mouseReleaseCount READ mouseReleaseCount WRITE setMouseReleaseCount
1674+ NOTIFY mouseReleaseCountChanged)
1675 public:
1676 explicit MirSurfaceItem(QQuickItem *parent = 0);
1677 ~MirSurfaceItem();
1678@@ -76,9 +80,17 @@
1679 int touchReleaseCount() const { return m_touchReleaseCount; }
1680 void setTouchReleaseCount(int count) { m_touchReleaseCount = count; Q_EMIT touchReleaseCountChanged(count); }
1681
1682+ int mousePressCount() const { return m_mousePressCount; }
1683+ void setMousePressCount(int count) { m_mousePressCount = count; Q_EMIT mousePressCountChanged(count); }
1684+
1685+ int mouseReleaseCount() const { return m_mouseReleaseCount; }
1686+ void setMouseReleaseCount(int count) { m_mouseReleaseCount = count; Q_EMIT mouseReleaseCountChanged(count); }
1687+
1688 Q_SIGNALS:
1689 void touchPressCountChanged(int count);
1690 void touchReleaseCountChanged(int count);
1691+ void mousePressCountChanged(int count);
1692+ void mouseReleaseCountChanged(int count);
1693
1694 protected:
1695 void touchEvent(QTouchEvent * event) override;
1696@@ -109,6 +121,8 @@
1697
1698 int m_touchPressCount;
1699 int m_touchReleaseCount;
1700+ int m_mousePressCount;
1701+ int m_mouseReleaseCount;
1702
1703 FillMode m_fillMode{Stretch};
1704
1705
1706=== modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp'
1707--- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-11-04 11:29:16 +0000
1708+++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2016-02-02 22:18:26 +0000
1709@@ -25,6 +25,7 @@
1710 MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
1711 item->setProgress(0);
1712 item->setPinned(true);
1713+ item->setRunning(true);
1714 item->setFocused(true);
1715 m_list.append(item);
1716 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
1717@@ -34,6 +35,7 @@
1718 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
1719 item->setProgress(50);
1720 item->setCountVisible(true);
1721+ item->setRunning(true);
1722 item->setAlerting(false);
1723 m_list.append(item);
1724 item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
1725
1726=== modified file 'tests/qmltests/Launcher/tst_Launcher.qml'
1727--- tests/qmltests/Launcher/tst_Launcher.qml 2016-01-19 15:36:15 +0000
1728+++ tests/qmltests/Launcher/tst_Launcher.qml 2016-02-02 22:18:26 +0000
1729@@ -28,12 +28,13 @@
1730 launcher. */
1731 Item {
1732 id: root
1733- width: units.gu(50)
1734- height: units.gu(55)
1735+ width: units.gu(140)
1736+ height: units.gu(70)
1737
1738 Loader {
1739 id: launcherLoader
1740 anchors.fill: parent
1741+ focus: true
1742 property bool itemDestroyed: false
1743 sourceComponent: Component {
1744 Launcher {
1745@@ -68,6 +69,7 @@
1746
1747 Component.onCompleted: {
1748 launcherLoader.itemDestroyed = false;
1749+ launcherLoader.focus = true
1750 edgeBarrierControls.target = testCase.findChild(this, "edgeBarrierController");
1751 }
1752 Component.onDestruction: {
1753@@ -77,11 +79,40 @@
1754 }
1755 }
1756
1757+ Binding {
1758+ target: launcherLoader.item
1759+ property: "lockedVisible"
1760+ value: lockedVisibleCheckBox.checked
1761+ }
1762+ Binding {
1763+ target: launcherLoader.item
1764+ property: "panelWidth"
1765+ value: units.gu(Math.round(widthSlider.value))
1766+ }
1767+
1768 ColumnLayout {
1769 anchors { bottom: parent.bottom; right: parent.right; margins: units.gu(1) }
1770 spacing: units.gu(1)
1771 width: childrenRect.width
1772
1773+ RowLayout {
1774+ CheckBox {
1775+ id: lockedVisibleCheckBox
1776+ checked: false
1777+ }
1778+ Label {
1779+ text: "Launcher always visible"
1780+ }
1781+ }
1782+
1783+ Slider {
1784+ id: widthSlider
1785+ Layout.fillWidth: true
1786+ minimumValue: 6
1787+ maximumValue: 12
1788+ value: 10
1789+ }
1790+
1791 MouseTouchEmulationCheckbox {}
1792
1793 EdgeBarrierControls {
1794@@ -102,6 +133,15 @@
1795 Layout.fillWidth: true
1796 }
1797
1798+ Button {
1799+ text: "open for kbd navigation"
1800+ onClicked: {
1801+ launcherLoader.item.openForKeyboardNavigation()
1802+ launcherLoader.item.forceActiveFocus();// = true
1803+ }
1804+ Layout.fillWidth: true
1805+ }
1806+
1807 Row {
1808 spacing: units.gu(1)
1809
1810@@ -206,10 +246,6 @@
1811 // growing while populating it with icons etc.
1812 tryCompare(listView, "flicking", false);
1813
1814- // Make sure noone changed the height of the window. The issue this test case
1815- // is verifying only happens on certain heights of the Launcher
1816- compare(root.height, units.gu(55));
1817-
1818 compare(listView.contentY, -listView.topMargin, "Launcher did not start up with first item unfolded");
1819
1820 // Now do check that snapping is in fact enabled
1821@@ -266,13 +302,32 @@
1822
1823 function positionLauncherListAtBeginning() {
1824 var listView = testCase.findChild(launcherLoader.item, "launcherListView");
1825- listView.contentY = -listView.topMargin;
1826+ var moveAnimation = findInvisibleChild(listView, "moveAnimation")
1827+
1828+ listView.moveToIndex(0);
1829+
1830+ waitForRendering(listView);
1831+ tryCompare(moveAnimation, "running", false);
1832 }
1833 function positionLauncherListAtEnd() {
1834 var listView = testCase.findChild(launcherLoader.item, "launcherListView");
1835- if ((listView.contentHeight + listView.topMargin + listView.bottomMargin) > listView.height) {
1836- listView.contentY = listView.topMargin + listView.contentHeight
1837- - listView.height;
1838+ var moveAnimation = findInvisibleChild(listView, "moveAnimation")
1839+
1840+ listView.moveToIndex(listView.count -1);
1841+
1842+ waitForRendering(listView);
1843+ tryCompare(moveAnimation, "running", false);
1844+ }
1845+
1846+ function assertFocusOnIndex(index) {
1847+ var launcherListView = findChild(launcher, "launcherListView");
1848+ var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
1849+
1850+ waitForRendering(launcher);
1851+ compare(bfbFocusHighlight.visible, index === -1);
1852+ for (var i = 0; i < launcherListView.count; i++) {
1853+ var focusRing = findChild(findChild(launcher, "launcherDelegate" + i), "focusRing")
1854+ compare(focusRing.visible, index === i);
1855 }
1856 }
1857
1858@@ -290,10 +345,10 @@
1859 dragLauncherIntoView()
1860
1861 // tapping on the center of the screen should dismiss the launcher
1862- mouseClick(launcher)
1863+ mouseClick(launcher, panel.width + units.gu(5), launcher.height / 2)
1864
1865 // should eventually get fully retracted (hidden)
1866- tryCompare(panel, "x", -launcher.panelWidth, 1000)
1867+ tryCompare(panel, "x", -launcher.panelWidth, 2000)
1868 }
1869
1870 /* If I click on the icon of an application on the launcher
1871@@ -377,6 +432,7 @@
1872 wait(100)
1873 compare(launcher.maxPanelX, -launcher.panelWidth, "Launcher moved even if it shouldn't")
1874 }
1875+
1876 waitUntilLauncherDisappears();
1877 launcher.available = true;
1878 }
1879@@ -400,6 +456,8 @@
1880 dragLauncherIntoView();
1881 var launcherListView = findChild(launcher, "launcherListView");
1882 for (var i = 0; i < launcherListView.count; ++i) {
1883+ launcherListView.moveToIndex(i);
1884+ waitForRendering(launcherListView);
1885 var delegate = findChild(launcherListView, "launcherDelegate" + i)
1886 compare(findChild(delegate, "countEmblem").visible, LauncherModel.get(i).countVisible)
1887 // Intentionally allow type coercion (string/number)
1888@@ -421,7 +479,7 @@
1889 var launcherListView = findChild(launcher, "launcherListView");
1890 for (var i = 0; i < launcherListView.count; ++i) {
1891 var delegate = findChild(launcherListView, "launcherDelegate" + i)
1892- compare(findChild(delegate, "runningHighlight").visible, LauncherModel.get(i).running)
1893+ compare(findChild(delegate, "runningHighlight0").visible, LauncherModel.get(i).running)
1894 }
1895 }
1896
1897@@ -460,6 +518,7 @@
1898 launcher.lastSelectedApplication = "";
1899 dragLauncherIntoView();
1900 var listView = findChild(launcher, "launcherListView");
1901+ var moveAnimation = findInvisibleChild(listView, "moveAnimation")
1902
1903 // flicking is unreliable. sometimes it works, sometimes the
1904 // list view moves just a tiny bit or not at all, making tests fail.
1905@@ -470,12 +529,14 @@
1906 } else {
1907 positionLauncherListAtEnd();
1908 }
1909- tryCompare(listView, "flicking", false);
1910-
1911 var oldY = listView.contentY;
1912
1913 mouseClick(listView, listView.width / 2, data.clickY);
1914- tryCompare(listView, "flicking", false);
1915+
1916+ if (data.expectFlick) {
1917+ tryCompare(moveAnimation, "running", true);
1918+ }
1919+ tryCompare(moveAnimation, "running", false);
1920
1921 if (data.expectFlick) {
1922 verify(listView.contentY != oldY);
1923@@ -764,14 +825,15 @@
1924 function test_launcher_dismiss() {
1925 dragLauncherIntoView();
1926 verify(launcher.state == "visible");
1927- mouseClick(root);
1928+
1929+ mouseClick(root, root.width / 2, units.gu(1));
1930 waitUntilLauncherDisappears();
1931 verify(launcher.state == "");
1932
1933 // and repeat, as a test for regression in lpbug#1531339
1934 dragLauncherIntoView();
1935 verify(launcher.state == "visible");
1936- mouseClick(root);
1937+ mouseClick(root, root.width / 2, units.gu(1));
1938 waitUntilLauncherDisappears();
1939 verify(launcher.state == "");
1940 }
1941@@ -1044,5 +1106,169 @@
1942 LauncherModel.setCountVisible(LauncherModel.get(1).appId, 0)
1943 LauncherModel.setCount(LauncherModel.get(1).appId, oldCount)
1944 }
1945+
1946+ function test_longpressSuperKeyShowsHints() {
1947+ var shortCutHint0 = findChild(findChild(launcher, "launcherDelegate0"), "shortcutHint");
1948+
1949+ tryCompare(shortCutHint0, "visible", false);
1950+
1951+ launcher.superPressed = true;
1952+ tryCompare(launcher, "state", "visible");
1953+ tryCompare(shortCutHint0, "visible", true);
1954+
1955+ launcher.superPressed = false;
1956+ tryCompare(launcher, "state", "");
1957+ tryCompare(shortCutHint0, "visible", false);
1958+ }
1959+
1960+ function test_keyboardNavigation() {
1961+ var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
1962+ var quickList = findChild(launcher, "quickList");
1963+ var launcherPanel = findChild(launcher, "launcherPanel");
1964+ var launcherListView = findChild(launcher, "launcherListView");
1965+ var last = launcherListView.count - 1;
1966+
1967+ compare(bfbFocusHighlight.visible, false);
1968+
1969+ launcher.openForKeyboardNavigation();
1970+ tryCompare(launcherPanel, "x", 0);
1971+ waitForRendering(launcher);
1972+
1973+ assertFocusOnIndex(-1);
1974+
1975+ // Down should go down
1976+ keyClick(Qt.Key_Down);
1977+ assertFocusOnIndex(0);
1978+
1979+ // Tab should go down
1980+ keyClick(Qt.Key_Tab);
1981+ assertFocusOnIndex(1);
1982+
1983+ // Up should go up
1984+ keyClick(Qt.Key_Up);
1985+ assertFocusOnIndex(0);
1986+
1987+ // Backtab should go up
1988+ keyClick(Qt.Key_Backtab);
1989+ assertFocusOnIndex(-1); // BFB
1990+
1991+ // The list should wrap around
1992+ keyClick(Qt.Key_Up);
1993+ assertFocusOnIndex(last);
1994+
1995+ keyClick(Qt.Key_Down);
1996+ waitForRendering(launcher);
1997+ keyClick(Qt.Key_Down);
1998+ assertFocusOnIndex(0); // Back to Top
1999+
2000+ // Right opens the quicklist
2001+ keyClick(Qt.Key_Right);
2002+ assertFocusOnIndex(0); // Navigating the quicklist... the launcher focus should not move
2003+ tryCompare(quickList, "visible", true);
2004+ tryCompare(quickList, "selectedIndex", 0)
2005+
2006+ // Down should move down the quicklist
2007+ keyClick(Qt.Key_Down);
2008+ tryCompare(quickList, "selectedIndex", 1)
2009+
2010+ // The quicklist should wrap around too
2011+ keyClick(Qt.Key_Down);
2012+ keyClick(Qt.Key_Down);
2013+ keyClick(Qt.Key_Down);
2014+ tryCompare(quickList, "selectedIndex", 0)
2015+
2016+ // Left gets us back to the launcher
2017+ keyClick(Qt.Key_Left);
2018+ assertFocusOnIndex(0);
2019+ tryCompare(quickList, "visible", false);
2020+
2021+ // Launcher navigation should still work
2022+ // Go bar to top by wrapping around
2023+ keyClick(Qt.Key_Down);
2024+ assertFocusOnIndex(1);
2025+ }
2026+
2027+ function test_selectQuicklistItemByKeyboard() {
2028+ launcher.openForKeyboardNavigation();
2029+ waitForRendering(launcher);
2030+
2031+ signalSpy.clear();
2032+ signalSpy.signalName = "quickListTriggered"
2033+
2034+ keyClick(Qt.Key_Down); // Down to launcher item 0
2035+ keyClick(Qt.Key_Down); // Down to launcher item 1
2036+ keyClick(Qt.Key_Right); // Into quicklist
2037+ keyClick(Qt.Key_Down); // Down to quicklist item 1
2038+ keyClick(Qt.Key_Down); // Down to quicklist item 2
2039+ keyClick(Qt.Key_Enter); // Trigger it
2040+
2041+ compare(signalSpy.count, 1, "Quicklist signal wasn't triggered")
2042+ compare(signalSpy.signalArguments[0][0], LauncherModel.get(1).appId)
2043+ compare(signalSpy.signalArguments[0][1], 2)
2044+ assertFocusOnIndex(-2);
2045+ }
2046+
2047+ function test_hideNotWorkingWhenLockedOut_data() {
2048+ return [
2049+ {tag: "locked visible", locked: true},
2050+ {tag: "no locked visible", locked: false},
2051+ ]
2052+ }
2053+
2054+ function test_hideNotWorkingWhenLockedOut(data) {
2055+ launcher.lockedVisible = data.locked;
2056+ if (data.locked) {
2057+ tryCompare(launcher, "state", "visible");
2058+ } else {
2059+ tryCompare(launcher, "state", "");
2060+ }
2061+
2062+ launcher.hide();
2063+ waitForRendering(launcher);
2064+ if (data.locked) {
2065+ verify(launcher.state == "visible");
2066+ } else {
2067+ verify(launcher.state == "");
2068+ }
2069+ }
2070+
2071+ function test_cancelKbdNavigationWitMouse_data() {
2072+ return [
2073+ {tag: "locked out - no quicklist", autohide: false, withQuickList: false },
2074+ {tag: "locked out - with quicklist", autohide: false, withQuickList: true },
2075+ {tag: "autohide - no quicklist", autohide: true, withQuickList: false },
2076+ {tag: "autohide - with quicklist", autohide: true, withQuickList: true },
2077+ ]
2078+ }
2079+
2080+ function test_cancelKbdNavigationWitMouse(data) {
2081+ launcher.autohideEnabled = data.autohide;
2082+ launcher.openForKeyboardNavigation();
2083+ waitForRendering(launcher);
2084+
2085+ var launcherPanel = findChild(launcher, "launcherPanel");
2086+ tryCompare(launcherPanel, "x", 0);
2087+
2088+ var quickList = findChild(launcher, "quickList");
2089+
2090+ keyClick(Qt.Key_Down); // Down to launcher item 0
2091+ keyClick(Qt.Key_Down); // Down to launcher item 1
2092+
2093+ if (data.withQuickList) {
2094+ keyClick(Qt.Key_Right); // Into quicklist
2095+ tryCompare(quickList, "visible", true)
2096+ }
2097+ waitForRendering(launcher)
2098+
2099+ mouseClick(root);
2100+
2101+ if (data.autohide) {
2102+ tryCompare(launcher, "state", "");
2103+ } else {
2104+ tryCompare(launcher, "state", "visible");
2105+ }
2106+
2107+ assertFocusOnIndex(-2);
2108+ }
2109 }
2110 }
2111
2112=== modified file 'tests/qmltests/tst_Shell.qml'
2113--- tests/qmltests/tst_Shell.qml 2016-01-29 11:51:09 +0000
2114+++ tests/qmltests/tst_Shell.qml 2016-02-02 22:18:26 +0000
2115@@ -26,6 +26,7 @@
2116 import Unity.Connectivity 0.1
2117 import Unity.Indicators 0.1
2118 import Unity.Notifications 1.0
2119+import Unity.Launcher 0.1
2120 import Unity.Test 0.1
2121 import Powerd 0.1
2122 import Wizard 0.1 as Wizard
2123@@ -49,6 +50,11 @@
2124 shellLoader.active = true;
2125 }
2126
2127+ MouseArea {
2128+ id: clickThroughCatcher
2129+ anchors.fill: shellContainer
2130+ }
2131+
2132 Item {
2133 id: shellContainer
2134 anchors.left: root.left
2135@@ -116,10 +122,6 @@
2136 Component.onDestruction: {
2137 shellLoader.itemDestroyed = true;
2138 }
2139- Component.onCompleted: {
2140- var keyMapper = testCase.findChild(__shell, "physicalKeysMapper");
2141- keyMapper.controlInsteadOfAlt = true;
2142- }
2143 }
2144 }
2145 }
2146@@ -208,6 +210,31 @@
2147 checked: true
2148 color: "white"
2149 }
2150+ ListItem.ItemSelector {
2151+ id: ctrlModifier
2152+ anchors { left: parent.left; right: parent.right }
2153+ activeFocusOnPress: false
2154+ text: "Ctrl key as"
2155+ model: ["Ctrl", "Alt", "Super"]
2156+ onSelectedIndexChanged: {
2157+ var keyMapper = testCase.findChild(shellContainer, "physicalKeysMapper");
2158+ keyMapper.controlInsteadOfAlt = selectedIndex == 1;
2159+ keyMapper.controlInsteadOfSuper = selectedIndex == 2;
2160+ }
2161+ }
2162+
2163+ Row {
2164+ anchors { left: parent.left; right: parent.right }
2165+ CheckBox {
2166+ id: autohideLauncherCheckbox
2167+ onCheckedChanged: {
2168+ GSettingsController.setAutohideLauncher(checked)
2169+ }
2170+ }
2171+ Label {
2172+ text: "Autohide launcher"
2173+ }
2174+ }
2175
2176 Label { text: "Applications"; font.bold: true }
2177
2178@@ -291,6 +318,12 @@
2179 signalName: "applicationRemoved"
2180 }
2181
2182+ SignalSpy {
2183+ id: clickThroughSpy
2184+ target: clickThroughCatcher
2185+ signalName: "clicked"
2186+ }
2187+
2188 Telephony.CallEntry {
2189 id: phoneCall
2190 phoneNumber: "+447812221111"
2191@@ -901,6 +934,7 @@
2192 function dragLauncherIntoView() {
2193 var launcher = findChild(shell, "launcher");
2194 var launcherPanel = findChild(launcher, "launcherPanel");
2195+ waitForRendering(launcher);
2196 verify(launcherPanel.x = - launcherPanel.width);
2197
2198 var touchStartX = 2;
2199@@ -1430,7 +1464,7 @@
2200
2201 // Do a quick alt-tab and see if focus changes
2202 tryCompare(app3.session.lastSurface, "activeFocus", true)
2203- keyClick(Qt.Key_Tab, Qt.ControlModifier)
2204+ keyClick(Qt.Key_Tab, Qt.AltModifier)
2205 tryCompare(app2.session.lastSurface, "activeFocus", true)
2206
2207 var desktopSpread = findChild(shell, "spread")
2208@@ -1438,12 +1472,12 @@
2209 tryCompare(desktopSpread, "state", "")
2210
2211 // Just press Alt, make sure the spread comes up
2212- keyPress(Qt.Key_Control);
2213+ keyPress(Qt.Key_Alt);
2214 keyClick(Qt.Key_Tab);
2215 tryCompare(desktopSpread, "state", "altTab")
2216
2217 // Release control, check if spread disappears
2218- keyRelease(Qt.Key_Control)
2219+ keyRelease(Qt.Key_Alt)
2220 tryCompare(desktopSpread, "state", "")
2221
2222 // Focus should have switched back now
2223@@ -1471,7 +1505,7 @@
2224 tryCompare(desktopSpread, "state", "")
2225
2226 // Just press Alt, make sure the spread comes up
2227- keyPress(Qt.Key_Control);
2228+ keyPress(Qt.Key_Alt);
2229 keyClick(Qt.Key_Tab);
2230 tryCompare(desktopSpread, "state", "altTab")
2231 tryCompare(spreadRepeater, "highlightedIndex", 1)
2232@@ -1492,7 +1526,7 @@
2233 tryCompare(spreadRepeater, "highlightedIndex", 0)
2234
2235 // Release control, check if spread disappears
2236- keyRelease(Qt.Key_Control)
2237+ keyRelease(Qt.Key_Alt)
2238 tryCompare(desktopSpread, "state", "")
2239
2240 // Make sure that after wrapping around once, we have the same one focused as at the beginning
2241@@ -1505,7 +1539,7 @@
2242 var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
2243 verify(spreadRepeater !== null);
2244
2245- keyPress(Qt.Key_Control)
2246+ keyPress(Qt.Key_Alt)
2247 keyClick(Qt.Key_Tab);
2248 tryCompare(spreadRepeater, "highlightedIndex", 1);
2249
2250@@ -1527,7 +1561,7 @@
2251 keyClick(Qt.Key_Backtab);
2252 tryCompare(spreadRepeater, "highlightedIndex", 1);
2253
2254- keyRelease(Qt.Key_Control);
2255+ keyRelease(Qt.Key_Alt);
2256 }
2257
2258 function test_highlightFollowsMouse() {
2259@@ -1536,7 +1570,7 @@
2260 var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
2261 verify(spreadRepeater !== null);
2262
2263- keyPress(Qt.Key_Control)
2264+ keyPress(Qt.Key_Alt)
2265 keyClick(Qt.Key_Tab);
2266
2267 tryCompare(spreadRepeater, "highlightedIndex", 1);
2268@@ -1555,7 +1589,7 @@
2269
2270 verify(y < 4000);
2271
2272- keyRelease(Qt.Key_Control);
2273+ keyRelease(Qt.Key_Alt);
2274 }
2275
2276 function test_closeFromSpread() {
2277@@ -1564,7 +1598,7 @@
2278 var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
2279 verify(spreadRepeater !== null);
2280
2281- keyPress(Qt.Key_Control)
2282+ keyPress(Qt.Key_Alt)
2283 keyClick(Qt.Key_Tab);
2284
2285 appRemovedSpy.clear();
2286@@ -1591,7 +1625,7 @@
2287 tryCompare(appRemovedSpy, "count", 1)
2288 compare(appRemovedSpy.signalArguments[0][0], closedAppId);
2289
2290- keyRelease(Qt.Key_Control);
2291+ keyRelease(Qt.Key_Alt);
2292 }
2293
2294 function test_selectFromSpreadWithMouse_data() {
2295@@ -1611,7 +1645,7 @@
2296 var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
2297 verify(spreadRepeater !== null);
2298
2299- keyPress(Qt.Key_Control)
2300+ keyPress(Qt.Key_Alt)
2301 keyClick(Qt.Key_Tab);
2302
2303 var focusAppId = ApplicationManager.get(2).appId;
2304@@ -1638,7 +1672,7 @@
2305 tryCompare(stage, "state", "");
2306 tryCompare(ApplicationManager, "focusedApplicationId", focusAppId);
2307
2308- keyRelease(Qt.Key_Control);
2309+ keyRelease(Qt.Key_Alt);
2310 }
2311
2312 function test_progressiveAutoScrolling() {
2313@@ -1647,7 +1681,7 @@
2314 var appRepeater = findInvisibleChild(shell, "appRepeater");
2315 verify(appRepeater !== null);
2316
2317- keyPress(Qt.Key_Control)
2318+ keyPress(Qt.Key_Alt)
2319 keyClick(Qt.Key_Tab);
2320
2321 var spreadFlickable = findChild(shell, "spreadFlickable")
2322@@ -1658,7 +1692,7 @@
2323 var x = 0;
2324 var y = shell.height * .5
2325 mouseMove(shell, x, y)
2326- while (x <= spreadFlickable.width) {
2327+ while (x <= shell.width) {
2328 x+=10;
2329 mouseMove(shell, x, y)
2330 wait(0); // spin the loop so bindings get evaluated
2331@@ -1673,7 +1707,7 @@
2332 }
2333 tryCompare(spreadFlickable, "contentX", 0);
2334
2335- keyRelease(Qt.Key_Control);
2336+ keyRelease(Qt.Key_Alt);
2337 }
2338
2339 // This makes sure the hoverMouseArea is set to invisible AND disabled
2340@@ -1685,13 +1719,13 @@
2341 tryCompare(hoverMouseArea, "enabled", false)
2342 tryCompare(hoverMouseArea, "visible", false)
2343
2344- keyPress(Qt.Key_Control)
2345+ keyPress(Qt.Key_Alt)
2346 keyClick(Qt.Key_Tab);
2347
2348 tryCompare(hoverMouseArea, "enabled", true)
2349 tryCompare(hoverMouseArea, "visible", true)
2350
2351- keyRelease(Qt.Key_Control)
2352+ keyRelease(Qt.Key_Alt)
2353
2354 tryCompare(hoverMouseArea, "enabled", false)
2355 tryCompare(hoverMouseArea, "visible", false)
2356@@ -1708,7 +1742,7 @@
2357 var appRepeater = findInvisibleChild(shell, "appRepeater");
2358 verify(appRepeater !== null);
2359
2360- keyPress(Qt.Key_Control)
2361+ keyPress(Qt.Key_Alt)
2362 keyClick(Qt.Key_Tab);
2363
2364 tryCompare(spreadRepeater, "highlightedIndex", 1);
2365@@ -1729,33 +1763,46 @@
2366
2367 verify(y < 4000);
2368
2369- keyRelease(Qt.Key_Control);
2370- }
2371-
2372- function test_focusAppFromLauncherExitsSpread() {
2373+ keyRelease(Qt.Key_Alt);
2374+ }
2375+
2376+ function test_focusAppFromLauncherExitsSpread_data() {
2377+ return [
2378+ {tag: "autohide launcher", launcherLocked: false },
2379+ {tag: "locked launcher", launcherLocked: true }
2380+ ]
2381+ }
2382+
2383+ function test_focusAppFromLauncherExitsSpread(data) {
2384 loadDesktopShellWithApps()
2385-
2386+ var launcher = findChild(shell, "launcher");
2387 var desktopSpread = findChild(shell, "spread");
2388- var launcher = findChild(shell, "launcher");
2389 var bfb = findChild(launcher, "buttonShowDashHome");
2390
2391- keyPress(Qt.Key_Control)
2392+ GSettingsController.setAutohideLauncher(!data.launcherLocked);
2393+ waitForRendering(shell);
2394+
2395+ keyPress(Qt.Key_Alt)
2396 keyClick(Qt.Key_Tab);
2397
2398 tryCompare(desktopSpread, "state", "altTab")
2399
2400- revealLauncherByEdgePushWithMouse();
2401- tryCompare(launcher, "x", 0);
2402- mouseMove(bfb, bfb.width / 2, bfb.height / 2)
2403- waitForRendering(shell)
2404+ if (!data.launcherLocked) {
2405+ revealLauncherByEdgePushWithMouse();
2406+ tryCompare(launcher, "x", 0);
2407+ mouseMove(bfb, bfb.width / 2, bfb.height / 2)
2408+ waitForRendering(shell)
2409+ }
2410
2411 mouseClick(bfb, bfb.width / 2, bfb.height / 2)
2412- tryCompare(launcher, "state", "")
2413+ if (!data.launcherLocked) {
2414+ tryCompare(launcher, "state", "")
2415+ }
2416 tryCompare(desktopSpread, "state", "")
2417
2418 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash")
2419
2420- keyRelease(Qt.Key_Control);
2421+ keyRelease(Qt.Key_Alt);
2422 }
2423
2424 // regression test for http://pad.lv/1443319
2425@@ -1977,5 +2024,175 @@
2426 compare(ApplicationManager.findApplication("libreoffice") === null, true);
2427 }
2428 }
2429+
2430+ function test_inputEventsOnEdgesEndUpInAppSurface_data() {
2431+ return [
2432+ { tag: "phone", repeaterName: "spreadRepeater" },
2433+ { tag: "tablet", repeaterName: "spreadRepeater" },
2434+ { tag: "desktop", repeaterName: "appRepeater" },
2435+ ]
2436+ }
2437+
2438+ function test_inputEventsOnEdgesEndUpInAppSurface(data) {
2439+ loadShell(data.tag);
2440+ shell.usageScenario = data.tag;
2441+ waitForRendering(shell);
2442+ swipeAwayGreeter();
2443+
2444+ // Let's open a fullscreen app
2445+ var app = ApplicationManager.startApplication("camera-app");
2446+ waitUntilAppWindowIsFullyLoaded(app);
2447+
2448+ var appRepeater = findChild(shell, data.repeaterName);
2449+ var topmostAppDelegate = appRepeater.itemAt(0);
2450+ verify(topmostAppDelegate);
2451+
2452+ var topmostSurfaceItem = findChild(topmostAppDelegate, "surfaceItem");
2453+ verify(topmostSurfaceItem);
2454+
2455+ mouseClick(shell, 1, shell.height / 2);
2456+ compare(topmostSurfaceItem.mousePressCount, 1);
2457+ compare(topmostSurfaceItem.mouseReleaseCount, 1);
2458+
2459+ mouseClick(shell, shell.width - 1, shell.height / 2);
2460+ compare(topmostSurfaceItem.mousePressCount, 2);
2461+ compare(topmostSurfaceItem.mouseReleaseCount, 2);
2462+
2463+ tap(shell, 1, shell.height / 2);
2464+ compare(topmostSurfaceItem.touchPressCount, 1);
2465+ compare(topmostSurfaceItem.touchReleaseCount, 1);
2466+
2467+ tap(shell, shell.width - 1, shell.height / 2);
2468+ compare(topmostSurfaceItem.touchPressCount, 2);
2469+ compare(topmostSurfaceItem.touchReleaseCount, 2);
2470+ }
2471+
2472+ function test_superTabToCycleLauncher_data() {
2473+ return [
2474+ {tag: "autohide launcher", launcherLocked: false},
2475+ {tag: "locked launcher", launcherLocked: true}
2476+ ]
2477+ }
2478+
2479+ function test_superTabToCycleLauncher(data) {
2480+ loadShell("desktop");
2481+ shell.usageScenario = "desktop";
2482+ GSettingsController.setAutohideLauncher(!data.launcherLocked);
2483+ waitForRendering(shell);
2484+
2485+ var launcher = findChild(shell, "launcher");
2486+ var launcherPanel = findChild(launcher, "launcherPanel");
2487+ var firstAppInLauncher = LauncherModel.get(0).appId;
2488+
2489+ compare(launcher.state, data.launcherLocked ? "visible": "");
2490+ compare(launcherPanel.highlightIndex, -2);
2491+ compare(ApplicationManager.focusedApplicationId, "unity8-dash");
2492+
2493+ wait(2000)
2494+ // Use Super + Tab Tab to cycle to the first entry in the launcher
2495+ keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2496+ keyClick(Qt.Key_Tab);
2497+ tryCompare(launcher, "state", "visible");
2498+ tryCompare(launcherPanel, "highlightIndex", -1);
2499+ keyClick(Qt.Key_Tab);
2500+ tryCompare(launcherPanel, "highlightIndex", 0);
2501+ keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2502+ tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
2503+ tryCompare(launcherPanel, "highlightIndex", -2);
2504+ tryCompare(ApplicationManager, "focusedApplicationId", firstAppInLauncher);
2505+
2506+ // Now go back to the dash
2507+ keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2508+ keyClick(Qt.Key_Tab);
2509+ tryCompare(launcher, "state", "visible");
2510+ tryCompare(launcherPanel, "highlightIndex", -1);
2511+ keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2512+ tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
2513+ tryCompare(launcherPanel, "highlightIndex", -2);
2514+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2515+ }
2516+
2517+ function test_longpressSuperOpensLauncher() {
2518+ loadShell("desktop");
2519+ var launcher = findChild(shell, "launcher");
2520+ var shortcutHint = findChild(findChild(launcher, "launcherDelegate0"), "shortcutHint")
2521+
2522+ compare(launcher.state, "");
2523+ keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2524+ tryCompare(launcher, "state", "visible");
2525+ tryCompare(shortcutHint, "visible", true);
2526+
2527+ keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2528+ tryCompare(launcher, "state", "");
2529+ tryCompare(shortcutHint, "visible", false);
2530+ }
2531+
2532+ function test_metaNumberLaunchesFromLauncher_data() {
2533+ return [
2534+ {tag: "Meta+1", key: Qt.Key_1, index: 0},
2535+ {tag: "Meta+2", key: Qt.Key_2, index: 1},
2536+ {tag: "Meta+4", key: Qt.Key_5, index: 4},
2537+ {tag: "Meta+0", key: Qt.Key_0, index: 9},
2538+ ]
2539+ }
2540+
2541+ function test_metaNumberLaunchesFromLauncher(data) {
2542+ loadShell("desktop");
2543+ var launcher = findChild(shell, "launcher");
2544+ var appId = LauncherModel.get(data.index).appId;
2545+ waitForRendering(shell);
2546+
2547+ keyClick(data.key, Qt.MetaModifier);
2548+ tryCompare(ApplicationManager, "focusedApplicationId", appId);
2549+ }
2550+
2551+ function test_altF1OpensLauncherForKeyboardNavigation() {
2552+ loadShell("desktop");
2553+ waitForRendering(shell);
2554+ var launcher = findChild(shell, "launcher");
2555+
2556+ keyClick(Qt.Key_F1, Qt.AltModifier);
2557+ tryCompare(launcher, "state", "visible");
2558+ tryCompare(launcher, "focus", true)
2559+ }
2560+
2561+ function test_lockedOutLauncherShrinksStage() {
2562+ loadShell("desktop");
2563+ shell.usageScenario = "desktop";
2564+ waitForRendering(shell);
2565+
2566+ var appContainer = findChild(shell, "appContainer");
2567+ var launcher = findChild(shell, "launcher");
2568+
2569+ GSettingsController.setAutohideLauncher(true);
2570+ waitForRendering(shell)
2571+ var hiddenSize = appContainer.width;
2572+
2573+ GSettingsController.setAutohideLauncher(false);
2574+ waitForRendering(shell)
2575+ var shownSize = appContainer.width;
2576+
2577+ compare(shownSize + launcher.panelWidth, hiddenSize);
2578+ }
2579+
2580+ function test_fullscreenAppHidesLockedOutLauncher() {
2581+ loadShell("desktop");
2582+ shell.usageScenario = "desktop";
2583+ waitForRendering(shell);
2584+
2585+ var appContainer = findChild(shell, "appContainer");
2586+ var launcher = findChild(shell, "launcher");
2587+ var launcherPanel = findChild(launcher, "launcherPanel");
2588+
2589+ GSettingsController.setAutohideLauncher(false);
2590+ waitForRendering(shell)
2591+
2592+ tryCompare(appContainer, "width", shell.width - launcherPanel.width);
2593+
2594+ var cameraApp = ApplicationManager.startApplication("camera-app");
2595+ waitUntilAppWindowIsFullyLoaded(cameraApp);
2596+
2597+ tryCompare(appContainer, "width", shell.width);
2598+ }
2599 }
2600 }

Subscribers

People subscribed via source and target branches