Merge lp:~lukas-kde/unity8/windowOpenCloseAnimations into lp:unity8

Proposed by Lukáš Tinkl
Status: Superseded
Proposed branch: lp:~lukas-kde/unity8/windowOpenCloseAnimations
Merge into: lp:unity8
Prerequisite: lp:~lukas-kde/unity8/fixPanelMaxState
Diff against target: 2596 lines (+1252/-372)
17 files modified
data/com.canonical.Unity8.gschema.xml (+11/-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 (+300/-231)
qml/Stages/WindowResizeArea.qml (+1/-1)
tests/mocks/GSettings.1.0/fake_gsettings.cpp (+64/-0)
tests/mocks/GSettings.1.0/fake_gsettings.h (+18/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+2/-0)
tests/qmltests/Launcher/tst_Launcher.qml (+244/-18)
tests/qmltests/Stages/tst_DesktopStage.qml (+3/-3)
tests/qmltests/Stages/tst_WindowResizeArea.qml (+1/-0)
tests/qmltests/tst_Shell.qml (+200/-36)
To merge this branch: bzr merge lp:~lukas-kde/unity8/windowOpenCloseAnimations
Reviewer Review Type Date Requested Status
Michael Terry Approve
PS Jenkins bot (community) continuous-integration Needs Fixing
Unity8 CI Bot continuous-integration Needs Fixing
Nick Dedekind (community) Needs Fixing
Review via email: mp+282028@code.launchpad.net

This proposal supersedes a proposal from 2016-01-08.

This proposal has been superseded by a proposal from 2016-02-02.

Commit message

Provide animations for windows opening/closing

Description of the change

Provide animations for windows opening/closing, as described by UX in the original bugreport.

* Are there any related MPs required for this MP to build/function as expected? Please list.

Yes, lp:~lukas-kde/unity8/fixPanelMaxState

* 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?

Yes

* If you changed the UI, has there been a design review?

Yes

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:2112
http://jenkins.qa.ubuntu.com/job/unity8-ci/7041/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5984
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/456/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1746
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/449
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1641
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1641
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/448
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/447
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4623
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5995
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5995/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26543
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/204/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/454
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/454/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26544

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Terry (mterry) wrote :

- The app closing animation seems to "stick" on the last frame. Or not smoothly go down to zero opacity. Or something. It didn't look right on my mako.

- closeApplication() takes two arguments, normally only using the first one. It uses the appId if the first argument is not given, which is an odd construction. Maybe just drop the second argument completely, as it's never used?

Otherwise already looks nice. :)

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

> - The app closing animation seems to "stick" on the last frame. Or not
> smoothly go down to zero opacity. Or something. It didn't look right on my
> mako.

Agree, using the standard UbuntuNumberAnimation feels much smoother, at least here

> - closeApplication() takes two arguments, normally only using the first one.
> It uses the appId if the first argument is not given, which is an odd
> construction. Maybe just drop the second argument completely, as it's never
> used?

Fixed

> Otherwise already looks nice. :)

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

FAILED: Continuous integration, rev:2114
http://jenkins.qa.ubuntu.com/job/unity8-ci/7048/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6000
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/463/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1753
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/456
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1648
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1648
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/455
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/454
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4635
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6011
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6011/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26591
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/211/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/461
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/461/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26592

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Terry (mterry) wrote :

> Agree, using the standard UbuntuNumberAnimation feels much smoother, at least here

I'm still seeing a bit of a pause at the end of the animation on my mako.

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

> > Agree, using the standard UbuntuNumberAnimation feels much smoother, at
> least here
>
> I'm still seeing a bit of a pause at the end of the animation on my mako.

I guess it's the reverse easing (UbuntuAnimation.StandardEasingReverse), if I try with StandardEasing, it goes away.

Revision history for this message
Michael Terry (mterry) wrote :

Yeah agreed, StandardEasing looks good to me. Is StandardEasingReverse specifically requested by Design?

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Yes, as per the attached bug report

Revision history for this message
Michael Terry (mterry) wrote :

Hrm. OK, but I ran Vesa's test code. And it didn't seem to pause at the end of the animation for me.

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

PASSED: Continuous integration, rev:2114
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/40/
Executed test runs:

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

review: Approve (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Confirming the close animation stuttering on flo. Could not see it on my laptop.

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

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Please test again, not it feels much smoother on both phone and desktop.

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

FAILED: Continuous integration, rev:2115
http://jenkins.qa.ubuntu.com/job/unity8-ci/7081/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6045
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/496/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1786
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/489
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1681
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1681
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/488
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/487
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4670
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6056
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6056/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26711
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/238/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/494
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/494/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26709

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

the new animation does behave better on my flo, but it's still not 100% perfect. Paying close attention one can still see the last frames sticking around longer than they should. I don't think it's a problem of this branch, rather some sync stuff happening in Unity.Application when cleaning the app out of the memory. The new animation makes it less obvious.

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

PASSED: Continuous integration, rev:2115
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/94/
Executed test runs:

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

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

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Terry (mterry) wrote :

But Michael, wouldn't the Unity.Application work only start happening once opacity is already animated down to zero?

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

FAILED: Continuous integration, rev:2117
http://jenkins.qa.ubuntu.com/job/unity8-ci/7084/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6048
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/499/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1789
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/492
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1684
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1684
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/491
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/490
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4672
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6059
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6059/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26716
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/241/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/497
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/497/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26715

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

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

PASSED: Continuous integration, rev:2117
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/101/
Executed test runs:

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

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

PASSED: Continuous integration, rev:2117
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/103/
Executed test runs:

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

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

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Animation is now smooth on devices, using a small hack to pause the animation at the end before actually closing the application.

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

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

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

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

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Terry (mterry) wrote :

Looks good to me. The delay after the animation is a gross hack, but not the worst thing. I sat with Lukas and couldn't figure out why it would be needed. But it seems to be for now.

So approved from my end. Animation is smooth with the delay.

Tested it manually.
CI bot is crazy right now, let's wait for it to fix itself before top-approving.
No tags.

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

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

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

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

FAILED: Continuous integration, rev:2118
http://jenkins.qa.ubuntu.com/job/unity8-ci/7089/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6056
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/504/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1794
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/497
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1689
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1689
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/496
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/495
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4677
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6067
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6067/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26733
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/244/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/502
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/502/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26734

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

I believe this is what is causing the window to not be visible when opening a maximised app.

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

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

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

review: Needs Fixing (continuous-integration)
2119. By Lukáš Tinkl

fix saving the state on closing (the delegate is no longer in maximized state)

2120. By Lukáš Tinkl

fix opacity and scale properties for apps that are started maximized

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Starting maximized apps should be fixed now

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

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

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

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

FAILED: Continuous integration, rev:2120
http://jenkins.qa.ubuntu.com/job/unity8-ci/7098/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6065
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/513/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1803
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/506
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1698
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1698
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/505
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/504
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4685
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6076
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6076/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26767
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/252/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/511
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/511/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26768

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

review: Needs Fixing (continuous-integration)
2121. By Lukáš Tinkl

fixup failing tests

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

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

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

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

FAILED: Continuous integration, rev:2121
http://jenkins.qa.ubuntu.com/job/unity8-ci/7099/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6069
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/514/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1804
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/507
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1699
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1699
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/506
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/505
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4687
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6080
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6080/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26773
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/253/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/512
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/512/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26772

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Terry (mterry) wrote :

LGTM now, maximized works.

review: Approve
2122. By Lukáš Tinkl

merge lp:~mzanetti/unity8/launcher-sizing

2123. By Nick Dedekind

fix disappearing windows

2124. By Lukáš Tinkl

merge prereq

2125. By Lukáš Tinkl

reevaluate the screen size by making it a binding

fixes tiny windows when switching stages

2126. By Lukáš Tinkl

drive just the appDelegate in states and transitions

2127. By Lukáš Tinkl

restore max states

2128. By Lukáš Tinkl

partial revert, turn the x/y coords into a binding as well
(they depend on screenWidth/Height too)

2129. By Lukáš Tinkl

simplify code, fix restoring maximized windows

2130. By Lukáš Tinkl

make close() a method of the delegate

2131. By Lukáš Tinkl

merge prereq, fix conflicts

2132. By Lukáš Tinkl

merge lp:~unity-team/unity8/launcher-sizing

2133. By Lukáš Tinkl

merge prereq

2134. By Lukáš Tinkl

merge trunk

2135. By Lukáš Tinkl

handle the close case coming from launcher

2136. By Lukáš Tinkl

fix the launcher ApplicationManager mock

2137. By Lukáš Tinkl

restart app if focusing doesn't work

happens with dash sometimes

2138. By Lukáš Tinkl

make the close animation testable using the App checkbox

2139. By Lukáš Tinkl

fix fullscreen apps being offset by the left margin

2140. By Lukáš Tinkl

disallow resizing windows up past the Panel

2141. By Lukáš Tinkl

fix closing animation for minimized apps

2142. By Lukáš Tinkl

fullscreen apps fix

2143. By Lukáš Tinkl

fix for fullscreen windows height

2144. By Lukáš Tinkl

merge lp:~mzanetti/unity8/launcher-sizing

2145. By Lukáš Tinkl

revert keymap (unrelated) changes

2146. By Lukáš Tinkl

depend on -15 appl framework

2147. By Lukáš Tinkl

implement maximizeHorizontally/Vertically

2148. By Lukáš Tinkl

requestStop() here

2149. By Lukáš Tinkl

save/restore the correct state in all cases

implement (easy now) maximize horizontal/vertical using it

2150. By Lukáš Tinkl

merge trunk

2151. By Lukáš Tinkl

merge trunk

2152. By Lukáš Tinkl

merge trunk

2153. By Lukáš Tinkl

merge trunk, resolve conflicts

2154. By Lukáš Tinkl

merge trunk

2155. By Lukáš Tinkl

merge trunk

Unmerged revisions

2155. By Lukáš Tinkl

merge trunk

2154. By Lukáš Tinkl

merge trunk

2153. By Lukáš Tinkl

merge trunk, resolve conflicts

2152. By Lukáš Tinkl

merge trunk

2151. By Lukáš Tinkl

merge trunk

2150. By Lukáš Tinkl

merge trunk

2149. By Lukáš Tinkl

save/restore the correct state in all cases

implement (easy now) maximize horizontal/vertical using it

2148. By Lukáš Tinkl

requestStop() here

2147. By Lukáš Tinkl

implement maximizeHorizontally/Vertically

2146. By Lukáš Tinkl

depend on -15 appl framework

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

Subscribers

People subscribed via source and target branches