Merge lp:~aacid/unity8/desktopRotatedCamera into lp:unity8

Proposed by Albert Astals Cid
Status: Superseded
Proposed branch: lp:~aacid/unity8/desktopRotatedCamera
Merge into: lp:unity8
Diff against target: 2267 lines (+1060/-168)
18 files modified
data/com.canonical.Unity8.gschema.xml (+11/-0)
qml/Components/PhysicalKeysMapper.qml (+24/-0)
qml/Launcher/Launcher.qml (+141/-9)
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/DecoratedWindow.qml (+27/-10)
qml/Stages/DesktopStage.qml (+49/-18)
qml/Stages/WindowResizeArea.qml (+7/-4)
tests/mocks/GSettings.1.0/fake_gsettings.cpp (+64/-0)
tests/mocks/GSettings.1.0/fake_gsettings.h (+18/-0)
tests/mocks/Unity/Application/ApplicationManager.cpp (+12/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+5/-0)
tests/qmltests/Launcher/tst_Launcher.qml (+244/-18)
tests/qmltests/tst_OrientedShell.qml (+13/-1)
tests/qmltests/tst_Shell.qml (+204/-36)
To merge this branch: bzr merge lp:~aacid/unity8/desktopRotatedCamera
Reviewer Review Type Date Requested Status
Lukáš Tinkl (community) Approve
PS Jenkins bot (community) continuous-integration Needs Fixing
Unity8 CI Bot continuous-integration Needs Fixing
Review via email: mp+287137@code.launchpad.net

This proposal has been superseded by a proposal from 2016-03-10.

Commit message

Desktop stage: Support rotatesWindowContents

Description of the change

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

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

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

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

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

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

PASSED: Continuous integration, rev:2205
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/481/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/643
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay/209
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial/209
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/666
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/684
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/684
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/680
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/680/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/680
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/680/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/680
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/680/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/680
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/680/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/680
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/680/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/680
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/680/artifact/output/*zip*/output.zip

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

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

FAILED: Continuous integration, rev:2205
http://jenkins.qa.ubuntu.com/job/unity8-ci/7411/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6628
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/826/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/2116
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/819
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/2011
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/2011
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/818
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/817
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/5031
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6639
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6639/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27879
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/424/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/824
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/824/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27878

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

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

FAILED: Continuous integration, rev:2206
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/499/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/663
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay/227
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial/227
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay/229
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial/229
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/686
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/704
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/704
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/700
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/700/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/700
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/700/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/700
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/700/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/700
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/700/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/700
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/700/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/700
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/700/artifact/output/*zip*/output.zip

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

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

Left some inline comments, also seems you want to rotate just the ApplicationWindow inside the delegate, why not do it directly there instead of doing the calculations to take the decoration into account?

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

Also, shouldn't there be some transition/animation when the window rotates?

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

FAILED: Continuous integration, rev:2206
http://jenkins.qa.ubuntu.com/job/unity8-ci/7429/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6659
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/844/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/2134
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/837
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/2029
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/2029
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/836
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/835
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/5053
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6670
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6670/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27923
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/441/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/842
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/842/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27922

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

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

> Left some inline comments, also seems you want to rotate just the
> ApplicationWindow inside the delegate, why not do it directly there instead of
> doing the calculations to take the decoration into account?

Yes, only the ApplicationWindow needs rotating and that's what i'm rotating only, no? I'm not sure what you mean with "there" means as instead of what i'm doing now.

Revision history for this message
Albert Astals Cid (aacid) wrote :

> Also, shouldn't there be some transition/animation when the window rotates?

The window doesn't really rotate, you move the phone and the window stays "the same" visually

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

> > Left some inline comments, also seems you want to rotate just the
> > ApplicationWindow inside the delegate, why not do it directly there instead
> of
> > doing the calculations to take the decoration into account?
>
> Yes, only the ApplicationWindow needs rotating and that's what i'm rotating
> only, no? I'm not sure what you mean with "there" means as instead of what i'm
> doing now.

Yup sorry, that's what I meant, blaming launchpad diff for not being to show/expand the context...

Revision history for this message
Albert Astals Cid (aacid) wrote :

> Why not just use "rotation: rotationAngle" instead of constructing the Rotation Transform? The "transformOrigin" is by default Item.Center

Because it doesn't work, see current code http://i.imgur.com/SeDA0n4.png vs using rotation as you say http://i.imgur.com/ptyxvQL.png

You need the correct origin otherwise the rotation sends the item away from the rest of the item

Revision history for this message
Albert Astals Cid (aacid) wrote :

> What about other states like "maximized", shouldn't we care about them as well?

They do work already, see tryOrientedShell, mako, windowed, start the second camera app and maximize it, then go to invertedlandscape and see how it works fine

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

FAILED: Continuous integration, rev:2208
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/501/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/665
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay/231
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial/231
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/688
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/706
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/706
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/702
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/702/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/702
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/702/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/702
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/702/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/702
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/702/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/702
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/702/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/702
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/702/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Maybe we would make camera-app not be fullscreen when in desktop mode (have code somewhere calling cameraApplication->setFullcreen(false)) instead of creating another app.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Good work, by the way. Completely forgot about implementing RotatesWindowContents in DesktopStage.

Another thing:
"""
{tag: "mako_windowed", deviceName: "mako", orientationAngleAfterRotation: 90, windowed: true},
"""

Wouldn't a "manta_windowed" make more sense? (larger display area)

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Maybe we would make camera-app not be fullscreen when in desktop mode (have
> code somewhere calling cameraApplication->setFullcreen(false)) instead of
> creating another app.

By the way, that would mimic the magic that will (or already does, don't recall trying) happen on the device.

Revision history for this message
Albert Astals Cid (aacid) wrote :

> Wouldn't a "manta_windowed" make more sense? (larger display area)

Does it matter? I guess the point is that it works on one it "should" work on all, maybe i can just add all three?

Revision history for this message
Albert Astals Cid (aacid) wrote :

> Maybe we would make camera-app not be fullscreen when in desktop mode (have code somewhere
> calling cameraApplication->setFullcreen(false)) instead of creating another app.

This has advantage that we kind of test the "same" camera app that we [will] have on the real world, the disadvantage is that we lose the hability to try/test pure fullscreen apps on the destkop stage (which i guess at some point makes sense too).

That's why i decided to go for the duplication case, but can make it the other way if you prefer.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 26/02/2016 10:36, Albert Astals Cid wrote:
>> Wouldn't a "manta_windowed" make more sense? (larger display area)
> Does it matter? I guess the point is that it works on one it "should" work on all, maybe i can just add all three?

just sugar on top. makes more sense when you look at it or try it out
manually.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 26/02/2016 10:43, Albert Astals Cid wrote:
> This has advantage that we kind of test the "same" camera app that we [will] have on the real world, the disadvantage is that we lose the hability to try/test pure fullscreen apps on the destkop stage (which i guess at some point makes sense too).

We already have other fullscreen apps there: gallery-app, webbrowser-app

Revision history for this message
Albert Astals Cid (aacid) wrote :

> We already have other fullscreen apps there: gallery-app, webbrowser-app

Sure, but they do not have rotatesWindowContents set

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

FAILED: Continuous integration, rev:2208
http://jenkins.qa.ubuntu.com/job/unity8-ci/7430/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6660
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/845/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/2135
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/838
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/2030
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/2030
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/837
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/836
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/5054
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6671
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6671/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27925
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/442/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/843
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/843/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27924

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

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

FAILED: Continuous integration, rev:2210
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/504/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/668
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay/237
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial/237
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=phone-armhf,release=vivid+overlay/238
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/691
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/709
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/709
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/705/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/705
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/705/artifact/output/*zip*/output.zip

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

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

FAILED: Continuous integration, rev:2210
http://jenkins.qa.ubuntu.com/job/unity8-ci/7432/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6663
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/847/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/2137
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/840
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/2032
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/2032
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/839
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/838
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/5058
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6674
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6674/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27930
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/444/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/845
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/845/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27929

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

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

fix for fullscreen apps in desktop mode

2092. By Lukáš Tinkl

similar fix to height...

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

Worked fine from my testing

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

Yes

* Did CI run pass? If not, please explain why.

Yes, unrelated failures

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

Yes

review: Approve
2093. By Albert Astals Cid

Desktop stage: Support rotatesWindowContents

2094. By Albert Astals Cid

Make it work on non fullscreen windows too

2095. By Albert Astals Cid

Add SurfaceManagerControls

2096. By Albert Astals Cid

These are readonly too (i think)

2097. By Albert Astals Cid

add the other two windowed variants too

2098. By Albert Astals Cid

also switch the min/maxwidth/height

2099. By Albert Astals Cid

Merge makeMakeTryOrientedShellWork

2100. By Albert Astals Cid

account for 180

2101. By Albert Astals Cid

Merge

2102. By Albert Astals Cid

Merge

2103. By Albert Astals Cid

Merge

2104. By Albert Astals Cid

Change to windowed/not windowed before starting the app

2105. By Albert Astals Cid

Merge

2106. By Albert Astals Cid

Merge

2107. By Albert Astals Cid

"compile"

2108. By Albert Astals Cid

fix startup of non rotatesWindowContents apps

2109. By Albert Astals Cid

Revert change infected from other branch

2110. By Albert Astals Cid

Merge

Unmerged revisions

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-03-10 09:37:58 +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>true</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-03-10 09:37:58 +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-03-10 09:37:58 +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+ panel.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,7 +353,7 @@
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 } else {
309@@ -240,11 +366,11 @@
310 property bool animate: true
311
312 onApplicationSelected: {
313- root.state = ""
314+ root.hide();
315 launcherApplicationSelected(appId)
316 }
317 onShowDashHome: {
318- root.state = ""
319+ root.hide();
320 root.showDashHome();
321 }
322
323@@ -254,6 +380,12 @@
324 }
325 }
326
327+ onKbdNavigationCancelled: {
328+ panel.highlightIndex = -2;
329+ root.hide();
330+ root.focus = false;
331+ }
332+
333 Behavior on x {
334 enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate;
335 NumberAnimation {
336
337=== modified file 'qml/Launcher/LauncherDelegate.qml'
338--- qml/Launcher/LauncherDelegate.qml 2015-11-19 16:55:31 +0000
339+++ qml/Launcher/LauncherDelegate.qml 2016-03-10 09:37:58 +0000
340@@ -20,6 +20,7 @@
341 Item {
342 id: root
343
344+ property int itemIndex: 0
345 property string iconName
346 property int count: 0
347 property bool countVisible: false
348@@ -29,10 +30,12 @@
349 property real maxAngle: 0
350 property bool inverted: false
351 property bool alerting: false
352- readonly property alias wiggling: wiggleAnim.running
353+ property bool highlighted: false
354+ property bool shortcutHintShown: false
355
356 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
357 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
358+ readonly property alias wiggling: wiggleAnim.running
359
360 property int itemWidth
361 property int itemHeight
362@@ -121,14 +124,25 @@
363
364 Item {
365 id: iconItem
366- width: parent.itemWidth + units.gu(1)
367+ width: root.width
368 height: parent.itemHeight + units.gu(1)
369 anchors.centerIn: parent
370
371+ Image {
372+ objectName: "focusRing"
373+ anchors.centerIn: iconShape
374+ height: width * 15 / 16
375+ width: iconShape.width + units.gu(1)
376+ source: "graphics/launcher-app-focus-ring.svg"
377+ sourceSize.width: width
378+ sourceSize.height: height
379+ visible: root.highlighted
380+ }
381+
382 ProportionalShape {
383 id: iconShape
384 anchors.centerIn: parent
385- width: parent.width - units.gu(2)
386+ width: root.itemWidth
387 aspect: UbuntuShape.DropShadow
388 source: Image {
389 id: iconImage
390@@ -144,7 +158,8 @@
391 anchors {
392 right: parent.right
393 bottom: parent.bottom
394- margins: units.dp(3)
395+ rightMargin: (iconItem.width - root.itemWidth) / 2 - units.dp(2)
396+ margins: units.dp(5)
397 }
398 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
399 height: units.gu(2)
400@@ -172,16 +187,11 @@
401 id: progressOverlay
402 objectName: "progressOverlay"
403
404- anchors {
405- left: iconItem.left
406- right: iconItem.right
407- verticalCenter: parent.verticalCenter
408- leftMargin: units.gu(1.5)
409- rightMargin: units.gu(1.5)
410- }
411+ anchors.centerIn: parent
412+ width: root.itemWidth * .8
413 height: units.gu(1)
414 visible: root.progress > -1
415- color: UbuntuColors.darkGrey
416+ backgroundColor: UbuntuColors.darkGrey
417 borderSource: "none"
418
419 Item {
420@@ -199,32 +209,56 @@
421 top: parent.top
422 bottom: parent.bottom
423 }
424- color: "white"
425+ backgroundColor: "white"
426 borderSource: "none"
427 width: progressOverlay.width
428 }
429 }
430 }
431
432- Image {
433- objectName: "runningHighlight"
434+ Column {
435 anchors {
436 left: parent.left
437 verticalCenter: parent.verticalCenter
438 }
439- visible: root.itemRunning
440- rotation: 180
441- source: "graphics/focused_app_arrow.png"
442+ spacing: units.gu(.5)
443+ Repeater {
444+ model: 1 // TODO: This should be "Math.min(3, app.surfaceCount)" once we have multiple surfaces
445+ Rectangle {
446+ objectName: "runningHighlight" + index
447+ width: units.gu(0.25)
448+ height: units.gu(.5)
449+ color: "white"
450+ visible: root.itemRunning
451+ }
452+ }
453 }
454
455- Image {
456+ Rectangle {
457 objectName: "focusedHighlight"
458 anchors {
459 right: parent.right
460 verticalCenter: parent.verticalCenter
461 }
462+ width: units.gu(0.25)
463+ height: units.gu(.5)
464+ color: "white"
465 visible: root.itemFocused
466- source: "graphics/focused_app_arrow.png"
467+ }
468+
469+ Rectangle {
470+ objectName: "shortcutHint"
471+ anchors.centerIn: parent
472+ width: units.gu(3)
473+ height: width
474+ color: "#E0292929"
475+ visible: root.shortcutHintShown
476+ Label {
477+ anchors.centerIn: parent
478+ text: (itemIndex + 1) % 10
479+ color: "white"
480+ font.weight: Font.DemiBold
481+ }
482 }
483 }
484
485
486=== modified file 'qml/Launcher/LauncherPanel.qml'
487--- qml/Launcher/LauncherPanel.qml 2016-01-11 17:38:19 +0000
488+++ qml/Launcher/LauncherPanel.qml 2016-03-10 09:37:58 +0000
489@@ -19,12 +19,13 @@
490 import Ubuntu.Components.ListItems 1.3 as ListItems
491 import Unity.Launcher 0.1
492 import Ubuntu.Components.Popups 1.3
493+import GlobalShortcut 1.0
494 import "../Components/ListItems"
495 import "../Components/"
496
497 Rectangle {
498 id: root
499- color: "#B2000000"
500+ color: "#E0292929"
501
502 rotation: inverted ? 180 : 0
503
504@@ -33,11 +34,13 @@
505 property bool dragging: false
506 property bool moving: launcherListView.moving || launcherListView.flicking
507 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
508- || mouseEventEater.containsMouse || dashItem.hovered
509- property int highlightIndex: -1
510+ || mouseEventEater.containsMouse || dashItem.hovered
511+ property int highlightIndex: -2
512+ property bool shortcutHintsShown: false
513
514 signal applicationSelected(string appId)
515 signal showDashHome()
516+ signal kbdNavigationCancelled()
517
518 onXChanged: {
519 if (quickList.state == "open") {
520@@ -45,6 +48,26 @@
521 }
522 }
523
524+ function highlightNext() {
525+ highlightIndex++;
526+ if (highlightIndex >= launcherListView.count) {
527+ highlightIndex = -1;
528+ }
529+ launcherListView.moveToIndex(Math.max(highlightIndex, 0));
530+ }
531+ function highlightPrevious() {
532+ highlightIndex--;
533+ if (highlightIndex <= -2) {
534+ highlightIndex = launcherListView.count - 1;
535+ }
536+ launcherListView.moveToIndex(Math.max(highlightIndex, 0));
537+ }
538+ function openQuicklist(index) {
539+ quickList.open(index);
540+ quickList.selectedIndex = 0;
541+ quickList.focus = true;
542+ }
543+
544 MouseArea {
545 id: mouseEventEater
546 anchors.fill: parent
547@@ -57,24 +80,16 @@
548 fill: parent
549 }
550
551- Item {
552+ Rectangle {
553 objectName: "buttonShowDashHome"
554 width: parent.width
555- height: units.gu(7)
556- clip: true
557-
558- UbuntuShape {
559- anchors {
560- fill: parent
561- topMargin: -units.gu(2)
562- }
563- aspect: UbuntuShape.Flat
564- backgroundColor: UbuntuColors.orange
565- }
566+ height: width * .9
567+ color: UbuntuColors.orange
568+ readonly property bool highlighted: root.highlightIndex == -1;
569
570 Image {
571 objectName: "dashItem"
572- width: units.gu(5)
573+ width: parent.width * .6
574 height: width
575 anchors.centerIn: parent
576 source: "graphics/home.png"
577@@ -85,6 +100,14 @@
578 anchors.fill: parent
579 onClicked: root.showDashHome()
580 }
581+ Rectangle {
582+ objectName: "bfbFocusHighlight"
583+ anchors.fill: parent
584+ border.color: "white"
585+ border.width: units.dp(1)
586+ color: "transparent"
587+ visible: parent.highlighted
588+ }
589 }
590
591 Item {
592@@ -102,10 +125,8 @@
593 objectName: "launcherListView"
594 anchors {
595 fill: parent
596- topMargin: -extensionSize + units.gu(0.5)
597- bottomMargin: -extensionSize + units.gu(1)
598- leftMargin: units.gu(0.5)
599- rightMargin: units.gu(0.5)
600+ topMargin: -extensionSize + width * .15
601+ bottomMargin: -extensionSize + width * .15
602 }
603 topMargin: extensionSize
604 bottomMargin: extensionSize
605@@ -140,11 +161,11 @@
606 }
607
608 // The height of the area where icons start getting folded
609- property int foldingStartHeight: units.gu(6.5)
610+ property int foldingStartHeight: itemHeight
611 // The height of the area where the items reach the final folding angle
612 property int foldingStopHeight: foldingStartHeight - itemHeight - spacing
613- property int itemWidth: units.gu(7)
614- property int itemHeight: units.gu(6.5)
615+ property int itemWidth: width * .75
616+ property int itemHeight: itemWidth * 15 / 16 + units.gu(1)
617 property int clickFlickSpeed: units.gu(60)
618 property int draggedIndex: dndArea.draggedIndex
619 property real realContentY: contentY - originY + topMargin
620@@ -172,12 +193,24 @@
621
622 UbuntuNumberAnimation {
623 id: moveAnimation
624+ objectName: "moveAnimation"
625 target: launcherListView
626 property: "contentY"
627 function moveTo(contentY) {
628 from = launcherListView.contentY;
629 to = contentY;
630- start();
631+ restart();
632+ }
633+ }
634+ function moveToIndex(index) {
635+ var totalItemHeight = launcherListView.itemHeight + launcherListView.spacing
636+ var itemPosition = index * totalItemHeight;
637+ var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
638+ var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : totalItemHeight
639+ if (itemPosition + totalItemHeight + distanceToEnd > launcherListView.contentY + launcherListView.originY + launcherListView.topMargin + height) {
640+ moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd - launcherListView.originY);
641+ } else if (itemPosition - distanceToEnd < launcherListView.contentY - launcherListView.originY + launcherListView.topMargin) {
642+ moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin + launcherListView.originY);
643 }
644 }
645
646@@ -192,9 +225,10 @@
647 // the right app when running autopilot tests for
648 // multiple apps.
649 readonly property string appId: model.appId
650+ itemIndex: index
651 itemHeight: launcherListView.itemHeight
652 itemWidth: launcherListView.itemWidth
653- width: itemWidth
654+ width: parent.width
655 height: itemHeight
656 iconName: model.icon
657 count: model.count
658@@ -204,6 +238,8 @@
659 itemFocused: model.focused
660 inverted: root.inverted
661 alerting: model.alerting
662+ highlighted: root.highlightIndex == index
663+ shortcutHintShown: root.shortcutHintsShown && index <= 9
664 z: -Math.abs(offset)
665 maxAngle: 55
666 property bool dragging: false
667@@ -241,14 +277,7 @@
668 onAlertingChanged: {
669 if(alerting) {
670 if (!dragging && (launcherListView.peekingIndex === -1 || launcher.visibleWidth > 0)) {
671- var itemPosition = index * launcherListView.itemHeight;
672- var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
673- var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : launcherListView.itemHeight
674- if (itemPosition + launcherListView.itemHeight + distanceToEnd > launcherListView.contentY + launcherListView.topMargin + height) {
675- moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd);
676- } else if (itemPosition - distanceToEnd < launcherListView.contentY + launcherListView.topMargin) {
677- moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin);
678- }
679+ launcherListView.moveToIndex(index)
680 if (!dragging && launcher.state !== "visible") {
681 peekingAnimation.start()
682 }
683@@ -402,10 +431,7 @@
684
685 if (mouse.button & Qt.RightButton) { // context menu
686 // Opening QuickList
687- quickList.item = clickedItem;
688- quickList.model = launcherListView.model.get(index).quickList;
689- quickList.appId = launcherListView.model.get(index).appId;
690- quickList.state = "open";
691+ quickList.open(index);
692 return;
693 }
694
695@@ -413,10 +439,8 @@
696
697 // First/last item do the scrolling at more than 12 degrees
698 if (index == 0 || index == launcherListView.count - 1) {
699- if (clickedItem.angle > 12) {
700- launcherListView.flick(0, -launcherListView.clickFlickSpeed);
701- } else if (clickedItem.angle < -12) {
702- launcherListView.flick(0, launcherListView.clickFlickSpeed);
703+ if (clickedItem.angle > 12 || clickedItem.angle < -12) {
704+ launcherListView.moveToIndex(index);
705 } else {
706 root.applicationSelected(LauncherModel.get(index).appId);
707 }
708@@ -424,10 +448,8 @@
709 }
710
711 // the rest launches apps up to an angle of 30 degrees
712- if (clickedItem.angle > 30) {
713- launcherListView.flick(0, -launcherListView.clickFlickSpeed);
714- } else if (clickedItem.angle < -30) {
715- launcherListView.flick(0, launcherListView.clickFlickSpeed);
716+ if (clickedItem.angle > 30 || clickedItem.angle < -30) {
717+ launcherListView.moveToIndex(index);
718 } else {
719 root.applicationSelected(LauncherModel.get(index).appId);
720 }
721@@ -481,11 +503,7 @@
722
723 draggedIndex = Math.floor((mouse.y + launcherListView.realContentY) / launcherListView.realItemHeight);
724
725- // Opening QuickList
726- quickList.item = selectedItem;
727- quickList.model = launcherListView.model.get(draggedIndex).quickList;
728- quickList.appId = launcherListView.model.get(draggedIndex).appId;
729- quickList.state = "open";
730+ quickList.open(draggedIndex)
731
732 launcherListView.interactive = false
733
734@@ -644,7 +662,9 @@
735 enabled: quickList.state == "open" || pressed
736
737 onClicked: {
738- quickList.state = ""
739+ quickList.state = "";
740+ quickList.focus = false;
741+ root.kbdNavigationCancelled();
742 }
743
744 // Forward for dragging to work when quickList is open
745@@ -693,12 +713,60 @@
746 property var model
747 property string appId
748 property var item
749+ property int selectedIndex: -1
750+
751+ Keys.onPressed: {
752+ switch (event.key) {
753+ case Qt.Key_Down:
754+ selectedIndex++;
755+ if (selectedIndex >= popoverRepeater.count) {
756+ selectedIndex = 0;
757+ }
758+ event.accepted = true;
759+ break;
760+ case Qt.Key_Up:
761+ selectedIndex--;
762+ if (selectedIndex < 0) {
763+ selectedIndex = popoverRepeater.count - 1;
764+ }
765+ event.accepted = true;
766+ break;
767+ case Qt.Key_Left:
768+ case Qt.Key_Escape:
769+ quickList.selectedIndex = -1;
770+ quickList.focus = false;
771+ quickList.state = ""
772+ event.accepted = true;
773+ break;
774+ case Qt.Key_Enter:
775+ case Qt.Key_Return:
776+ case Qt.Key_Space:
777+ if (quickList.selectedIndex >= 0) {
778+ LauncherModel.quickListActionInvoked(quickList.appId, quickList.selectedIndex)
779+ }
780+ quickList.selectedIndex = -1;
781+ quickList.focus = false;
782+ quickList.state = ""
783+ root.kbdNavigationCancelled();
784+ event.accepted = true;
785+ break;
786+ }
787+ }
788
789 // internal
790 property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) + quickList.item.offset : units.gu(1)
791 property int offset: itemCenter + (height/2) + units.gu(1) > parent.height ? -itemCenter - (height/2) - units.gu(1) + parent.height :
792 itemCenter - (height/2) < units.gu(1) ? (height/2) - itemCenter + units.gu(1) : 0
793
794+ function open(index) {
795+ var itemPosition = index * launcherListView.itemHeight;
796+ var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
797+ item = launcherListView.itemAt(launcherListView.width / 2, itemPosition + launcherListView.itemHeight / 2);
798+ quickList.model = launcherListView.model.get(index).quickList;
799+ quickList.appId = launcherListView.model.get(index).appId;
800+ quickList.state = "open";
801+ }
802+
803 Column {
804 id: quickListColumn
805 width: parent.width
806@@ -712,6 +780,7 @@
807 objectName: "quickListEntry" + index
808 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
809 highlightWhenPressed: model.clickable
810+ selected: index === quickList.selectedIndex
811
812 // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
813 // ListItems don't know that they are sitting in a themed Popover where the color
814@@ -727,6 +796,8 @@
815 // Unsetting model to prevent showing changing entries during fading out
816 // that may happen because of triggering an action.
817 LauncherModel.quickListActionInvoked(quickList.appId, index);
818+ quickList.focus = false;
819+ root.kbdNavigationCancelled();
820 quickList.model = undefined;
821 }
822 }
823
824=== added file 'qml/Launcher/graphics/launcher-app-focus-ring.svg'
825--- qml/Launcher/graphics/launcher-app-focus-ring.svg 1970-01-01 00:00:00 +0000
826+++ qml/Launcher/graphics/launcher-app-focus-ring.svg 2016-03-10 09:37:58 +0000
827@@ -0,0 +1,12 @@
828+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
829+<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">
830+ <!-- Generator: Sketch 3.4.4 (17249) - http://www.bohemiancoding.com/sketch -->
831+ <title>Shape</title>
832+ <desc>Created with Sketch.</desc>
833+ <defs></defs>
834+ <g id="•-Launcher" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
835+ <g id="Artboard-9" sketch:type="MSArtboardGroup" transform="translate(-163.000000, -1436.000000)" fill="#E95420">
836+ <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>
837+ </g>
838+ </g>
839+</svg>
840\ No newline at end of file
841
842=== modified file 'qml/Shell.qml'
843--- qml/Shell.qml 2016-03-08 20:59:08 +0000
844+++ qml/Shell.qml 2016-03-10 09:37:58 +0000
845@@ -25,6 +25,7 @@
846 import Unity.Connectivity 0.1
847 import Unity.Launcher 0.1
848 import GlobalShortcut 1.0 // has to be before Utils, because of WindowKeysFilter
849+import GSettings 1.0
850 import Utils 0.1
851 import Powerd 0.1
852 import SessionBroadcast 0.1
853@@ -187,6 +188,11 @@
854 }
855 }
856
857+ GSettings {
858+ id: settings
859+ schema.id: "com.canonical.Unity8"
860+ }
861+
862 Item {
863 id: stages
864 objectName: "stages"
865@@ -343,6 +349,11 @@
866 property: "altTabPressed"
867 value: physicalKeysMapper.altTabPressed
868 }
869+ Binding {
870+ target: applicationsDisplayLoader.item
871+ property: "leftMargin"
872+ value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
873+ }
874 }
875
876 Tutorial {
877@@ -373,7 +384,11 @@
878 InputMethod {
879 id: inputMethod
880 objectName: "inputMethod"
881- anchors { fill: parent; topMargin: panel.panelHeight }
882+ anchors {
883+ fill: parent
884+ topMargin: panel.panelHeight
885+ leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
886+ }
887 z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
888 }
889
890@@ -557,6 +572,10 @@
891 && !greeter.hasLockedApp
892 inverted: shell.usageScenario !== "desktop"
893 shadeBackground: !tutorial.running
894+ superPressed: physicalKeysMapper.superPressed
895+ superTabPressed: physicalKeysMapper.superTabPressed
896+ panelWidth: units.gu(settings.launcherWidth)
897+ lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
898
899 onShowDashHome: showHome()
900 onDash: showDash()
901@@ -576,6 +595,37 @@
902 panel.indicators.hide()
903 }
904 }
905+ onFocusChanged: {
906+ if (!focus) {
907+ applicationsDisplayLoader.focus = true;
908+ }
909+ }
910+
911+ GlobalShortcut {
912+ shortcut: Qt.AltModifier | Qt.Key_F1
913+ onTriggered: {
914+ launcher.openForKeyboardNavigation();
915+ }
916+ }
917+ GlobalShortcut {
918+ shortcut: Qt.MetaModifier | Qt.Key_0
919+ onTriggered: {
920+ if (LauncherModel.get(9)) {
921+ activateApplication(LauncherModel.get(9).appId);
922+ }
923+ }
924+ }
925+ Repeater {
926+ model: 9
927+ GlobalShortcut {
928+ shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
929+ onTriggered: {
930+ if (LauncherModel.get(index)) {
931+ activateApplication(LauncherModel.get(index).appId);
932+ }
933+ }
934+ }
935+ }
936 }
937
938 Wizard {
939
940=== modified file 'qml/Stages/AbstractStage.qml'
941--- qml/Stages/AbstractStage.qml 2016-01-14 13:03:20 +0000
942+++ qml/Stages/AbstractStage.qml 2016-03-10 09:37:58 +0000
943@@ -39,6 +39,8 @@
944 property int shellOrientationAngle
945 property bool spreadEnabled: true // If false, animations and right edge will be disabled
946 property bool suspended
947+ // A Stage should paint a wallpaper etc over its full size but not use the margins for window placement
948+ property int leftMargin: 0
949
950 // To be read from outside
951 property var mainApp: null
952
953=== modified file 'qml/Stages/DecoratedWindow.qml'
954--- qml/Stages/DecoratedWindow.qml 2015-11-30 18:25:47 +0000
955+++ qml/Stages/DecoratedWindow.qml 2016-03-10 09:37:58 +0000
956@@ -23,8 +23,8 @@
957 FocusScope {
958 id: root
959
960- width: applicationWindow.width
961- height: (decorationShown ? decoration.height : 0) + applicationWindow.height
962+ width: !counterRotate ? applicationWindow.width : applicationWindow.height
963+ height: visibleDecorationHeight + (!counterRotate ? applicationWindow.height : applicationWindow.width)
964
965 property alias window: applicationWindow
966 property alias application: applicationWindow.application
967@@ -36,15 +36,18 @@
968 property bool highlightShown: false
969 property real shadowOpacity: 1
970
971- property alias requestedWidth: applicationWindow.requestedWidth
972+ property real requestedWidth
973 property real requestedHeight
974+ property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
975+ readonly property real visibleDecorationHeight: root.decorationShown ? decoration.height : 0
976+ readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
977
978- property alias minimumWidth: applicationWindow.minimumWidth
979- readonly property int minimumHeight: (root.decorationShown ? decoration.height : 0) + applicationWindow.minimumHeight
980- property alias maximumWidth: applicationWindow.maximumWidth
981- readonly property int maximumHeight: (root.decorationShown ? decoration.height : 0) + applicationWindow.maximumHeight
982- property alias widthIncrement: applicationWindow.widthIncrement
983- property alias heightIncrement: applicationWindow.heightIncrement
984+ readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
985+ readonly property int minimumHeight: visibleDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
986+ readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
987+ readonly property int maximumHeight: visibleDecorationHeight + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
988+ readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
989+ readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
990
991 signal close()
992 signal maximize()
993@@ -98,8 +101,22 @@
994 anchors.top: parent.top
995 anchors.topMargin: decoration.height
996 anchors.left: parent.left
997- requestedHeight: root.requestedHeight - (root.decorationShown ? decoration.height : 0)
998+ readonly property real requestedHeightMinusDecoration: root.requestedHeight - root.visibleDecorationHeight
999+ requestedHeight: !counterRotate ? requestedHeightMinusDecoration : root.requestedWidth
1000+ requestedWidth: !counterRotate ? root.requestedWidth : requestedHeightMinusDecoration
1001 interactive: true
1002 focus: true
1003+
1004+ transform: Rotation {
1005+ readonly property int rotationAngle: applicationWindow.application &&
1006+ applicationWindow.application.rotatesWindowContents
1007+ ? ((360 - applicationWindow.surfaceOrientationAngle) % 360) : 0
1008+ readonly property real rotationOrigin: rotationAngle == 90 ? applicationWindow.height / 2
1009+ : rotationAngle == 270 ? applicationWindow.width / 2
1010+ : 0
1011+ origin.x: rotationOrigin
1012+ origin.y: rotationOrigin
1013+ angle: rotationAngle
1014+ }
1015 }
1016 }
1017
1018=== modified file 'qml/Stages/DesktopStage.qml'
1019--- qml/Stages/DesktopStage.qml 2016-02-03 14:00:47 +0000
1020+++ qml/Stages/DesktopStage.qml 2016-03-10 09:37:58 +0000
1021@@ -224,6 +224,7 @@
1022 PanelState.dropShadow = false;
1023 }
1024
1025+
1026 FocusScope {
1027 id: appContainer
1028 objectName: "appContainer"
1029@@ -254,14 +255,40 @@
1030 focus: appId === priv.focusedAppId
1031 width: decoratedWindow.width
1032 height: decoratedWindow.height
1033+
1034+ Connections {
1035+ target: root
1036+ onShellOrientationAngleChanged: {
1037+ // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
1038+ if (application && application.rotatesWindowContents) {
1039+ if (state == "normal") {
1040+ var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
1041+ angleDiff = (360 + angleDiff) % 360;
1042+ if (angleDiff === 90 || angleDiff === 270) {
1043+ var aux = decoratedWindow.requestedHeight;
1044+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.visibleDecorationHeight;
1045+ decoratedWindow.requestedWidth = aux - decoratedWindow.visibleDecorationHeight;
1046+ }
1047+ }
1048+ decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
1049+ } else {
1050+ decoratedWindow.surfaceOrientationAngle = 0;
1051+ }
1052+ }
1053+ }
1054+ Component.onCompleted: {
1055+ decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
1056+ }
1057+
1058+ readonly property alias application: decoratedWindow.application
1059+ readonly property alias minimumWidth: decoratedWindow.minimumWidth
1060+ readonly property alias minimumHeight: decoratedWindow.minimumHeight
1061+ readonly property alias maximumWidth: decoratedWindow.maximumWidth
1062+ readonly property alias maximumHeight: decoratedWindow.maximumHeight
1063+ readonly property alias widthIncrement: decoratedWindow.widthIncrement
1064+ readonly property alias heightIncrement: decoratedWindow.heightIncrement
1065 property alias requestedWidth: decoratedWindow.requestedWidth
1066 property alias requestedHeight: decoratedWindow.requestedHeight
1067- property alias minimumWidth: decoratedWindow.minimumWidth
1068- property alias minimumHeight: decoratedWindow.minimumHeight
1069- property alias maximumWidth: decoratedWindow.maximumWidth
1070- property alias maximumHeight: decoratedWindow.maximumHeight
1071- property alias widthIncrement: decoratedWindow.widthIncrement
1072- property alias heightIncrement: decoratedWindow.heightIncrement
1073
1074 QtObject {
1075 id: appDelegatePrivate
1076@@ -274,6 +301,7 @@
1077 readonly property alias maximizedLeft: appDelegatePrivate.maximizedLeft
1078 readonly property alias maximizedRight: appDelegatePrivate.maximizedRight
1079 readonly property alias minimized: appDelegatePrivate.minimized
1080+ readonly property alias fullscreen: decoratedWindow.fullscreen
1081
1082 readonly property string appId: model.appId
1083 property bool animationsEnabled: true
1084@@ -293,6 +321,7 @@
1085 visible: !visuallyMinimized &&
1086 !greeter.fullyShown &&
1087 (priv.foregroundMaximizedAppZ === -1 || priv.foregroundMaximizedAppZ <= z) ||
1088+ decoratedWindow.fullscreen ||
1089 (spread.state == "altTab" && index === spread.highlightedIndex)
1090
1091 Binding {
1092@@ -351,10 +380,11 @@
1093 states: [
1094 State {
1095 name: "fullscreen"; when: decoratedWindow.fullscreen
1096- extend: "maximized"
1097 PropertyChanges {
1098 target: appDelegate;
1099- y: -PanelState.panelHeight
1100+ x: rotation == 0 ? 0 : (parent.width - width) / 2 + (shellOrientationAngle == 90 ? -PanelState.panelHeight : PanelState.panelHeight)
1101+ y: rotation == 0 ? -PanelState.panelHeight : (parent.height - height) / 2
1102+ requestedWidth: appContainer.width; requestedHeight: appContainer.height;
1103 }
1104 },
1105 State {
1106@@ -371,21 +401,21 @@
1107 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1108 PropertyChanges {
1109 target: appDelegate;
1110- x: 0; y: 0;
1111- requestedWidth: root.width; requestedHeight: root.height;
1112+ x: root.leftMargin; y: 0;
1113+ requestedWidth: appContainer.width - root.leftMargin; requestedHeight: appContainer.height;
1114 visuallyMinimized: false;
1115 visuallyMaximized: true
1116 }
1117 },
1118 State {
1119 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
1120- PropertyChanges { target: appDelegate; x: 0; y: PanelState.panelHeight;
1121- requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
1122+ PropertyChanges { target: appDelegate; x: root.leftMargin; y: PanelState.panelHeight;
1123+ requestedWidth: (appContainer.width - root.leftMargin)/2; requestedHeight: appContainer.height - PanelState.panelHeight }
1124 },
1125 State {
1126 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
1127- PropertyChanges { target: appDelegate; x: root.width/2; y: PanelState.panelHeight;
1128- requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
1129+ PropertyChanges { target: appDelegate; x: (appContainer.width + root.leftMargin)/2; y: PanelState.panelHeight;
1130+ requestedWidth: (appContainer.width - root.leftMargin)/2; requestedHeight: appContainer.height - PanelState.panelHeight }
1131 },
1132 State {
1133 name: "minimized"; when: appDelegate.minimized
1134@@ -448,8 +478,9 @@
1135 minHeight: units.gu(10)
1136 borderThickness: units.gu(2)
1137 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
1138- screenWidth: root.width
1139- screenHeight: root.height
1140+ screenWidth: appContainer.width
1141+ screenHeight: appContainer.height
1142+ leftMargin: root.leftMargin
1143
1144 onPressed: { ApplicationManager.focusApplication(model.appId) }
1145 }
1146@@ -475,7 +506,7 @@
1147
1148 BlurLayer {
1149 id: blurLayer
1150- anchors.fill: parent
1151+ anchors.fill: appContainer
1152 source: appContainer
1153 visible: false
1154 }
1155@@ -527,7 +558,7 @@
1156 DesktopSpread {
1157 id: spread
1158 objectName: "spread"
1159- anchors.fill: parent
1160+ anchors.fill: appContainer
1161 workspace: appContainer
1162 focus: state == "altTab"
1163 altTabPressed: root.altTabPressed
1164
1165=== modified file 'qml/Stages/WindowResizeArea.qml'
1166--- qml/Stages/WindowResizeArea.qml 2016-02-03 14:00:47 +0000
1167+++ qml/Stages/WindowResizeArea.qml 2016-03-10 09:37:58 +0000
1168@@ -40,6 +40,7 @@
1169 property int defaultHeight: units.gu(50)
1170 property int screenWidth: 0
1171 property int screenHeight: 0
1172+ property int leftMargin: 0
1173
1174 QtObject {
1175 id: priv
1176@@ -72,10 +73,12 @@
1177 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
1178 Qt.rect(target.x, target.y, defaultWidth, defaultHeight));
1179
1180- target.requestedWidth = Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth);
1181- target.requestedHeight = Math.min(Math.max(windowGeometry.height, d.minimumHeight), root.screenHeight - PanelState.panelHeight);
1182- target.x = Math.max(Math.min(windowGeometry.x, root.screenWidth - target.requestedWidth), 0)
1183- target.y = Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight)
1184+ target.requestedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
1185+ target.requestedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
1186+ root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
1187+ target.x = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.requestedWidth),
1188+ (target.fullscreen ? 0 : root.leftMargin)); });
1189+ target.y = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight); });
1190
1191 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
1192 if (windowState === WindowStateStorage.WindowStateMaximized) {
1193
1194=== modified file 'tests/mocks/GSettings.1.0/fake_gsettings.cpp'
1195--- tests/mocks/GSettings.1.0/fake_gsettings.cpp 2015-09-29 20:19:56 +0000
1196+++ tests/mocks/GSettings.1.0/fake_gsettings.cpp 2016-03-10 09:37:58 +0000
1197@@ -22,6 +22,8 @@
1198
1199 GSettingsControllerQml::GSettingsControllerQml()
1200 : m_usageMode("Staged")
1201+ , m_autohideLauncher(false)
1202+ , m_launcherWidth(8)
1203 {
1204 }
1205
1206@@ -88,6 +90,32 @@
1207 }
1208 }
1209
1210+bool GSettingsControllerQml::autohideLauncher() const
1211+{
1212+ return m_autohideLauncher;
1213+}
1214+
1215+void GSettingsControllerQml::setAutohideLauncher(bool autohideLauncher)
1216+{
1217+ if (m_autohideLauncher != autohideLauncher) {
1218+ m_autohideLauncher = autohideLauncher;
1219+ Q_EMIT autohideLauncherChanged(autohideLauncher);
1220+ }
1221+}
1222+
1223+int GSettingsControllerQml::launcherWidth() const
1224+{
1225+ return m_launcherWidth;
1226+}
1227+
1228+void GSettingsControllerQml::setLauncherWidth(int launcherWidth)
1229+{
1230+ if (m_launcherWidth != launcherWidth) {
1231+ m_launcherWidth = launcherWidth;
1232+ Q_EMIT launcherWidthChanged(launcherWidth);
1233+ }
1234+}
1235+
1236 GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
1237 }
1238
1239@@ -129,6 +157,10 @@
1240 this, &GSettingsQml::lockedOutTimeChanged);
1241 connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::lifecycleExemptAppidsChanged,
1242 this, &GSettingsQml::lifecycleExemptAppidsChanged);
1243+ connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::autohideLauncherChanged,
1244+ this, &GSettingsQml::autohideLauncherChanged);
1245+ connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::launcherWidthChanged,
1246+ this, &GSettingsQml::launcherWidthChanged);
1247 }
1248
1249 GSettingsSchemaQml * GSettingsQml::schema() const {
1250@@ -192,9 +224,41 @@
1251 }
1252 }
1253
1254+bool GSettingsQml::autohideLauncher() const
1255+{
1256+ if (m_schema->id() == "com.canonical.Unity8") {
1257+ return GSettingsControllerQml::instance()->autohideLauncher();
1258+ } else {
1259+ return false;
1260+ }
1261+}
1262+
1263+int GSettingsQml::launcherWidth() const
1264+{
1265+ if (m_schema->id() == "com.canonical.Unity8") {
1266+ return GSettingsControllerQml::instance()->launcherWidth();
1267+ } else {
1268+ return false;
1269+ }
1270+}
1271+
1272 void GSettingsQml::setLifecycleExemptAppids(const QStringList &appIds)
1273 {
1274 if (m_schema->id() == "com.canonical.qtmir") {
1275 GSettingsControllerQml::instance()->setLifecycleExemptAppids(appIds);
1276 }
1277 }
1278+
1279+void GSettingsQml::setAutohideLauncher(bool autohideLauncher)
1280+{
1281+ if (m_schema->id() == "com.canonical.Unity8") {
1282+ GSettingsControllerQml::instance()->setAutohideLauncher(autohideLauncher);
1283+ }
1284+}
1285+
1286+void GSettingsQml::setLauncherWidth(int launcherWidth)
1287+{
1288+ if (m_schema->id() == "com.canonical.Unity8") {
1289+ GSettingsControllerQml::instance()->setLauncherWidth(launcherWidth);
1290+ }
1291+}
1292
1293=== modified file 'tests/mocks/GSettings.1.0/fake_gsettings.h'
1294--- tests/mocks/GSettings.1.0/fake_gsettings.h 2015-09-29 20:19:56 +0000
1295+++ tests/mocks/GSettings.1.0/fake_gsettings.h 2016-03-10 09:37:58 +0000
1296@@ -50,6 +50,8 @@
1297 Q_PROPERTY(QString usageMode READ usageMode WRITE setUsageMode NOTIFY usageModeChanged)
1298 Q_PROPERTY(qint64 lockedOutTime READ lockedOutTime WRITE setLockedOutTime NOTIFY lockedOutTimeChanged)
1299 Q_PROPERTY(QStringList lifecycleExemptAppids READ lifecycleExemptAppids WRITE setLifecycleExemptAppids NOTIFY lifecycleExemptAppidsChanged)
1300+ Q_PROPERTY(bool autohideLauncher READ autohideLauncher WRITE setAutohideLauncher NOTIFY autohideLauncherChanged)
1301+ Q_PROPERTY(int launcherWidth READ launcherWidth WRITE setLauncherWidth NOTIFY launcherWidthChanged)
1302
1303 public:
1304 GSettingsQml(QObject *parent = nullptr);
1305@@ -59,11 +61,15 @@
1306 QString usageMode() const;
1307 qint64 lockedOutTime() const;
1308 QStringList lifecycleExemptAppids() const;
1309+ bool autohideLauncher() const;
1310+ int launcherWidth() const;
1311
1312 void setPictureUri(const QString &str);
1313 void setUsageMode(const QString &usageMode);
1314 void setLockedOutTime(qint64 timestamp);
1315 void setLifecycleExemptAppids(const QStringList &appIds);
1316+ void setAutohideLauncher(bool autohideLauncher);
1317+ void setLauncherWidth(int launcherWidth);
1318
1319 Q_SIGNALS:
1320 void schemaChanged();
1321@@ -71,6 +77,8 @@
1322 void usageModeChanged(const QString&);
1323 void lockedOutTimeChanged(qint64);
1324 void lifecycleExemptAppidsChanged(const QStringList &);
1325+ void autohideLauncherChanged(bool);
1326+ void launcherWidthChanged(int launcherWidth);
1327
1328 private:
1329 GSettingsSchemaQml* m_schema;
1330@@ -98,11 +106,19 @@
1331 QStringList lifecycleExemptAppids() const;
1332 Q_INVOKABLE void setLifecycleExemptAppids(const QStringList &appIds);
1333
1334+ bool autohideLauncher() const;
1335+ Q_INVOKABLE void setAutohideLauncher(bool autohideLauncher);
1336+
1337+ int launcherWidth() const;
1338+ Q_INVOKABLE void setLauncherWidth(int launcherWidth);
1339+
1340 Q_SIGNALS:
1341 void pictureUriChanged(const QString&);
1342 void usageModeChanged(const QString&);
1343 void lockedOutTimeChanged(qint64 timestamp);
1344 void lifecycleExemptAppidsChanged(const QStringList&);
1345+ void autohideLauncherChanged(bool autohideLauncher);
1346+ void launcherWidthChanged(int launcherWidth);
1347
1348 private:
1349 GSettingsControllerQml();
1350@@ -111,6 +127,8 @@
1351 QString m_usageMode;
1352 qint64 m_lockedOutTime;
1353 QStringList m_lifecycleExemptAppids;
1354+ bool m_autohideLauncher;
1355+ int m_launcherWidth;
1356
1357 static GSettingsControllerQml* s_controllerInstance;
1358 QList<GSettingsQml *> m_registeredGSettings;
1359
1360=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
1361--- tests/mocks/Unity/Application/ApplicationManager.cpp 2015-12-03 18:10:39 +0000
1362+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2016-03-10 09:37:58 +0000
1363@@ -345,6 +345,18 @@
1364 m_availableApplications.append(application);
1365
1366 application = new ApplicationInfo(this);
1367+ application->setAppId("camera-app2");
1368+ application->setName("Camera2");
1369+ application->setScreenshotId("camera");
1370+ application->setIconId("camera");
1371+ application->setSupportedOrientations(Qt::PortraitOrientation
1372+ | Qt::LandscapeOrientation
1373+ | Qt::InvertedPortraitOrientation
1374+ | Qt::InvertedLandscapeOrientation);
1375+ application->setRotatesWindowContents(true);
1376+ m_availableApplications.append(application);
1377+
1378+ application = new ApplicationInfo(this);
1379 application->setAppId("gallery-app");
1380 application->setName("Gallery");
1381 application->setScreenshotId("gallery");
1382
1383=== modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp'
1384--- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-11-04 11:29:16 +0000
1385+++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2016-03-10 09:37:58 +0000
1386@@ -25,15 +25,20 @@
1387 MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
1388 item->setProgress(0);
1389 item->setPinned(true);
1390+ item->setRunning(true);
1391 item->setFocused(true);
1392 m_list.append(item);
1393 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
1394 item->setProgress(10);
1395 item->setPinned(true);
1396 m_list.append(item);
1397+ item = new MockLauncherItem("camera-app2", "/usr/share/applications/camera-app2.desktop", "Camera2", "camera", this);
1398+ item->setPinned(true);
1399+ m_list.append(item);
1400 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
1401 item->setProgress(50);
1402 item->setCountVisible(true);
1403+ item->setRunning(true);
1404 item->setAlerting(false);
1405 m_list.append(item);
1406 item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
1407
1408=== modified file 'tests/qmltests/Launcher/tst_Launcher.qml'
1409--- tests/qmltests/Launcher/tst_Launcher.qml 2016-01-19 15:36:15 +0000
1410+++ tests/qmltests/Launcher/tst_Launcher.qml 2016-03-10 09:37:58 +0000
1411@@ -28,12 +28,13 @@
1412 launcher. */
1413 Item {
1414 id: root
1415- width: units.gu(50)
1416- height: units.gu(55)
1417+ width: units.gu(140)
1418+ height: units.gu(70)
1419
1420 Loader {
1421 id: launcherLoader
1422 anchors.fill: parent
1423+ focus: true
1424 property bool itemDestroyed: false
1425 sourceComponent: Component {
1426 Launcher {
1427@@ -68,6 +69,7 @@
1428
1429 Component.onCompleted: {
1430 launcherLoader.itemDestroyed = false;
1431+ launcherLoader.focus = true
1432 edgeBarrierControls.target = testCase.findChild(this, "edgeBarrierController");
1433 }
1434 Component.onDestruction: {
1435@@ -77,11 +79,40 @@
1436 }
1437 }
1438
1439+ Binding {
1440+ target: launcherLoader.item
1441+ property: "lockedVisible"
1442+ value: lockedVisibleCheckBox.checked
1443+ }
1444+ Binding {
1445+ target: launcherLoader.item
1446+ property: "panelWidth"
1447+ value: units.gu(Math.round(widthSlider.value))
1448+ }
1449+
1450 ColumnLayout {
1451 anchors { bottom: parent.bottom; right: parent.right; margins: units.gu(1) }
1452 spacing: units.gu(1)
1453 width: childrenRect.width
1454
1455+ RowLayout {
1456+ CheckBox {
1457+ id: lockedVisibleCheckBox
1458+ checked: false
1459+ }
1460+ Label {
1461+ text: "Launcher always visible"
1462+ }
1463+ }
1464+
1465+ Slider {
1466+ id: widthSlider
1467+ Layout.fillWidth: true
1468+ minimumValue: 6
1469+ maximumValue: 12
1470+ value: 10
1471+ }
1472+
1473 MouseTouchEmulationCheckbox {}
1474
1475 EdgeBarrierControls {
1476@@ -102,6 +133,15 @@
1477 Layout.fillWidth: true
1478 }
1479
1480+ Button {
1481+ text: "open for kbd navigation"
1482+ onClicked: {
1483+ launcherLoader.item.openForKeyboardNavigation()
1484+ launcherLoader.item.forceActiveFocus();// = true
1485+ }
1486+ Layout.fillWidth: true
1487+ }
1488+
1489 Row {
1490 spacing: units.gu(1)
1491
1492@@ -206,10 +246,6 @@
1493 // growing while populating it with icons etc.
1494 tryCompare(listView, "flicking", false);
1495
1496- // Make sure noone changed the height of the window. The issue this test case
1497- // is verifying only happens on certain heights of the Launcher
1498- compare(root.height, units.gu(55));
1499-
1500 compare(listView.contentY, -listView.topMargin, "Launcher did not start up with first item unfolded");
1501
1502 // Now do check that snapping is in fact enabled
1503@@ -266,13 +302,32 @@
1504
1505 function positionLauncherListAtBeginning() {
1506 var listView = testCase.findChild(launcherLoader.item, "launcherListView");
1507- listView.contentY = -listView.topMargin;
1508+ var moveAnimation = findInvisibleChild(listView, "moveAnimation")
1509+
1510+ listView.moveToIndex(0);
1511+
1512+ waitForRendering(listView);
1513+ tryCompare(moveAnimation, "running", false);
1514 }
1515 function positionLauncherListAtEnd() {
1516 var listView = testCase.findChild(launcherLoader.item, "launcherListView");
1517- if ((listView.contentHeight + listView.topMargin + listView.bottomMargin) > listView.height) {
1518- listView.contentY = listView.topMargin + listView.contentHeight
1519- - listView.height;
1520+ var moveAnimation = findInvisibleChild(listView, "moveAnimation")
1521+
1522+ listView.moveToIndex(listView.count -1);
1523+
1524+ waitForRendering(listView);
1525+ tryCompare(moveAnimation, "running", false);
1526+ }
1527+
1528+ function assertFocusOnIndex(index) {
1529+ var launcherListView = findChild(launcher, "launcherListView");
1530+ var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
1531+
1532+ waitForRendering(launcher);
1533+ compare(bfbFocusHighlight.visible, index === -1);
1534+ for (var i = 0; i < launcherListView.count; i++) {
1535+ var focusRing = findChild(findChild(launcher, "launcherDelegate" + i), "focusRing")
1536+ compare(focusRing.visible, index === i);
1537 }
1538 }
1539
1540@@ -290,10 +345,10 @@
1541 dragLauncherIntoView()
1542
1543 // tapping on the center of the screen should dismiss the launcher
1544- mouseClick(launcher)
1545+ mouseClick(launcher, panel.width + units.gu(5), launcher.height / 2)
1546
1547 // should eventually get fully retracted (hidden)
1548- tryCompare(panel, "x", -launcher.panelWidth, 1000)
1549+ tryCompare(panel, "x", -launcher.panelWidth, 2000)
1550 }
1551
1552 /* If I click on the icon of an application on the launcher
1553@@ -377,6 +432,7 @@
1554 wait(100)
1555 compare(launcher.maxPanelX, -launcher.panelWidth, "Launcher moved even if it shouldn't")
1556 }
1557+
1558 waitUntilLauncherDisappears();
1559 launcher.available = true;
1560 }
1561@@ -400,6 +456,8 @@
1562 dragLauncherIntoView();
1563 var launcherListView = findChild(launcher, "launcherListView");
1564 for (var i = 0; i < launcherListView.count; ++i) {
1565+ launcherListView.moveToIndex(i);
1566+ waitForRendering(launcherListView);
1567 var delegate = findChild(launcherListView, "launcherDelegate" + i)
1568 compare(findChild(delegate, "countEmblem").visible, LauncherModel.get(i).countVisible)
1569 // Intentionally allow type coercion (string/number)
1570@@ -421,7 +479,7 @@
1571 var launcherListView = findChild(launcher, "launcherListView");
1572 for (var i = 0; i < launcherListView.count; ++i) {
1573 var delegate = findChild(launcherListView, "launcherDelegate" + i)
1574- compare(findChild(delegate, "runningHighlight").visible, LauncherModel.get(i).running)
1575+ compare(findChild(delegate, "runningHighlight0").visible, LauncherModel.get(i).running)
1576 }
1577 }
1578
1579@@ -460,6 +518,7 @@
1580 launcher.lastSelectedApplication = "";
1581 dragLauncherIntoView();
1582 var listView = findChild(launcher, "launcherListView");
1583+ var moveAnimation = findInvisibleChild(listView, "moveAnimation")
1584
1585 // flicking is unreliable. sometimes it works, sometimes the
1586 // list view moves just a tiny bit or not at all, making tests fail.
1587@@ -470,12 +529,14 @@
1588 } else {
1589 positionLauncherListAtEnd();
1590 }
1591- tryCompare(listView, "flicking", false);
1592-
1593 var oldY = listView.contentY;
1594
1595 mouseClick(listView, listView.width / 2, data.clickY);
1596- tryCompare(listView, "flicking", false);
1597+
1598+ if (data.expectFlick) {
1599+ tryCompare(moveAnimation, "running", true);
1600+ }
1601+ tryCompare(moveAnimation, "running", false);
1602
1603 if (data.expectFlick) {
1604 verify(listView.contentY != oldY);
1605@@ -764,14 +825,15 @@
1606 function test_launcher_dismiss() {
1607 dragLauncherIntoView();
1608 verify(launcher.state == "visible");
1609- mouseClick(root);
1610+
1611+ mouseClick(root, root.width / 2, units.gu(1));
1612 waitUntilLauncherDisappears();
1613 verify(launcher.state == "");
1614
1615 // and repeat, as a test for regression in lpbug#1531339
1616 dragLauncherIntoView();
1617 verify(launcher.state == "visible");
1618- mouseClick(root);
1619+ mouseClick(root, root.width / 2, units.gu(1));
1620 waitUntilLauncherDisappears();
1621 verify(launcher.state == "");
1622 }
1623@@ -1044,5 +1106,169 @@
1624 LauncherModel.setCountVisible(LauncherModel.get(1).appId, 0)
1625 LauncherModel.setCount(LauncherModel.get(1).appId, oldCount)
1626 }
1627+
1628+ function test_longpressSuperKeyShowsHints() {
1629+ var shortCutHint0 = findChild(findChild(launcher, "launcherDelegate0"), "shortcutHint");
1630+
1631+ tryCompare(shortCutHint0, "visible", false);
1632+
1633+ launcher.superPressed = true;
1634+ tryCompare(launcher, "state", "visible");
1635+ tryCompare(shortCutHint0, "visible", true);
1636+
1637+ launcher.superPressed = false;
1638+ tryCompare(launcher, "state", "");
1639+ tryCompare(shortCutHint0, "visible", false);
1640+ }
1641+
1642+ function test_keyboardNavigation() {
1643+ var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
1644+ var quickList = findChild(launcher, "quickList");
1645+ var launcherPanel = findChild(launcher, "launcherPanel");
1646+ var launcherListView = findChild(launcher, "launcherListView");
1647+ var last = launcherListView.count - 1;
1648+
1649+ compare(bfbFocusHighlight.visible, false);
1650+
1651+ launcher.openForKeyboardNavigation();
1652+ tryCompare(launcherPanel, "x", 0);
1653+ waitForRendering(launcher);
1654+
1655+ assertFocusOnIndex(-1);
1656+
1657+ // Down should go down
1658+ keyClick(Qt.Key_Down);
1659+ assertFocusOnIndex(0);
1660+
1661+ // Tab should go down
1662+ keyClick(Qt.Key_Tab);
1663+ assertFocusOnIndex(1);
1664+
1665+ // Up should go up
1666+ keyClick(Qt.Key_Up);
1667+ assertFocusOnIndex(0);
1668+
1669+ // Backtab should go up
1670+ keyClick(Qt.Key_Backtab);
1671+ assertFocusOnIndex(-1); // BFB
1672+
1673+ // The list should wrap around
1674+ keyClick(Qt.Key_Up);
1675+ assertFocusOnIndex(last);
1676+
1677+ keyClick(Qt.Key_Down);
1678+ waitForRendering(launcher);
1679+ keyClick(Qt.Key_Down);
1680+ assertFocusOnIndex(0); // Back to Top
1681+
1682+ // Right opens the quicklist
1683+ keyClick(Qt.Key_Right);
1684+ assertFocusOnIndex(0); // Navigating the quicklist... the launcher focus should not move
1685+ tryCompare(quickList, "visible", true);
1686+ tryCompare(quickList, "selectedIndex", 0)
1687+
1688+ // Down should move down the quicklist
1689+ keyClick(Qt.Key_Down);
1690+ tryCompare(quickList, "selectedIndex", 1)
1691+
1692+ // The quicklist should wrap around too
1693+ keyClick(Qt.Key_Down);
1694+ keyClick(Qt.Key_Down);
1695+ keyClick(Qt.Key_Down);
1696+ tryCompare(quickList, "selectedIndex", 0)
1697+
1698+ // Left gets us back to the launcher
1699+ keyClick(Qt.Key_Left);
1700+ assertFocusOnIndex(0);
1701+ tryCompare(quickList, "visible", false);
1702+
1703+ // Launcher navigation should still work
1704+ // Go bar to top by wrapping around
1705+ keyClick(Qt.Key_Down);
1706+ assertFocusOnIndex(1);
1707+ }
1708+
1709+ function test_selectQuicklistItemByKeyboard() {
1710+ launcher.openForKeyboardNavigation();
1711+ waitForRendering(launcher);
1712+
1713+ signalSpy.clear();
1714+ signalSpy.signalName = "quickListTriggered"
1715+
1716+ keyClick(Qt.Key_Down); // Down to launcher item 0
1717+ keyClick(Qt.Key_Down); // Down to launcher item 1
1718+ keyClick(Qt.Key_Right); // Into quicklist
1719+ keyClick(Qt.Key_Down); // Down to quicklist item 1
1720+ keyClick(Qt.Key_Down); // Down to quicklist item 2
1721+ keyClick(Qt.Key_Enter); // Trigger it
1722+
1723+ compare(signalSpy.count, 1, "Quicklist signal wasn't triggered")
1724+ compare(signalSpy.signalArguments[0][0], LauncherModel.get(1).appId)
1725+ compare(signalSpy.signalArguments[0][1], 2)
1726+ assertFocusOnIndex(-2);
1727+ }
1728+
1729+ function test_hideNotWorkingWhenLockedOut_data() {
1730+ return [
1731+ {tag: "locked visible", locked: true},
1732+ {tag: "no locked visible", locked: false},
1733+ ]
1734+ }
1735+
1736+ function test_hideNotWorkingWhenLockedOut(data) {
1737+ launcher.lockedVisible = data.locked;
1738+ if (data.locked) {
1739+ tryCompare(launcher, "state", "visible");
1740+ } else {
1741+ tryCompare(launcher, "state", "");
1742+ }
1743+
1744+ launcher.hide();
1745+ waitForRendering(launcher);
1746+ if (data.locked) {
1747+ verify(launcher.state == "visible");
1748+ } else {
1749+ verify(launcher.state == "");
1750+ }
1751+ }
1752+
1753+ function test_cancelKbdNavigationWitMouse_data() {
1754+ return [
1755+ {tag: "locked out - no quicklist", autohide: false, withQuickList: false },
1756+ {tag: "locked out - with quicklist", autohide: false, withQuickList: true },
1757+ {tag: "autohide - no quicklist", autohide: true, withQuickList: false },
1758+ {tag: "autohide - with quicklist", autohide: true, withQuickList: true },
1759+ ]
1760+ }
1761+
1762+ function test_cancelKbdNavigationWitMouse(data) {
1763+ launcher.autohideEnabled = data.autohide;
1764+ launcher.openForKeyboardNavigation();
1765+ waitForRendering(launcher);
1766+
1767+ var launcherPanel = findChild(launcher, "launcherPanel");
1768+ tryCompare(launcherPanel, "x", 0);
1769+
1770+ var quickList = findChild(launcher, "quickList");
1771+
1772+ keyClick(Qt.Key_Down); // Down to launcher item 0
1773+ keyClick(Qt.Key_Down); // Down to launcher item 1
1774+
1775+ if (data.withQuickList) {
1776+ keyClick(Qt.Key_Right); // Into quicklist
1777+ tryCompare(quickList, "visible", true)
1778+ }
1779+ waitForRendering(launcher)
1780+
1781+ mouseClick(root);
1782+
1783+ if (data.autohide) {
1784+ tryCompare(launcher, "state", "");
1785+ } else {
1786+ tryCompare(launcher, "state", "visible");
1787+ }
1788+
1789+ assertFocusOnIndex(-2);
1790+ }
1791 }
1792 }
1793
1794=== modified file 'tests/qmltests/tst_OrientedShell.qml'
1795--- tests/qmltests/tst_OrientedShell.qml 2016-01-28 11:31:48 +0000
1796+++ tests/qmltests/tst_OrientedShell.qml 2016-03-10 09:37:58 +0000
1797@@ -26,6 +26,7 @@
1798 import Unity.InputInfo 0.1
1799
1800 import "../../qml"
1801+import "Stages"
1802
1803 Rectangle {
1804 id: root
1805@@ -406,6 +407,8 @@
1806 }
1807 }
1808 }
1809+
1810+ SurfaceManagerControls { textColor: "white" }
1811 }
1812 }
1813
1814@@ -551,8 +554,11 @@
1815 function test_appRotatesWindowContents_data() {
1816 return [
1817 {tag: "mako", deviceName: "mako", orientationAngleAfterRotation: 90},
1818+ {tag: "mako_windowed", deviceName: "mako", orientationAngleAfterRotation: 90, windowed: true},
1819 {tag: "manta", deviceName: "manta", orientationAngleAfterRotation: 90},
1820- {tag: "flo", deviceName: "flo", orientationAngleAfterRotation: 180}
1821+ {tag: "manta_windowed", deviceName: "manta", orientationAngleAfterRotation: 90, windowed: true},
1822+ {tag: "flo", deviceName: "flo", orientationAngleAfterRotation: 180},
1823+ {tag: "flo_windowed", deviceName: "flo", orientationAngleAfterRotation: 180, windowed: true}
1824 ];
1825 }
1826 function test_appRotatesWindowContents(data) {
1827@@ -560,6 +566,12 @@
1828 var cameraApp = ApplicationManager.startApplication("camera-app");
1829 verify(cameraApp);
1830
1831+ if (data.windowed) {
1832+ usageModeSelector.selectWindowed();
1833+ } else {
1834+ usageModeSelector.selectStaged();
1835+ }
1836+
1837 // ensure the mock camera-app is as we expect
1838 compare(cameraApp.fullscreen, true);
1839 compare(cameraApp.rotatesWindowContents, true);
1840
1841=== modified file 'tests/qmltests/tst_Shell.qml'
1842--- tests/qmltests/tst_Shell.qml 2016-02-12 00:11:28 +0000
1843+++ tests/qmltests/tst_Shell.qml 2016-03-10 09:37:58 +0000
1844@@ -26,6 +26,7 @@
1845 import Unity.Connectivity 0.1
1846 import Unity.Indicators 0.1
1847 import Unity.Notifications 1.0
1848+import Unity.Launcher 0.1
1849 import Unity.Test 0.1
1850 import Powerd 0.1
1851 import Wizard 0.1 as Wizard
1852@@ -121,10 +122,6 @@
1853 Component.onDestruction: {
1854 shellLoader.itemDestroyed = true;
1855 }
1856- Component.onCompleted: {
1857- var keyMapper = testCase.findChild(__shell, "physicalKeysMapper");
1858- keyMapper.controlInsteadOfAlt = true;
1859- }
1860 }
1861 }
1862 }
1863@@ -213,6 +210,31 @@
1864 checked: true
1865 color: "white"
1866 }
1867+ ListItem.ItemSelector {
1868+ id: ctrlModifier
1869+ anchors { left: parent.left; right: parent.right }
1870+ activeFocusOnPress: false
1871+ text: "Ctrl key as"
1872+ model: ["Ctrl", "Alt", "Super"]
1873+ onSelectedIndexChanged: {
1874+ var keyMapper = testCase.findChild(shellContainer, "physicalKeysMapper");
1875+ keyMapper.controlInsteadOfAlt = selectedIndex == 1;
1876+ keyMapper.controlInsteadOfSuper = selectedIndex == 2;
1877+ }
1878+ }
1879+
1880+ Row {
1881+ anchors { left: parent.left; right: parent.right }
1882+ CheckBox {
1883+ id: autohideLauncherCheckbox
1884+ onCheckedChanged: {
1885+ GSettingsController.setAutohideLauncher(checked)
1886+ }
1887+ }
1888+ Label {
1889+ text: "Autohide launcher"
1890+ }
1891+ }
1892
1893 Label { text: "Applications"; font.bold: true }
1894
1895@@ -912,6 +934,7 @@
1896 function dragLauncherIntoView() {
1897 var launcher = findChild(shell, "launcher");
1898 var launcherPanel = findChild(launcher, "launcherPanel");
1899+ waitForRendering(launcher);
1900 verify(launcherPanel.x = - launcherPanel.width);
1901
1902 var touchStartX = 2;
1903@@ -1441,7 +1464,7 @@
1904
1905 // Do a quick alt-tab and see if focus changes
1906 tryCompare(app3.session.lastSurface, "activeFocus", true)
1907- keyClick(Qt.Key_Tab, Qt.ControlModifier)
1908+ keyClick(Qt.Key_Tab, Qt.AltModifier)
1909 tryCompare(app2.session.lastSurface, "activeFocus", true)
1910
1911 var desktopSpread = findChild(shell, "spread")
1912@@ -1449,12 +1472,12 @@
1913 tryCompare(desktopSpread, "state", "")
1914
1915 // Just press Alt, make sure the spread comes up
1916- keyPress(Qt.Key_Control);
1917+ keyPress(Qt.Key_Alt);
1918 keyClick(Qt.Key_Tab);
1919 tryCompare(desktopSpread, "state", "altTab")
1920
1921 // Release control, check if spread disappears
1922- keyRelease(Qt.Key_Control)
1923+ keyRelease(Qt.Key_Alt)
1924 tryCompare(desktopSpread, "state", "")
1925
1926 // Focus should have switched back now
1927@@ -1482,7 +1505,7 @@
1928 tryCompare(desktopSpread, "state", "")
1929
1930 // Just press Alt, make sure the spread comes up
1931- keyPress(Qt.Key_Control);
1932+ keyPress(Qt.Key_Alt);
1933 keyClick(Qt.Key_Tab);
1934 tryCompare(desktopSpread, "state", "altTab")
1935 tryCompare(spreadRepeater, "highlightedIndex", 1)
1936@@ -1503,7 +1526,7 @@
1937 tryCompare(spreadRepeater, "highlightedIndex", 0)
1938
1939 // Release control, check if spread disappears
1940- keyRelease(Qt.Key_Control)
1941+ keyRelease(Qt.Key_Alt)
1942 tryCompare(desktopSpread, "state", "")
1943
1944 // Make sure that after wrapping around once, we have the same one focused as at the beginning
1945@@ -1516,7 +1539,7 @@
1946 var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1947 verify(spreadRepeater !== null);
1948
1949- keyPress(Qt.Key_Control)
1950+ keyPress(Qt.Key_Alt)
1951 keyClick(Qt.Key_Tab);
1952 tryCompare(spreadRepeater, "highlightedIndex", 1);
1953
1954@@ -1538,7 +1561,7 @@
1955 keyClick(Qt.Key_Backtab);
1956 tryCompare(spreadRepeater, "highlightedIndex", 1);
1957
1958- keyRelease(Qt.Key_Control);
1959+ keyRelease(Qt.Key_Alt);
1960 }
1961
1962 function test_highlightFollowsMouse() {
1963@@ -1547,7 +1570,7 @@
1964 var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1965 verify(spreadRepeater !== null);
1966
1967- keyPress(Qt.Key_Control)
1968+ keyPress(Qt.Key_Alt)
1969 keyClick(Qt.Key_Tab);
1970
1971 tryCompare(spreadRepeater, "highlightedIndex", 1);
1972@@ -1566,7 +1589,7 @@
1973
1974 verify(y < 4000);
1975
1976- keyRelease(Qt.Key_Control);
1977+ keyRelease(Qt.Key_Alt);
1978 }
1979
1980 function test_closeFromSpread() {
1981@@ -1575,7 +1598,7 @@
1982 var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1983 verify(spreadRepeater !== null);
1984
1985- keyPress(Qt.Key_Control)
1986+ keyPress(Qt.Key_Alt)
1987 keyClick(Qt.Key_Tab);
1988
1989 appRemovedSpy.clear();
1990@@ -1602,7 +1625,7 @@
1991 tryCompare(appRemovedSpy, "count", 1)
1992 compare(appRemovedSpy.signalArguments[0][0], closedAppId);
1993
1994- keyRelease(Qt.Key_Control);
1995+ keyRelease(Qt.Key_Alt);
1996 }
1997
1998 function test_selectFromSpreadWithMouse_data() {
1999@@ -1622,7 +1645,7 @@
2000 var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
2001 verify(spreadRepeater !== null);
2002
2003- keyPress(Qt.Key_Control)
2004+ keyPress(Qt.Key_Alt)
2005 keyClick(Qt.Key_Tab);
2006
2007 var focusAppId = ApplicationManager.get(2).appId;
2008@@ -1649,7 +1672,7 @@
2009 tryCompare(stage, "state", "");
2010 tryCompare(ApplicationManager, "focusedApplicationId", focusAppId);
2011
2012- keyRelease(Qt.Key_Control);
2013+ keyRelease(Qt.Key_Alt);
2014 }
2015
2016 function test_progressiveAutoScrolling() {
2017@@ -1658,7 +1681,7 @@
2018 var appRepeater = findInvisibleChild(shell, "appRepeater");
2019 verify(appRepeater !== null);
2020
2021- keyPress(Qt.Key_Control)
2022+ keyPress(Qt.Key_Alt)
2023 keyClick(Qt.Key_Tab);
2024
2025 var spreadFlickable = findChild(shell, "spreadFlickable")
2026@@ -1669,7 +1692,7 @@
2027 var x = 0;
2028 var y = shell.height * .5
2029 mouseMove(shell, x, y)
2030- while (x <= spreadFlickable.width) {
2031+ while (x <= shell.width) {
2032 x+=10;
2033 mouseMove(shell, x, y)
2034 wait(0); // spin the loop so bindings get evaluated
2035@@ -1684,7 +1707,7 @@
2036 }
2037 tryCompare(spreadFlickable, "contentX", 0);
2038
2039- keyRelease(Qt.Key_Control);
2040+ keyRelease(Qt.Key_Alt);
2041 }
2042
2043 // This makes sure the hoverMouseArea is set to invisible AND disabled
2044@@ -1696,13 +1719,13 @@
2045 tryCompare(hoverMouseArea, "enabled", false)
2046 tryCompare(hoverMouseArea, "visible", false)
2047
2048- keyPress(Qt.Key_Control)
2049+ keyPress(Qt.Key_Alt)
2050 keyClick(Qt.Key_Tab);
2051
2052 tryCompare(hoverMouseArea, "enabled", true)
2053 tryCompare(hoverMouseArea, "visible", true)
2054
2055- keyRelease(Qt.Key_Control)
2056+ keyRelease(Qt.Key_Alt)
2057
2058 tryCompare(hoverMouseArea, "enabled", false)
2059 tryCompare(hoverMouseArea, "visible", false)
2060@@ -1719,7 +1742,7 @@
2061 var appRepeater = findInvisibleChild(shell, "appRepeater");
2062 verify(appRepeater !== null);
2063
2064- keyPress(Qt.Key_Control)
2065+ keyPress(Qt.Key_Alt)
2066 keyClick(Qt.Key_Tab);
2067
2068 tryCompare(spreadRepeater, "highlightedIndex", 1);
2069@@ -1740,33 +1763,46 @@
2070
2071 verify(y < 4000);
2072
2073- keyRelease(Qt.Key_Control);
2074- }
2075-
2076- function test_focusAppFromLauncherExitsSpread() {
2077+ keyRelease(Qt.Key_Alt);
2078+ }
2079+
2080+ function test_focusAppFromLauncherExitsSpread_data() {
2081+ return [
2082+ {tag: "autohide launcher", launcherLocked: false },
2083+ {tag: "locked launcher", launcherLocked: true }
2084+ ]
2085+ }
2086+
2087+ function test_focusAppFromLauncherExitsSpread(data) {
2088 loadDesktopShellWithApps()
2089-
2090+ var launcher = findChild(shell, "launcher");
2091 var desktopSpread = findChild(shell, "spread");
2092- var launcher = findChild(shell, "launcher");
2093 var bfb = findChild(launcher, "buttonShowDashHome");
2094
2095- keyPress(Qt.Key_Control)
2096+ GSettingsController.setAutohideLauncher(!data.launcherLocked);
2097+ waitForRendering(shell);
2098+
2099+ keyPress(Qt.Key_Alt)
2100 keyClick(Qt.Key_Tab);
2101
2102 tryCompare(desktopSpread, "state", "altTab")
2103
2104- revealLauncherByEdgePushWithMouse();
2105- tryCompare(launcher, "x", 0);
2106- mouseMove(bfb, bfb.width / 2, bfb.height / 2)
2107- waitForRendering(shell)
2108+ if (!data.launcherLocked) {
2109+ revealLauncherByEdgePushWithMouse();
2110+ tryCompare(launcher, "x", 0);
2111+ mouseMove(bfb, bfb.width / 2, bfb.height / 2)
2112+ waitForRendering(shell)
2113+ }
2114
2115 mouseClick(bfb, bfb.width / 2, bfb.height / 2)
2116- tryCompare(launcher, "state", "")
2117+ if (!data.launcherLocked) {
2118+ tryCompare(launcher, "state", "")
2119+ }
2120 tryCompare(desktopSpread, "state", "")
2121
2122 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash")
2123
2124- keyRelease(Qt.Key_Control);
2125+ keyRelease(Qt.Key_Alt);
2126 }
2127
2128 // regression test for http://pad.lv/1443319
2129@@ -1989,6 +2025,138 @@
2130 }
2131 }
2132
2133+ function test_superTabToCycleLauncher_data() {
2134+ return [
2135+ {tag: "autohide launcher", launcherLocked: false},
2136+ {tag: "locked launcher", launcherLocked: true}
2137+ ]
2138+ }
2139+
2140+ function test_superTabToCycleLauncher(data) {
2141+ loadShell("desktop");
2142+ shell.usageScenario = "desktop";
2143+ GSettingsController.setAutohideLauncher(!data.launcherLocked);
2144+ waitForRendering(shell);
2145+
2146+ var launcher = findChild(shell, "launcher");
2147+ var launcherPanel = findChild(launcher, "launcherPanel");
2148+ var firstAppInLauncher = LauncherModel.get(0).appId;
2149+
2150+ compare(launcher.state, data.launcherLocked ? "visible": "");
2151+ compare(launcherPanel.highlightIndex, -2);
2152+ compare(ApplicationManager.focusedApplicationId, "unity8-dash");
2153+
2154+ // Use Super + Tab Tab to cycle to the first entry in the launcher
2155+ keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2156+ keyClick(Qt.Key_Tab);
2157+ tryCompare(launcher, "state", "visible");
2158+ tryCompare(launcherPanel, "highlightIndex", -1);
2159+ keyClick(Qt.Key_Tab);
2160+ tryCompare(launcherPanel, "highlightIndex", 0);
2161+ keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2162+ tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
2163+ tryCompare(launcherPanel, "highlightIndex", -2);
2164+ tryCompare(ApplicationManager, "focusedApplicationId", firstAppInLauncher);
2165+
2166+ // Now go back to the dash
2167+ keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2168+ keyClick(Qt.Key_Tab);
2169+ tryCompare(launcher, "state", "visible");
2170+ tryCompare(launcherPanel, "highlightIndex", -1);
2171+ keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2172+ tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
2173+ tryCompare(launcherPanel, "highlightIndex", -2);
2174+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2175+ }
2176+
2177+ function test_longpressSuperOpensLauncher() {
2178+ loadShell("desktop");
2179+ var launcher = findChild(shell, "launcher");
2180+ var shortcutHint = findChild(findChild(launcher, "launcherDelegate0"), "shortcutHint")
2181+
2182+ compare(launcher.state, "");
2183+ keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2184+ tryCompare(launcher, "state", "visible");
2185+ tryCompare(shortcutHint, "visible", true);
2186+
2187+ keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2188+ tryCompare(launcher, "state", "");
2189+ tryCompare(shortcutHint, "visible", false);
2190+ }
2191+
2192+ function test_metaNumberLaunchesFromLauncher_data() {
2193+ return [
2194+ {tag: "Meta+1", key: Qt.Key_1, index: 0},
2195+ {tag: "Meta+2", key: Qt.Key_2, index: 1},
2196+ {tag: "Meta+4", key: Qt.Key_5, index: 4},
2197+ {tag: "Meta+0", key: Qt.Key_0, index: 9},
2198+ ]
2199+ }
2200+
2201+ function test_metaNumberLaunchesFromLauncher(data) {
2202+ loadShell("desktop");
2203+ var launcher = findChild(shell, "launcher");
2204+ var appId = LauncherModel.get(data.index).appId;
2205+ waitForRendering(shell);
2206+
2207+ keyClick(data.key, Qt.MetaModifier);
2208+ tryCompare(ApplicationManager, "focusedApplicationId", appId);
2209+ }
2210+
2211+ function test_altF1OpensLauncherForKeyboardNavigation() {
2212+ loadShell("desktop");
2213+ waitForRendering(shell);
2214+ var launcher = findChild(shell, "launcher");
2215+
2216+ keyClick(Qt.Key_F1, Qt.AltModifier);
2217+ tryCompare(launcher, "state", "visible");
2218+ tryCompare(launcher, "focus", true)
2219+ }
2220+
2221+ function test_lockedOutLauncherAddsMarginsToMaximized() {
2222+ loadShell("desktop");
2223+ shell.usageScenario = "desktop";
2224+ waitForRendering(shell);
2225+ var appContainer = findChild(shell, "appContainer");
2226+ var launcher = findChild(shell, "launcher");
2227+
2228+ var app = ApplicationManager.startApplication("music-app");
2229+ waitUntilAppWindowIsFullyLoaded(app);
2230+ var appDelegate = findChild(appContainer, "appDelegate_music-app");
2231+ appDelegate.maximize();
2232+ tryCompare(appDelegate, "visuallyMaximized", true);
2233+ waitForRendering(shell);
2234+
2235+ GSettingsController.setAutohideLauncher(true);
2236+ waitForRendering(shell)
2237+ var hiddenSize = appDelegate.width;
2238+
2239+ GSettingsController.setAutohideLauncher(false);
2240+ waitForRendering(shell)
2241+ var shownSize = appDelegate.width;
2242+
2243+ compare(shownSize + launcher.panelWidth, hiddenSize);
2244+ }
2245+
2246+ function test_fullscreenAppHidesLockedOutLauncher() {
2247+ loadShell("desktop");
2248+ shell.usageScenario = "desktop";
2249+
2250+ var launcher = findChild(shell, "launcher");
2251+ var launcherPanel = findChild(launcher, "launcherPanel");
2252+
2253+ GSettingsController.setAutohideLauncher(false);
2254+ waitForRendering(shell)
2255+
2256+ tryCompare(launcher, "lockedVisible", true);
2257+
2258+ var cameraApp = ApplicationManager.startApplication("camera-app");
2259+ waitUntilAppWindowIsFullyLoaded(cameraApp);
2260+
2261+ tryCompare(launcher, "lockedVisible", false);
2262+ }
2263+
2264+
2265 function test_inputEventsOnEdgesEndUpInAppSurface_data() {
2266 return [
2267 { tag: "phone", repeaterName: "spreadRepeater" },

Subscribers

People subscribed via source and target branches