Merge lp:~mzanetti/unity8/launcher-sizing into lp:unity8

Proposed by Michael Zanetti
Status: Superseded
Proposed branch: lp:~mzanetti/unity8/launcher-sizing
Merge into: lp:unity8
Prerequisite: lp:~mzanetti/unity8/launcher-updates
Diff against target: 2956 lines (+1315/-203)
33 files modified
CMakeLists.txt (+1/-1)
data/com.canonical.Unity8.gschema.xml (+11/-0)
debian/control (+3/-3)
plugins/AccountsService/AccountsService.cpp (+54/-0)
plugins/AccountsService/AccountsService.h (+8/-0)
qml/Components/EdgeBarrier.qml (+1/-1)
qml/Components/PhysicalKeysMapper.qml (+24/-0)
qml/Launcher/Launcher.qml (+144/-12)
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/ApplicationWindow.qml (+8/-0)
qml/Stages/DecoratedWindow.qml (+8/-0)
qml/Stages/DesktopSpread.qml (+59/-16)
qml/Stages/DesktopSpreadDelegate.qml (+15/-1)
qml/Stages/DesktopStage.qml (+54/-34)
qml/Stages/SurfaceContainer.qml (+36/-1)
qml/Stages/WindowResizeArea.qml (+3/-2)
tests/mocks/AccountsService/AccountsService.cpp (+17/-0)
tests/mocks/AccountsService/AccountsService.h (+8/-0)
tests/mocks/GSettings.1.0/fake_gsettings.cpp (+64/-0)
tests/mocks/GSettings.1.0/fake_gsettings.h (+18/-0)
tests/mocks/Unity/Application/MirSurface.cpp (+15/-1)
tests/mocks/Unity/Application/MirSurface.h (+6/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+2/-0)
tests/plugins/AccountsService/PropertiesServer.cpp (+10/-1)
tests/plugins/AccountsService/PropertiesServer.h (+0/-1)
tests/plugins/AccountsService/client.cpp (+29/-0)
tests/qmltests/Launcher/tst_Launcher.qml (+244/-18)
tests/qmltests/Stages/tst_DesktopStage.qml (+29/-3)
tests/qmltests/tst_Shell.qml (+203/-36)
To merge this branch: bzr merge lp:~mzanetti/unity8/launcher-sizing
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
Daniel d'Andrada (community) Needs Information
Michael Terry Needs Information
Michał Sawicz Needs Fixing
Albert Astals Cid (community) Abstain
Review via email: mp+280149@code.launchpad.net

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

Commit message

Make launcher scalable, allow it locking

Description of the change

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

 - see prereq
 - also this contains lp:~dandrader/unity8/fixDragHandleTest in the diff as I can only set 1 prereq. It will vanish after the next landing.

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

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

FAILED: Continuous integration, rev:2065
http://jenkins.qa.ubuntu.com/job/unity8-ci/6911/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5697
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/326/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1622
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/325
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1517
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1517
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/324
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/323
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4423
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5710
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5710/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/25935
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/125/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/325
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/325/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/25937

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

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

Some tests failing:

qmltestrunner.Shell::test_focusAppFromLauncherExitsSpread
qmltestrunner.Shell::test_progressiveAutoScrolling
qmltestrunner.Shell::test_superTabToCycleLauncher

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

One minor comment inline, fix the gsettings description

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

Text conflict in tests/qmltests/tst_Shell.qml
1 conflicts encountered.

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

FAILED: Continuous integration, rev:2071
http://jenkins.qa.ubuntu.com/job/unity8-ci/6952/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5789
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/367/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1663
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/366
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1558
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1558
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/365
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/364
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4477
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5802
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5802/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26068
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/136/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/366
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/366/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26069

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

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

FAILED: Continuous integration, rev:2073
http://jenkins.qa.ubuntu.com/job/unity8-ci/6958/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5800
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/373/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1669
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/372
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1564
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1564
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/371
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/370
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4486
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5813
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5813/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26085
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/141/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/372
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/372/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26084

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

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

I know this may be bending too far backwards, but have you considered re-using the unity7 gsettings locations for the launcher?

The org.compiz.unityshell schema, installed by the unity-schemas package, has a launcher-hide-mode key and a icon-size key. The former should work just fine for our needs. But the icon-size is specified in pixels. So if we used that key, maybe we'd do some clever (or dumb!) converting.

I know it's cleaner to use our own schema. But compatibility between the two DEs (both of which we make!) would be nice. But I'm not going to push very hard for it. :)

===

In Launcher.qml, when lockedVisible changes, this code immediately calls hide(). Do you want to trigger the dismiss timer instead? That way panel.preventHiding gets respected. And just calling hide() assumes that lockedVisible is tied to autohideEnabled. Which it is... But feels weird to have those be overlapping states and have Shell.qml be the one combining them.

How would you feel about renaming lockedVisible to something like visibleByDefault and just having it be set to "scenario == desktop"? And then having Launcher combine that state and autohideEnabled to do the right thing.

The current way is fine too. But maybe just use the dismiss trigger instead of hide() at least.

===

I also tested this on my phone and couldn't pull the launcher out. It just didn't come out when I swiped from the left... I probably did something wrong... Maybe I should do a fresh build, I just moved qml files into place (no c++ changes here or in pre-req, right?) since the debs from jenkins are 404 now. Have you tested this MP recently?

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

Oh, duh. The gsettings schema. Need to make a deb I guess.

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

OK... Now I see that autohideLauncher is in fact a separate property from Launcher.autohideEnabled. That confusion on my part drove me talking about the overlapping states above. I guess ignore that piece then.

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

Maybe move the launcherSettings object into the main Shell object instead of the Launcher, since it is not a launcher-specific object?

The old GSettings object seems to have moved into a Unity8Settings override-able object on the OrientedShell... I guess someone figured that was easier to mock than our existing GSettings mocks? But that means it's not accessible from the base Shell now, hence why you needed to add your own GSettings object.

:(

===

Neither the pips nor the badge text changes size with the launcher icons. Is that intentional?

===

I'm getting "Damper::maxDelta must be a positive number. Aborted" when running xvfbtestLauncher/Shell. But I also get that on the Dash tests. I don't think that's related. Outside of xvfb works fine.

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

re re-using the unity7 schema: I did try to keep compatibility in the launcher for a long time. However, given the drastic changes of how we work with app ids now, at some point I could not reuse the favorites key in there any more. Also this branch's requirements were quite different at some point, in a sense that we'd need to store different size configs for different usage modes, this might come back as a design request at any point. Last but not least, the px vs GU issue is another one why I think reusing is not the best idea. Even if I'd convert it, the setting is stored in pixels and will break if the use switches to a screen with different PX/GU.

===

re: hide() vs dismissTimer. using dismissTimer would cause the launcher to wait for some seconds before hiding when the user changes the setting in systemsettings, which I think would be a bit weird (unity7 hides it immediately on setting change too). You do have a point that if the user would have the mouse hovered on the launcher while changing the setting it would hide despite the user "interacting" with it. However, is it really a use case that the user interacts with the mouse on the launcher and uses, touch or cmdline to make the launcher hide at the same time? Hence my decision to go for hide() immediately, so the user gets immediate feedback when clicking on the (yet to be added in settings) checkbox.

===

re requiring a .deb for testing. I usually copy the schema to the device and call "sudo glib-compile-schemas /usr/share/glib-2.0/schemas" myself.

===

re moving GSettings around, yes, Daniel keeps on moving those things so he can mock them in QML instead of using the GSettingsController to control the mock... I think we should remove the Unity8Settings again, given that the only thing that we actually mock with that are already supported by our GSettingsControllerQML stuff. Also the workaround in Unity8Settings is not required any more as the fix for that landed by now. Given that touches quite some places tho, I'd vote for doing that in a different branch.

Anyhow, I've moved the GSettings object out of the launcher now and called it settings.

===

re pip and count emblems not scaling, yes, intentional. You couldn't read them any more at the smalles level and they'd be super huge on the biggest. I talked with design about that. we agreed to not scale them.

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

FAILED: Continuous integration, rev:2075
http://jenkins.qa.ubuntu.com/job/unity8-ci/6979/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5863
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/394/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1689
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/392
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1584
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1584
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/391
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/390
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4522
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5874
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5874/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26228
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/155/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/392
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/392/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26227

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

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

Alright then, sounds sensible. :)

I like the code changes, but looks like we have new failures in testShell at least? I get 15 new failures locally.

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

fixed the tests.

Please note that I had to merge lp:~dandrader/unity8/fixDragHandleTest in order to make xvfbtestShell work at all. As I already have a prereq, that diff will show up here too. It should vanish after the next landing.

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

FAILED: Continuous integration, rev:2078
http://jenkins.qa.ubuntu.com/job/unity8-ci/7033/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5973
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/448/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1738
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/441
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1633
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1633
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/440
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/439
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4617
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5984
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5984/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26502
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/198/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/446
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/446/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26503

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

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

I also see a failure in tst_Launcher::test_clickFlick in jenkins, but I don't see it locally. Does that pass/fail for you?

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

FAILED: Continuous integration, rev:2079
http://jenkins.qa.ubuntu.com/job/unity8-ci/7036/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5976
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/451/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1741
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/444
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1636
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1636
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/443
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/442
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4620
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5987
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5987/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26516
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/201/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/449
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/449/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26518

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

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

Hrm. Jenkins failure went away... And I can't see it locally, so fine. :) Approved, thanks!

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

Text conflict in qml/Launcher/Launcher.qml
Text conflict in qml/Launcher/LauncherPanel.qml
2 conflicts encountered.

Was already top approved.

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

> Text conflict in qml/Launcher/Launcher.qml
> Text conflict in qml/Launcher/LauncherPanel.qml
> 2 conflicts encountered.
>
> Was already top approved.

merged

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

FAILED: Continuous integration, rev:2080
http://jenkins.qa.ubuntu.com/job/unity8-ci/7059/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6013
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/474/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1764
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/467
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1659
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1659
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/466
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/465
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4645
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6024
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6024/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26616
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/219/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/472
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/472/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26617

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

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

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

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

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

Looks good again, and CI bot says good!

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

Something went wrong

file:///home/tsdgeos_work/phablet/unity8/launcher-sizing/tests/qmltests/Launcher/tst_Launcher.qml:313:18: Duplicate method name
             function assertFocusOnIndex(index) {

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

Found a small bug:

1. Alt+F1 to open the keyboard navigation
2. Press Down to highlight an item
3. Press Right to open the quicklist
4. Launch the app
5. The (keyboard) focus ring doesn't go away

review: Needs Fixing
Revision history for this message
Michael Terry (mterry) wrote :
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Hmm yes and no, it becomes obvious here now that the launcher stays locked visible in the desktop mode; tbh I don't recall seeing this when testing just the launcher-updates branch before

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

When switching between windows with Alt+Tab (while the launcher is locked visible), the launcher flashes/flickers

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

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

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

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

> Found a small bug:
>
> 1. Alt+F1 to open the keyboard navigation
> 2. Press Down to highlight an item
> 3. Press Right to open the quicklist
> 4. Launch the app
> 5. The (keyboard) focus ring doesn't go away
> review: Needs Fixing
> Reply
> Michael Terry (mterry) wrote 1 minute ago: #

> That's probably a bug in the pre-req: https://code.launchpad.net/~mzanetti/unity8/launcher-updates
> /+merge/278567

Indeed, fixed in the prereq and merged this

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

FAILED: Continuous integration, rev:2081
http://jenkins.qa.ubuntu.com/job/unity8-ci/7065/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6023
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/480/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1770
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/473
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1665
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1665
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/472
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/471
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4650
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6034
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6034/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26647
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/224/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/478
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/478/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26649

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) :
review: Abstain (the broken merge is gone)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

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

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

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

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

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

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

When having a fullscreen app (like camera or a webbrowser windows), the launcher should imho hide regardless of the visible-locked preference, just like the top panel does.

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

FAILED: Continuous integration, rev:2083
http://jenkins.qa.ubuntu.com/job/unity8-ci/7070/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6030/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/485/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1775
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/478
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1670/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1670
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/477
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/476
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4657/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6041
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6041/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26662
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/229/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/483
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/483/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26663

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

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

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

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

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

FAILED: Continuous integration, rev:2084
http://jenkins.qa.ubuntu.com/job/unity8-ci/7073/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6035
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/488/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1778
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/481
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1673
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1673
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/480
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/479
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4662
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6046
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6046/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26675
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/232/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/486
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/486/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26674

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

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

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

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

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

> When having a fullscreen app (like camera or a webbrowser windows), the
> launcher should imho hide regardless of the visible-locked preference, just
> like the top panel does.

done

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

FAILED: Continuous integration, rev:2085
http://jenkins.qa.ubuntu.com/job/unity8-ci/7075/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6038
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/490/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1780
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/483
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1675
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1675
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/482
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/481
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4665
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6049
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6049/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26686
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/234/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/488
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/488/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26688

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

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

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

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

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

The flickering and fullscreen is fixed, great

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

Please remove the spurious bzr tags, otherwise no more objections

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

> Please remove the spurious bzr tags, otherwise no more objections

done. must've been merged in after the initial proposal

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

LGTM, works fine now, minus some some havoc in LauncherModel (unrelated to this branch), gonna file a bug about it

* 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 (all the relevant tests passing locally)

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

Yes

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

FAILED: Continuous integration, rev:2086
http://jenkins.qa.ubuntu.com/job/unity8-ci/7077/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6041
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/492/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1782
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/485
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1677
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1677
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/484
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/483
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4668
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6052
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6052/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26705
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/236/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/490
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/490/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26704

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

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

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

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

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

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

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

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

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

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

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

Note: this was already top approved, re-approve after merge

Text conflict in qml/Components/PhysicalKeysMapper.qml
Text conflict in qml/Launcher/Launcher.qml
Text conflict in tests/qmltests/tst_Shell.qml
3 conflicts encountered.

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

Merges now, re-top-approving

review: Abstain
Revision history for this message
Michał Sawicz (saviq) wrote :

I don't think "always-launcher" is as easy as resizing the desktop stage, it results in fullscreen^W apps moving about:

http://imgur.com/a/5wxlt

Non-fullscreen apps should probably get margins instead of the whole stage being moved about.

I'd vote for leaving the always-launcher feature out from this MP.

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

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

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

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

- panel.dismissTimer.restart()
+ dismissTimer.restart()

Is that right?

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

qml/Launcher/Launcher.qml:98: ReferenceError: dismissTimer is not defined

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

Why to we need this new intermediate (id: stageContainer) Item in DesktopStage.qml?

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

> Why to we need this new intermediate (id: stageContainer) Item in
> DesktopStage.qml?

because the area for the apps needs to be smaller when the launcher is always visible. that said, this might not be good enough yet.

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

> - panel.dismissTimer.restart()
> + dismissTimer.restart()
>
> Is that right?

> qml/Launcher/Launcher.qml:98: ReferenceError: dismissTimer is not defined

bad merge, thanks. fixed

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 10/02/2016 14:31, Michael Zanetti wrote:
>> Why to we need this new intermediate (id: stageContainer) Item in
>> DesktopStage.qml?
> because the area for the apps needs to be smaller when the launcher is always visible. that said, this might not be good enough yet.

But the leftMargin is not being applied to it, but to appContainer instead.

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

> On 10/02/2016 14:31, Michael Zanetti wrote:
> >> Why to we need this new intermediate (id: stageContainer) Item in
> >> DesktopStage.qml?
> > because the area for the apps needs to be smaller when the launcher is
> always visible. that said, this might not be good enough yet.
>
>
> But the leftMargin is not being applied to it, but to appContainer instead.

Right. So the inner container is for the margins. As the wallpaper can't have the same margins (it shines through the launcher), it can't be inside that container. The outer is used for snapshotting the whole thing in order to apply blur for the spread background. I guess we could make the background also act as the outer container and with that get rid of one item. Anyways, as I said, this doesn't seem to be good enough for switching between fullscreen and non-fullscreen apps yet. have to rework it a bit.

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

Yes, works good now, even with the spread and fullscreen apps

* 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 (all the relevant tests passing locally)

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

Yes

review: Approve
lp:~mzanetti/unity8/launcher-sizing updated
2087. By Michael Zanetti

merge prereq

2088. By Michael Zanetti

don't shrink the complete stage

2089. By Michael Zanetti

default to autohide

2090. By Michael Zanetti

merge prereq

Unmerged revisions

Preview Diff

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

Subscribers

People subscribed via source and target branches