Merge lp:~mzanetti/unity8/launcher-sizing into lp:unity8
- launcher-sizing
- Merge into trunk
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 | ||||
Related bugs: |
|
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
PS Jenkins bot (ps-jenkins) wrote : | # |
Lukáš Tinkl (lukas-kde) wrote : | # |
Some tests failing:
qmltestrunner.
qmltestrunner.
qmltestrunner.
Lukáš Tinkl (lukas-kde) wrote : | # |
One minor comment inline, fix the gsettings description
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2066
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2068
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2069
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Text conflict in tests/qmltests/
1 conflicts encountered.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2071
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2073
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
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?
Michael Terry (mterry) wrote : | # |
Oh, duh. The gsettings schema. Need to make a deb I guess.
Michael Terry (mterry) wrote : | # |
OK... Now I see that autohideLauncher is in fact a separate property from Launcher.
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 xvfbtestLaunche
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-
===
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 GSettingsContro
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2075
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2078
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Terry (mterry) wrote : | # |
I also see a failure in tst_Launcher:
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2079
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Terry (mterry) wrote : | # |
Hrm. Jenkins failure went away... And I can't see it locally, so fine. :) Approved, thanks!
Albert Astals Cid (aacid) wrote : | # |
Text conflict in qml/Launcher/
Text conflict in qml/Launcher/
2 conflicts encountered.
Was already top approved.
Michael Zanetti (mzanetti) wrote : | # |
> Text conflict in qml/Launcher/
> Text conflict in qml/Launcher/
> 2 conflicts encountered.
>
> Was already top approved.
merged
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2080
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2080
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Michael Terry (mterry) wrote : | # |
Looks good again, and CI bot says good!
Albert Astals Cid (aacid) wrote : | # |
Something went wrong
file://
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
Michael Terry (mterry) wrote : | # |
That's probably a bug in the pre-req: https:/
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
Lukáš Tinkl (lukas-kde) wrote : | # |
When switching between windows with Alt+Tab (while the launcher is locked visible), the launcher flashes/flickers
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2081
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
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:/
> /+merge/278567
Indeed, fixed in the prereq and merged this
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2081
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) : | # |
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2082
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2083
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2083
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2084
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2084
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2085
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
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
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2085
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2086
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Lukáš Tinkl (lukas-kde) wrote : | # |
The flickering and fullscreen is fixed, great
Lukáš Tinkl (lukas-kde) wrote : | # |
Please remove the spurious bzr tags, otherwise no more objections
Michael Zanetti (mzanetti) wrote : | # |
> Please remove the spurious bzr tags, otherwise no more objections
done. must've been merged in after the initial proposal
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
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2086
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2086
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2086
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2086
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Albert Astals Cid (aacid) wrote : | # |
Note: this was already top approved, re-approve after merge
Text conflict in qml/Components/
Text conflict in qml/Launcher/
Text conflict in tests/qmltests/
3 conflicts encountered.
Albert Astals Cid (aacid) wrote : | # |
Merges now, re-top-approving
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:
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.
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2089
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2089
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Terry (mterry) wrote : | # |
- panel.dismissTi
+ dismissTimer.
Is that right?
Lukáš Tinkl (lukas-kde) wrote : | # |
qml/Launcher/
Daniel d'Andrada (dandrader) wrote : | # |
Why to we need this new intermediate (id: stageContainer) Item in DesktopStage.qml?
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.
Michael Zanetti (mzanetti) wrote : | # |
> - panel.dismissTi
> + dismissTimer.
>
> Is that right?
> qml/Launcher/
bad merge, thanks. fixed
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2090
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2090
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
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.
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.
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
- 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
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" }, |
FAILED: Continuous integration, rev:2065 jenkins. qa.ubuntu. com/job/ unity8- ci/6911/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 5697 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- xenial- touch/326/ console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- vivid/1622 jenkins. qa.ubuntu. com/job/ unity8- qmluitest- xenial- amd64/325 jenkins. qa.ubuntu. com/job/ unity8- vivid-amd64- ci/1517 jenkins. qa.ubuntu. com/job/ unity8- vivid-i386- ci/1517 jenkins. qa.ubuntu. com/job/ unity8- xenial- amd64-ci/ 324 jenkins. qa.ubuntu. com/job/ unity8- xenial- i386-ci/ 323 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- vivid-touch/ 4423 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 5710 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 5710/artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 25935 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- xenial- touch/125/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- xenial- armhf/325 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- xenial- armhf/325/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 25937
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/6911/ rebuild
http://