Merge lp:~unity-team/unity8/dash-as-app into lp:unity8

Proposed by Michael Zanetti on 2014-07-28
Status: Merged
Approved by: Michał Sawicz on 2014-08-05
Approved revision: 1110
Merged at revision: 1111
Proposed branch: lp:~unity-team/unity8/dash-as-app
Merge into: lp:unity8
Prerequisite: lp:~mzanetti/unity8/drop-running-apps-from-dash
Diff against target: 2983 lines (+1043/-783)
51 files modified
CMakeLists.txt (+1/-0)
data/CMakeLists.txt (+5/-2)
data/unity8-dash.conf (+22/-0)
data/unity8-dash.desktop.in (+9/-0)
data/unity8.conf (+1/-7)
debian/unity8.install (+3/-0)
plugins/Unity/CMakeLists.txt (+1/-0)
plugins/Unity/DashCommunicator/CMakeLists.txt (+19/-0)
plugins/Unity/DashCommunicator/dashcommunicator.cpp (+43/-0)
plugins/Unity/DashCommunicator/dashcommunicator.h (+35/-0)
plugins/Unity/DashCommunicator/dashcommunicatorservice.cpp (+30/-0)
plugins/Unity/DashCommunicator/dashcommunicatorservice.h (+38/-0)
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.cpp (+39/-0)
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.h (+39/-0)
plugins/Unity/DashCommunicator/plugin.cpp (+31/-0)
plugins/Unity/DashCommunicator/plugin.h (+34/-0)
plugins/Unity/DashCommunicator/qmldir (+3/-0)
plugins/Unity/Launcher/launchermodel.cpp (+5/-0)
qml/Components/EdgeDemo.qml (+5/-6)
qml/Dash/Dash.qml (+8/-0)
qml/Dash/DashApplication.qml (+29/-0)
qml/Dash/GenericScopeView.qml (+1/-1)
qml/Dash/ScopeListView.qml (+0/-5)
qml/Launcher/Launcher.qml (+2/-3)
qml/Shell.qml (+26/-132)
qml/Stages/PhoneStage.qml (+61/-28)
qml/Stages/SpreadDelegate.qml (+6/-0)
qml/Stages/TabletStage.qml (+85/-41)
qml/Stages/TransformedSpreadDelegate.qml (+6/-5)
qml/Stages/TransformedTabletSpreadDelegate.qml (+29/-1)
src/CMakeLists.txt (+1/-0)
src/Dash/CMakeLists.txt (+12/-0)
src/Dash/main.cpp (+74/-0)
tests/mocks/Unity/Application/ApplicationInfo.cpp (+0/-62)
tests/mocks/Unity/Application/ApplicationInfo.h (+0/-10)
tests/mocks/Unity/Application/ApplicationManager.cpp (+17/-147)
tests/mocks/Unity/Application/ApplicationManager.h (+0/-16)
tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp (+1/-1)
tests/mocks/Unity/CMakeLists.txt (+1/-0)
tests/mocks/Unity/DashCommunicator/CMakeLists.txt (+18/-0)
tests/mocks/Unity/DashCommunicator/dashcommunicator.cpp (+37/-0)
tests/mocks/Unity/DashCommunicator/dashcommunicator.h (+39/-0)
tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.cpp (+33/-0)
tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.h (+36/-0)
tests/mocks/Unity/DashCommunicator/plugin.cpp (+31/-0)
tests/mocks/Unity/DashCommunicator/plugin.h (+34/-0)
tests/mocks/Unity/DashCommunicator/qmldir (+3/-0)
tests/qmltests/Dash/tst_Dash.qml (+19/-0)
tests/qmltests/Stages/tst_PhoneStage.qml (+3/-2)
tests/qmltests/tst_Shell.qml (+64/-277)
tests/qmltests/tst_ShellWithPin.qml (+4/-37)
To merge this branch: bzr merge lp:~unity-team/unity8/dash-as-app
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing on 2014-08-05
Michał Sawicz Approve on 2014-08-05
Daniel d'Andrada (community) 2014-07-28 Approve on 2014-07-29
Review via email: mp+228534@code.launchpad.net

Commit message

Split the dash from the shell into a separate app

Description of the change

### Notes for reviewers ###

* It depends on QtCompositor (silo 6). Alternatively this and qtcomp rc can be installed through ppa:unity-team/phone-right-edge

* Adds an upstart script to autolaunch and respawn the dash app.

* Introduces a new plugin DashCommunicator which consists of a server and a client part, to be used to communicate between shell and dash.

* Adds a mock plugin for the DashCommunicator plugin

* Drops a whole bunch of useless stuff from MockApplicationManager which isn't needed any more since QtCompositor. (The fake placing of surfaces behind the shell - as unity-mir did it.). This could/should have been gone earlier, but only became a visible issue with this branch. Those changes are isolated in commit 1099.

* Adds a fake unity8-dash app (screenshot) to MockApplicationManager which will always be there, simulating the running dash app.

* Drops some code and tests for stages in/out dragging, given the dash is a regular app now, the stages are always visible now.

* Updates/simplifies shell and dash tests for the split app scenario.

* Does some slight updates to the Stages to keep the Dash behind the current app when not in spread mode so a left edge flick still shows the dash behind the app.

### Still TODO ###

* Make autopilot work again

### Checklist ###

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

https://code.launchpad.net/~unity-team/unity-scopes-shell/drop-appid-workaround/+merge/228427
https://code.launchpad.net/~dandrader/qtmir/fix_lp1350917/+merge/229585

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

Yes, works fine for me, except launching apps from dash and AP (see TODO section)

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

Yes.

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

I added the additional binary and upstart script to installs, to be reviewed.

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

Vesa is on holiday atm. I tried to keep UI changes as minimal as possible to fulfill the design request of adding the dash into the spread. So should be good I hope.

To post a comment you must log in.
Daniel d'Andrada (dandrader) wrote :

"""
Q_SIGNALS:
    void setCurrentScope(const QString &scopeId, bool animate, bool reset);
"""

Naming signals like functions is never a good thing. I would make an effort to name it like a signal. "requestedScopeAsCurrent" or even "setCurrentScopeCalled" would do it.

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

> """
> Q_SIGNALS:
> void setCurrentScope(const QString &scopeId, bool animate, bool reset);
> """
>
> Naming signals like functions is never a good thing. I would make an effort to
> name it like a signal. "requestedScopeAsCurrent" or even
> "setCurrentScopeCalled" would do it.

That's in DashCommunicatorService and DBusDashCommunicatorService, to be clear.

Daniel d'Andrada (dandrader) wrote :

Jouni says nothing should happen when you do a right-edge drag and there's no app running. That is, when you have just the dash).

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

1 - long press power button
<shutdown dialog shows up>
2 - press "Restart"

Expected outcome:
The device reboots

Actual outcome:
You see the dash being restarted behind the dialog and that's it.

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

1 - Launch an app or two
2 - go to the spread
3 - reveal the launcher
4 - tap on the ubuntu/dash icon

expected outcome:
Dash is focused

actual outcome:
Nothing happens

review: Needs Fixing
Michael Zanetti (mzanetti) wrote :

> Jouni says nothing should happen when you do a right-edge drag and there's no
> app running. That is, when you have just the dash).

This doesn't line up with an explicit request from Vesa to not have any difference on the behavior regardless of the amount of apps.

Daniel d'Andrada (dandrader) wrote :

> 1 - long press power button
> <shutdown dialog shows up>
> 2 - press "Restart"
>
> Expected outcome:
> The device reboots
>
> Actual outcome:
> You see the dash being restarted behind the dialog and that's it.

Hold on on that as it might be a general qtcomp issue :(

Michael Zanetti (mzanetti) wrote :

> """
> Q_SIGNALS:
> void setCurrentScope(const QString &scopeId, bool animate, bool reset);
> """
>
> Naming signals like functions is never a good thing. I would make an effort to
> name it like a signal. "requestedScopeAsCurrent" or even
> "setCurrentScopeCalled" would do it.

fixed

Michael Zanetti (mzanetti) wrote :

> """
> Q_SIGNALS:
> void setCurrentScope(const QString &scopeId, bool animate, bool reset);
> """
>
> Naming signals like functions is never a good thing. I would make an effort to
> name it like a signal. "requestedScopeAsCurrent" or even
> "setCurrentScopeCalled" would do it.

fixed

Michael Zanetti (mzanetti) wrote :

> 1 - Launch an app or two
> 2 - go to the spread
> 3 - reveal the launcher
> 4 - tap on the ubuntu/dash icon
>
> expected outcome:
> Dash is focused
>
> actual outcome:
> Nothing happens

Hmm, this works fine for me on the phone and in testShell. Is there any log output when this issue happens for you?

Daniel d'Andrada (dandrader) wrote :

> > 1 - Launch an app or two
> > 2 - go to the spread
> > 3 - reveal the launcher
> > 4 - tap on the ubuntu/dash icon
> >
> > expected outcome:
> > Dash is focused
> >
> > actual outcome:
> > Nothing happens
>
> Hmm, this works fine for me on the phone and in testShell. Is there any log
> output when this issue happens for you?

It works if an app is the currently focused app but not if unity8-dash itself is the focused guy

- have some apps open
- go to dash
- right-edge to show spread
- left-edge to show launcher
- tap dash button

Daniel d'Andrada (dandrader) wrote :

Did you add a 0 bytes qml/Dash/graphics/phone/screenshots/dash.png?

It would be good to save some kilobytes by making unity8-dash@12.png 480 pixels wide like all other screenshots. Afterall they're used only in a rather small windows in the qml tests.

Daniel d'Andrada (dandrader) wrote :

> Did you add a 0 bytes qml/Dash/graphics/phone/screenshots/dash.png?
>
> It would be good to save some kilobytes by making unity8-dash@12.png 480
> pixels wide like all other screenshots. Afterall they're used only in a rather
> small windows in the qml tests.

Btw, you would have to rewrite history to fix that, as otherwise we would end up with two images in the bzr history (leading to slower "bzr branch" commands), defeating the idea.

Daniel d'Andrada (dandrader) wrote :

1 - have the greeter on (like turn the display off and on)
2 - do a full left-edge drag

expected outcome:
greeter goes away for goo

actual outcome:
greeter goes back into place

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

+++ qml/Stages/PhoneStage.qml 2014-07-27 01:55:40 +0000
@@ -116,6 +117,8 @@ Item {
         contentWidth: spreadRow.width - shift
         contentX: -shift

+ readonly property bool isActive: shiftedContentX > 0 || spreadDragArea.dragging
+
         // The flickable needs to fill the screen in order to get touch events all over.
         // However, we don't want to the user to be able to scroll back all the way. For
         // that, the beginning of the gesture starts with a negative value for contentX

In QML (unlike in C++) boolean properties are named simply "foo", not "isFoo". I would choose a less overloaded/generic term than "active" if possible. What's the difference between being "active" and being "interactive". I would add a comment explaining what it means to be "active" there.

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

> +++ qml/Stages/PhoneStage.qml 2014-07-27 01:55:40 +0000
> @@ -116,6 +117,8 @@ Item {
> contentWidth: spreadRow.width - shift
> contentX: -shift
>
> + readonly property bool isActive: shiftedContentX > 0 ||
> spreadDragArea.dragging
> +
> // The flickable needs to fill the screen in order to get touch
> events all over.
> // However, we don't want to the user to be able to scroll back all
> the way. For
> // that, the beginning of the gesture starts with a negative value
> for contentX
>
>
> In QML (unlike in C++) boolean properties are named simply "foo", not "isFoo".
> I would choose a less overloaded/generic term than "active" if possible.
> What's the difference between being "active" and being "interactive". I would
> add a comment explaining what it means to be "active" there.

Which doesn't apply here as "Dash" is not an adjective.

+ readonly property bool isDash: model.appId == "unity8-dash"

Daniel d'Andrada (dandrader) wrote :

In SpreadDelegate.qml:
+ if (model.appId == "unity8-dash") {

That messes up with encapsulation. You should declare it a as SpreadDelegate property and fill it up in PhoneStage instead.

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

+ onIsActiveChanged: print("spreadView isActive changed", isActive)

Debug stuff in TabletStage.

review: Needs Fixing
Michael Zanetti (mzanetti) wrote :

> > Did you add a 0 bytes qml/Dash/graphics/phone/screenshots/dash.png?
> >
> > It would be good to save some kilobytes by making unity8-dash@12.png 480
> > pixels wide like all other screenshots. Afterall they're used only in a
> rather
> > small windows in the qml tests.
>
> Btw, you would have to rewrite history to fix that, as otherwise we would end
> up with two images in the bzr history (leading to slower "bzr branch"
> commands), defeating the idea.

fixed

Michael Zanetti (mzanetti) wrote :

> 1 - have the greeter on (like turn the display off and on)
> 2 - do a full left-edge drag
>
> expected outcome:
> greeter goes away for goo
>
> actual outcome:
> greeter goes back into place

fixed

Michael Zanetti (mzanetti) wrote :

> +++ qml/Stages/PhoneStage.qml 2014-07-27 01:55:40 +0000
> @@ -116,6 +117,8 @@ Item {
> contentWidth: spreadRow.width - shift
> contentX: -shift
>
> + readonly property bool isActive: shiftedContentX > 0 ||
> spreadDragArea.dragging
> +
> // The flickable needs to fill the screen in order to get touch
> events all over.
> // However, we don't want to the user to be able to scroll back all
> the way. For
> // that, the beginning of the gesture starts with a negative value
> for contentX
>
>
> In QML (unlike in C++) boolean properties are named simply "foo", not "isFoo".
> I would choose a less overloaded/generic term than "active" if possible.
> What's the difference between being "active" and being "interactive". I would
> add a comment explaining what it means to be "active" there.

I added a comment. I tend to agree that the "is*" is quite uncommon for qml, however, as you realized yourself just "active" is a bit overloaded and I think isActive describes best what's happening. I kept the name but added a comment what it does.

Michael Zanetti (mzanetti) wrote :

> In SpreadDelegate.qml:
> + if (model.appId == "unity8-dash") {
>
> That messes up with encapsulation. You should declare it a as SpreadDelegate
> property and fill it up in PhoneStage instead.

Well, its a "Delegate" so imo fine that it accesses model.* stuff. Also, there's quite a lot of other places where we access model.* stuff, fir instance model.surface.

Maybe this file could be split at some point to be a SpreadDelegate handling the model.stuff and then move the SurfaceContainer into a separate file that doesn't know anything about the model any more. IMO out of scope of this MP though.

Michael Zanetti (mzanetti) wrote :

> + onIsActiveChanged: print("spreadView isActive changed", isActive)
>
> Debug stuff in TabletStage.

fixed

Michael Zanetti (mzanetti) wrote :

> > > 1 - Launch an app or two
> > > 2 - go to the spread
> > > 3 - reveal the launcher
> > > 4 - tap on the ubuntu/dash icon
> > >
> > > expected outcome:
> > > Dash is focused
> > >
> > > actual outcome:
> > > Nothing happens
> >
> > Hmm, this works fine for me on the phone and in testShell. Is there any log
> > output when this issue happens for you?
>
> It works if an app is the currently focused app but not if unity8-dash itself
> is the focused guy
>
> - have some apps open
> - go to dash
> - right-edge to show spread
> - left-edge to show launcher
> - tap dash button

Fixed in here for the MockApplicationManager and fixed for qtmir in https://code.launchpad.net/~mzanetti/qtmir/always-forward-focus-requests/+merge/228659

Daniel d'Andrada (dandrader) wrote :

In PhoneStage:

+ // Hiding tiles when their progress is negative or reached the maximum
+ visible: (progress >= 0 && progress < 1.7) ||
+ (model.appId == "unity8-dash" && priv.focusedAppDelegate.x !== 0)

s/model.appId == "unity8-dash"/isDash

review: Needs Fixing
Daniel d'Andrada (dandrader) wrote :

> > In SpreadDelegate.qml:
> > + if (model.appId == "unity8-dash") {
> >
> > That messes up with encapsulation. You should declare it a as SpreadDelegate
> > property and fill it up in PhoneStage instead.
>
> Well, its a "Delegate" so imo fine that it accesses model.* stuff. Also,
> there's quite a lot of other places where we access model.* stuff, fir
> instance model.surface.

Makes it cumbersome at best to write a tst_SpreadDelegate for instance. But ok, I'm already changing that in the app lifecycle patch I'm working on top of yours so I can change that line there as well.

Michael Zanetti (mzanetti) wrote :

> In PhoneStage:
>
> + // Hiding tiles when their progress is negative or
> reached the maximum
> + visible: (progress >= 0 && progress < 1.7) ||
> + (model.appId == "unity8-dash" &&
> priv.focusedAppDelegate.x !== 0)
>
> s/model.appId == "unity8-dash"/isDash

fixed

Daniel d'Andrada (dandrader) wrote :

Looking good.
Thanks!

review: Approve
Michał Sawicz (saviq) wrote :

FWIW, run_on_device will get quite broken with this. We need a think whether we can fix it quickly or do we need to leave it for later.

Michał Sawicz (saviq) wrote :

Failure in qmltests:

qml/Dash/Dash.qml:35:9: Cannot assign to non-existent property "onSetCurrentScopeRequested"

review: Needs Fixing
lp:~unity-team/unity8/dash-as-app updated on 2014-08-05
1109. By Daniel d'Andrada on 2014-08-05

Merge trunk

[ Gerry Boland ]
* Fix the run.sh script - pretend to be running with qtmir and emit
  SIGSTOP at the right time
[ Ying-Chun Liu ]
* Implement Attribute UI. (LP: #1282460)
[ Albert Astals ]
* Hide search history popup as soon as you start typing As discussed
  with Mike and Saviq
* Compile with for scopes-v3 unity-api
* PageHeader: Unfocus search field when search entry is selected
* Show search field if the search query changes
* Test: Add a condition for art.height being > 0 means stuff has
  already been layouted a bit without it it can happen that we get 0
  for everything at startup and tests still pass
* Remove leftover in test of an old headerless implementation
[ Michael Zanetti ]
* Drop Recent apps category from Dash (LP: #1281092)
* update launcher count emblems to match new spec (LP: #1338984)
[ Bill Filler ]
* disable predictive text for dash search field (LP: #1340409)
[ CI bot ]
* Resync trunk
[ Antti Kaijanmäki ]
* DefaultIndicatorPage: use Loader status to determine the visible
  property. (LP: #1350555)
[ Michael Terry ]
* Check user's pin/password using PAM, instead of a plaintext keyfile.
  New build dependency: libpam0g-dev for phone unlock with PAM (LP:
  #1234983)
[ Ubuntu daily release ]
* New rebuild forced

1110. By Daniel d'Andrada on 2014-08-05

Update DashCommunicator mock plugin

Michał Sawicz (saviq) wrote :

All tests passed locally now.

review: Approve
Michał Sawicz (saviq) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes. Extensive testing in silo 7.

 * Did CI run pass? If not, please explain why.
No, ap failures fixed in the prerequisite branch and unrelated qmltests failures otherwise.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-06-11 15:36:51 +0000
3+++ CMakeLists.txt 2014-08-05 11:53:58 +0000
4@@ -96,6 +96,7 @@
5 declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
6
7 set(SHELL_APP unity8)
8+set(DASH_APP unity8-dash)
9 set(SCOPE_TOOL unity-scope-tool)
10
11 include_directories(
12
13=== modified file 'data/CMakeLists.txt'
14--- data/CMakeLists.txt 2014-06-11 15:36:51 +0000
15+++ data/CMakeLists.txt 2014-08-05 11:53:58 +0000
16@@ -1,7 +1,10 @@
17-# generate desktop file
18+# generate desktop files
19 configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
20+configure_file(${DASH_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${DASH_APP}.desktop @ONLY)
21
22 # install desktop files
23-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
24+install(FILES
25+ ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
26+ ${CMAKE_CURRENT_BINARY_DIR}/${DASH_APP}.desktop
27 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
28 )
29
30=== added file 'data/unity8-dash.conf'
31--- data/unity8-dash.conf 1970-01-01 00:00:00 +0000
32+++ data/unity8-dash.conf 2014-08-05 11:53:58 +0000
33@@ -0,0 +1,22 @@
34+description "Unity Shell v8 Dash"
35+author "Michael Zanetti <michael.zanetti@canonical.com>"
36+
37+emits scope-ui-starting
38+
39+start on started unity8
40+stop on stopping unity8
41+
42+kill timeout 120
43+
44+respawn
45+
46+pre-start script
47+ if [ -z "$UNITY_SCOPES_LIST" ]; then
48+ # FIXME: remove once we have this in dconf
49+ initctl set-env UNITY_SCOPES_LIST="scopes;clickscope;musicaggregator;videoaggregator"
50+ fi
51+
52+ initctl emit scope-ui-starting
53+end script
54+
55+exec ${BINARY:-unity8-dash} $ARGS --desktop_file_hint=/usr/share/applications/unity8-dash.desktop
56
57=== added file 'data/unity8-dash.desktop.in'
58--- data/unity8-dash.desktop.in 1970-01-01 00:00:00 +0000
59+++ data/unity8-dash.desktop.in 2014-08-05 11:53:58 +0000
60@@ -0,0 +1,9 @@
61+[Desktop Entry]
62+Type=Application
63+Name=Unity 8 Dash
64+Comment=The converged Unity shell dash
65+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity8-dash
66+Terminal=false
67+Icon=unity8
68+NoDisplay=true
69+X-Ubuntu-Touch=true
70
71=== modified file 'data/unity8.conf'
72--- data/unity8.conf 2014-07-18 16:40:56 +0000
73+++ data/unity8.conf 2014-08-05 11:53:58 +0000
74@@ -1,7 +1,7 @@
75 description "Unity Shell v8"
76 author "Ricardo Mendoza <ricmm@ubuntu.com>"
77
78-emits scope-ui-starting indicator-services-start
79+emits indicator-services-start
80
81 start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=ubuntu-touch-surfaceflinger)) and started dbus
82 stop on desktop-end
83@@ -34,11 +34,6 @@
84 gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
85 fi
86
87- if [ -z "$UNITY_SCOPES_LIST" ]; then
88- # FIXME: remove once we have this in dconf
89- initctl set-env UNITY_SCOPES_LIST="scopes;clickscope;musicaggregator;videoaggregator"
90- fi
91-
92 # Remove the socket if still there
93 if [ -S "$MIR_SERVER_FILE" ]; then
94 rm "$MIR_SERVER_FILE"
95@@ -46,7 +41,6 @@
96
97 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
98
99- initctl emit scope-ui-starting
100 initctl emit --no-wait indicator-services-start
101 end script
102
103
104=== modified file 'debian/unity8.install'
105--- debian/unity8.install 2014-07-08 18:53:52 +0000
106+++ debian/unity8.install 2014-08-05 11:53:58 +0000
107@@ -1,6 +1,9 @@
108 data/unity8.conf usr/share/upstart/sessions/
109+data/unity8-dash.conf usr/share/upstart/sessions/
110 usr/bin/unity8
111+usr/bin/unity8-dash
112 usr/share/applications/unity8.desktop
113+usr/share/applications/unity8-dash.desktop
114 usr/share/unity8/Greeter
115 usr/share/unity8/Hud
116 usr/share/unity8/Launcher
117
118=== modified file 'plugins/Unity/CMakeLists.txt'
119--- plugins/Unity/CMakeLists.txt 2014-07-08 19:09:35 +0000
120+++ plugins/Unity/CMakeLists.txt 2014-08-05 11:53:58 +0000
121@@ -1,3 +1,4 @@
122 add_subdirectory(Indicators)
123 add_subdirectory(Launcher)
124 add_subdirectory(Session)
125+add_subdirectory(DashCommunicator)
126
127=== added directory 'plugins/Unity/DashCommunicator'
128=== added file 'plugins/Unity/DashCommunicator/CMakeLists.txt'
129--- plugins/Unity/DashCommunicator/CMakeLists.txt 1970-01-01 00:00:00 +0000
130+++ plugins/Unity/DashCommunicator/CMakeLists.txt 2014-08-05 11:53:58 +0000
131@@ -0,0 +1,19 @@
132+include_directories(
133+ ${CMAKE_CURRENT_SOURCE_DIR}
134+)
135+
136+set(QMLDASHCOMMUNICATORPLUGIN_SRC
137+ plugin.cpp
138+ dbusdashcommunicatorservice.cpp
139+ dashcommunicatorservice.cpp
140+ dashcommunicator.cpp
141+ )
142+
143+add_library(DashCommunicator-qml MODULE
144+ ${QMLDASHCOMMUNICATORPLUGIN_SRC}
145+ )
146+
147+qt5_use_modules(DashCommunicator-qml DBus Qml)
148+
149+# export the qmldir and qmltypes files
150+add_unity8_plugin(Unity.DashCommunicator 0.1 Unity/DashCommunicator TARGETS DashCommunicator-qml)
151
152=== added file 'plugins/Unity/DashCommunicator/dashcommunicator.cpp'
153--- plugins/Unity/DashCommunicator/dashcommunicator.cpp 1970-01-01 00:00:00 +0000
154+++ plugins/Unity/DashCommunicator/dashcommunicator.cpp 2014-08-05 11:53:58 +0000
155@@ -0,0 +1,43 @@
156+/*
157+ * Copyright (C) 2014 Canonical, Ltd.
158+ *
159+ * This program is free software: you can redistribute it and/or modify it under
160+ * the terms of the GNU Lesser General Public License version 3, as published by
161+ * the Free Software Foundation.
162+ *
163+ * This program is distributed in the hope that it will be useful, but WITHOUT
164+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
165+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
166+ * Lesser General Public License for more details.
167+ *
168+ * You should have received a copy of the GNU Lesser General Public License
169+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
170+ */
171+
172+#include "dashcommunicator.h"
173+
174+#include <QObject>
175+#include <QDBusConnection>
176+#include <QDBusInterface>
177+#include <QDebug>
178+
179+DashCommunicator::DashCommunicator(QObject *parent):
180+ QObject(parent)
181+{
182+}
183+
184+DashCommunicator::~DashCommunicator()
185+{
186+}
187+
188+
189+void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, bool reset)
190+{
191+ QDBusConnection connection = QDBusConnection::sessionBus();
192+ QDBusInterface dashIface ("com.canonical.UnityDash",
193+ "/com/canonical/UnityDash",
194+ "",
195+ connection);
196+
197+ dashIface.call("SetCurrentScope", scopeId, animate, reset);
198+}
199
200=== added file 'plugins/Unity/DashCommunicator/dashcommunicator.h'
201--- plugins/Unity/DashCommunicator/dashcommunicator.h 1970-01-01 00:00:00 +0000
202+++ plugins/Unity/DashCommunicator/dashcommunicator.h 2014-08-05 11:53:58 +0000
203@@ -0,0 +1,35 @@
204+/*
205+ * Copyright (C) 2014 Canonical, Ltd.
206+ *
207+ * This program is free software: you can redistribute it and/or modify it under
208+ * the terms of the GNU Lesser General Public License version 3, as published by
209+ * the Free Software Foundation.
210+ *
211+ * This program is distributed in the hope that it will be useful, but WITHOUT
212+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
213+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
214+ * Lesser General Public License for more details.
215+ *
216+ * You should have received a copy of the GNU Lesser General Public License
217+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
218+ */
219+
220+#ifndef DASHCOMMUNICATOR_H
221+#define DASHCOMMUNICATOR_H
222+
223+#include <QObject>
224+
225+class DashCommunicator: public QObject
226+{
227+ Q_OBJECT
228+ Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.DashCommunicator")
229+
230+public:
231+ DashCommunicator(QObject *parent = 0);
232+ ~DashCommunicator();
233+
234+public Q_SLOTS:
235+ void setCurrentScope(const QString &scopeId, bool animate, bool reset);
236+};
237+
238+#endif
239
240=== added file 'plugins/Unity/DashCommunicator/dashcommunicatorservice.cpp'
241--- plugins/Unity/DashCommunicator/dashcommunicatorservice.cpp 1970-01-01 00:00:00 +0000
242+++ plugins/Unity/DashCommunicator/dashcommunicatorservice.cpp 2014-08-05 11:53:58 +0000
243@@ -0,0 +1,30 @@
244+/*
245+ * Copyright (C) 2014 Canonical, Ltd.
246+ *
247+ * This program is free software: you can redistribute it and/or modify it under
248+ * the terms of the GNU Lesser General Public License version 3, as published by
249+ * the Free Software Foundation.
250+ *
251+ * This program is distributed in the hope that it will be useful, but WITHOUT
252+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
253+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
254+ * Lesser General Public License for more details.
255+ *
256+ * You should have received a copy of the GNU Lesser General Public License
257+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
258+ */
259+
260+#include "dashcommunicatorservice.h"
261+
262+DashCommunicatorService::DashCommunicatorService(QObject *parent):
263+ QObject(parent),
264+ m_dbusService(new DBusDashCommunicatorService(this))
265+{
266+ connect(m_dbusService, &DBusDashCommunicatorService::setCurrentScopeRequested, this, &DashCommunicatorService::setCurrentScopeRequested);
267+}
268+
269+
270+DashCommunicatorService::~DashCommunicatorService()
271+{
272+
273+}
274
275=== added file 'plugins/Unity/DashCommunicator/dashcommunicatorservice.h'
276--- plugins/Unity/DashCommunicator/dashcommunicatorservice.h 1970-01-01 00:00:00 +0000
277+++ plugins/Unity/DashCommunicator/dashcommunicatorservice.h 2014-08-05 11:53:58 +0000
278@@ -0,0 +1,38 @@
279+/*
280+ * Copyright (C) 2014 Canonical, Ltd.
281+ *
282+ * This program is free software: you can redistribute it and/or modify it under
283+ * the terms of the GNU Lesser General Public License version 3, as published by
284+ * the Free Software Foundation.
285+ *
286+ * This program is distributed in the hope that it will be useful, but WITHOUT
287+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
288+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
289+ * Lesser General Public License for more details.
290+ *
291+ * You should have received a copy of the GNU Lesser General Public License
292+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
293+ */
294+
295+#ifndef DASHCOMMUNICATORSERVICE_H
296+#define DASHCOMMUNICATORSERVICE_H
297+
298+#include "dbusdashcommunicatorservice.h"
299+
300+#include <QObject>
301+
302+class DashCommunicatorService: public QObject
303+{
304+ Q_OBJECT
305+public:
306+ DashCommunicatorService(QObject *parent = 0);
307+ ~DashCommunicatorService();
308+
309+Q_SIGNALS:
310+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
311+
312+private:
313+ DBusDashCommunicatorService *m_dbusService;
314+};
315+
316+#endif // DBUSUNITYSESSIONSERVICE_H
317
318=== added file 'plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.cpp'
319--- plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.cpp 1970-01-01 00:00:00 +0000
320+++ plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.cpp 2014-08-05 11:53:58 +0000
321@@ -0,0 +1,39 @@
322+/*
323+ * Copyright (C) 2014 Canonical, Ltd.
324+ *
325+ * This program is free software: you can redistribute it and/or modify it under
326+ * the terms of the GNU Lesser General Public License version 3, as published by
327+ * the Free Software Foundation.
328+ *
329+ * This program is distributed in the hope that it will be useful, but WITHOUT
330+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
331+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
332+ * Lesser General Public License for more details.
333+ *
334+ * You should have received a copy of the GNU Lesser General Public License
335+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
336+ */
337+
338+#include "dbusdashcommunicatorservice.h"
339+
340+#include <QDBusConnection>
341+#include <QDBusInterface>
342+#include <QDebug>
343+
344+DBusDashCommunicatorService::DBusDashCommunicatorService(QObject *parent):
345+ QObject(parent)
346+{
347+ QDBusConnection connection = QDBusConnection::sessionBus();
348+
349+ connection.registerService("com.canonical.UnityDash");
350+ connection.registerObject("/com/canonical/UnityDash", this, QDBusConnection::ExportScriptableSlots);
351+}
352+
353+DBusDashCommunicatorService::~DBusDashCommunicatorService()
354+{
355+}
356+
357+void DBusDashCommunicatorService::SetCurrentScope(const QString &scopeId, bool animate, bool reset)
358+{
359+ Q_EMIT setCurrentScopeRequested(scopeId, animate, reset);
360+}
361
362=== added file 'plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.h'
363--- plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.h 1970-01-01 00:00:00 +0000
364+++ plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.h 2014-08-05 11:53:58 +0000
365@@ -0,0 +1,39 @@
366+/*
367+ * Copyright (C) 2014 Canonical, Ltd.
368+ *
369+ * This program is free software: you can redistribute it and/or modify it under
370+ * the terms of the GNU Lesser General Public License version 3, as published by
371+ * the Free Software Foundation.
372+ *
373+ * This program is distributed in the hope that it will be useful, but WITHOUT
374+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
375+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
376+ * Lesser General Public License for more details.
377+ *
378+ * You should have received a copy of the GNU Lesser General Public License
379+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
380+ */
381+
382+#ifndef DBUSDASHCOMMUNICATORSERVICE_H
383+#define DBUSDASHCOMMUNICATORSERVICE_H
384+
385+#include <QObject>
386+
387+class DBusDashCommunicatorService: public QObject
388+{
389+ Q_OBJECT
390+ Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.DashCommunicator")
391+
392+public:
393+ DBusDashCommunicatorService(QObject *parent = 0);
394+ ~DBusDashCommunicatorService();
395+
396+Q_SIGNALS:
397+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
398+
399+public Q_SLOTS:
400+ Q_SCRIPTABLE void SetCurrentScope(const QString &scopeId, bool animate, bool reset);
401+
402+};
403+
404+#endif // DBUSUNITYSESSIONSERVICE_H
405
406=== added file 'plugins/Unity/DashCommunicator/plugin.cpp'
407--- plugins/Unity/DashCommunicator/plugin.cpp 1970-01-01 00:00:00 +0000
408+++ plugins/Unity/DashCommunicator/plugin.cpp 2014-08-05 11:53:58 +0000
409@@ -0,0 +1,31 @@
410+/*
411+ * Copyright (C) 2014 Canonical, Ltd.
412+ *
413+ * This program is free software; you can redistribute it and/or modify
414+ * it under the terms of the GNU General Public License as published by
415+ * the Free Software Foundation; version 3.
416+ *
417+ * This program is distributed in the hope that it will be useful,
418+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
419+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
420+ * GNU General Public License for more details.
421+ *
422+ * You should have received a copy of the GNU General Public License
423+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
424+ *
425+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
426+ */
427+
428+#include "plugin.h"
429+#include "dashcommunicator.h"
430+#include "dashcommunicatorservice.h"
431+
432+#include <QDBusConnection>
433+#include <QtQml/qqml.h>
434+
435+void DashCommunicatorPlugin::registerTypes(const char *uri)
436+{
437+ Q_ASSERT(uri == QStringLiteral("Unity.DashCommunicator"));
438+ qmlRegisterType<DashCommunicatorService>(uri, 0, 1, "DashCommunicatorService");
439+ qmlRegisterType<DashCommunicator>(uri, 0, 1, "DashCommunicator");
440+}
441
442=== added file 'plugins/Unity/DashCommunicator/plugin.h'
443--- plugins/Unity/DashCommunicator/plugin.h 1970-01-01 00:00:00 +0000
444+++ plugins/Unity/DashCommunicator/plugin.h 2014-08-05 11:53:58 +0000
445@@ -0,0 +1,34 @@
446+/*
447+ * Copyright (C) 2014 Canonical, Ltd.
448+ *
449+ * This program is free software; you can redistribute it and/or modify
450+ * it under the terms of the GNU General Public License as published by
451+ * the Free Software Foundation; version 3.
452+ *
453+ * This program is distributed in the hope that it will be useful,
454+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
455+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
456+ * GNU General Public License for more details.
457+ *
458+ * You should have received a copy of the GNU General Public License
459+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
460+ *
461+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
462+ */
463+
464+#ifndef DASHCOMMUNICATOR_PLUGIN_H
465+#define DASHCOMMUNICATOR_PLUGIN_H
466+
467+#include <QtQml/QQmlEngine>
468+#include <QtQml/QQmlExtensionPlugin>
469+
470+class DashCommunicatorPlugin : public QQmlExtensionPlugin
471+{
472+ Q_OBJECT
473+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
474+
475+public:
476+ void registerTypes(const char *uri);
477+};
478+
479+#endif
480
481=== added file 'plugins/Unity/DashCommunicator/qmldir'
482--- plugins/Unity/DashCommunicator/qmldir 1970-01-01 00:00:00 +0000
483+++ plugins/Unity/DashCommunicator/qmldir 2014-08-05 11:53:58 +0000
484@@ -0,0 +1,3 @@
485+module Unity.DashCommunicator
486+plugin DashCommunicator-qml
487+typeinfo DashCommunicator.qmltypes
488
489=== modified file 'plugins/Unity/Launcher/launchermodel.cpp'
490--- plugins/Unity/Launcher/launchermodel.cpp 2014-07-25 11:29:56 +0000
491+++ plugins/Unity/Launcher/launchermodel.cpp 2014-08-05 11:53:58 +0000
492@@ -317,6 +317,11 @@
493 return;
494 }
495
496+ if (app->appId() == "unity8-dash") {
497+ // Not adding the dash app
498+ return;
499+ }
500+
501 bool found = false;
502 Q_FOREACH(LauncherItem *item, m_list) {
503 if (app->appId() == item->appId()) {
504
505=== modified file 'qml/Components/EdgeDemo.qml'
506--- qml/Components/EdgeDemo.qml 2014-06-11 15:36:51 +0000
507+++ qml/Components/EdgeDemo.qml 2014-08-05 11:53:58 +0000
508@@ -22,7 +22,6 @@
509 id: demo
510
511 property Item greeter
512- property Item dash
513 property Item launcher
514 property Item indicators
515 property Item underlay
516@@ -144,7 +143,7 @@
517 "edge": "top",
518 "title": i18n.tr("Top edge"),
519 "text": i18n.tr("Try swiping from the top edge to access the indicators"),
520- "anchors.fill": demo.dash,
521+ "anchors.fill": demo.underlay,
522 });
523 }
524 if (d.topEdgeDemo) {
525@@ -193,12 +192,12 @@
526 function startLeftEdgeDemo() {
527 demo.panelEnabled = false;
528 demo.launcherEnabled = true;
529- if (demo.dash && demo.underlay) {
530+ if (demo.underlay) {
531 d.leftEdgeDemo = d.overlay.createObject(demo.underlay, {
532 "edge": "left",
533 "title": i18n.tr("Left edge"),
534 "text": i18n.tr("Swipe from the left to reveal the launcher for quick access to apps"),
535- "anchors.fill": demo.dash,
536+ "anchors.fill": demo.underlay,
537 });
538 }
539 if (d.leftEdgeDemo) {
540@@ -221,12 +220,12 @@
541
542 function startFinalEdgeDemo() {
543 demo.launcherEnabled = false;
544- if (demo.dash && demo.underlay) {
545+ if (demo.underlay) {
546 d.finalEdgeDemo = d.overlay.createObject(demo.underlay, {
547 "edge": "none",
548 "title": i18n.tr("Well done"),
549 "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap on the screen to start"),
550- "anchors.fill": demo.dash,
551+ "anchors.fill": demo.underlay,
552 "showSkip": false,
553 });
554 }
555
556=== modified file 'qml/Dash/Dash.qml'
557--- qml/Dash/Dash.qml 2014-07-10 09:27:19 +0000
558+++ qml/Dash/Dash.qml 2014-08-05 11:53:58 +0000
559@@ -18,6 +18,7 @@
560 import Ubuntu.Components 0.1
561 import Unity 0.2
562 import Utils 0.1
563+import Unity.DashCommunicator 0.1
564 import "../Components"
565
566 Showable {
567@@ -29,6 +30,13 @@
568 property string showScopeOnLoaded: "clickscope"
569 property real contentScale: 1.0
570
571+ DashCommunicatorService {
572+ objectName: "dashCommunicatorService"
573+ onSetCurrentScopeRequested: {
574+ dash.setCurrentScope(scopeId, animate, reset)
575+ }
576+ }
577+
578 function setCurrentScope(scopeId, animate, reset) {
579 var scopeIndex = filteredScopes.findFirst(Scopes.RoleId, scopeId)
580
581
582=== added file 'qml/Dash/DashApplication.qml'
583--- qml/Dash/DashApplication.qml 1970-01-01 00:00:00 +0000
584+++ qml/Dash/DashApplication.qml 2014-08-05 11:53:58 +0000
585@@ -0,0 +1,29 @@
586+/*
587+ * Copyright (C) 2014 Canonical, Ltd.
588+ *
589+ * This program is free software; you can redistribute it and/or modify
590+ * it under the terms of the GNU General Public License as published by
591+ * the Free Software Foundation; version 3.
592+ *
593+ * This program is distributed in the hope that it will be useful,
594+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
595+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
596+ * GNU General Public License for more details.
597+ *
598+ * You should have received a copy of the GNU General Public License
599+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
600+ */
601+
602+import QtQuick 2.2
603+import Ubuntu.Components 1.0
604+
605+MainView {
606+ width: units.gu(40)
607+ height: units.gu(71)
608+
609+ useDeprecatedToolbar: false
610+
611+ Dash {
612+ anchors.fill: parent
613+ }
614+}
615
616=== modified file 'qml/Dash/GenericScopeView.qml'
617--- qml/Dash/GenericScopeView.qml 2014-07-25 11:49:28 +0000
618+++ qml/Dash/GenericScopeView.qml 2014-08-05 11:53:58 +0000
619@@ -46,7 +46,7 @@
620 }
621
622 function activateApp(appId) {
623- shell.activateApplication(appId);
624+ Qt.openUrlExternally(appId);
625 }
626
627 function positionAtBeginning() {
628
629=== modified file 'qml/Dash/ScopeListView.qml'
630--- qml/Dash/ScopeListView.qml 2014-06-11 15:36:51 +0000
631+++ qml/Dash/ScopeListView.qml 2014-08-05 11:53:58 +0000
632@@ -20,9 +20,4 @@
633 ListViewWithPageHeader {
634 maximumFlickVelocity: height * 10
635 flickDeceleration: height * 2
636-
637- Connections {
638- target: greeter
639- onShownChanged: if (greeter.shown) showHeader()
640- }
641 }
642
643=== added file 'qml/Dash/graphics/phone/screenshots/unity8-dash@12.png'
644Binary files qml/Dash/graphics/phone/screenshots/unity8-dash@12.png 1970-01-01 00:00:00 +0000 and qml/Dash/graphics/phone/screenshots/unity8-dash@12.png 2014-08-05 11:53:58 +0000 differ
645=== modified file 'qml/Launcher/Launcher.qml'
646--- qml/Launcher/Launcher.qml 2014-07-16 13:01:08 +0000
647+++ qml/Launcher/Launcher.qml 2014-08-05 11:53:58 +0000
648@@ -29,8 +29,7 @@
649 property int dragAreaWidth: units.gu(1)
650 property int minimizeDistance: units.gu(26)
651 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
652- (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) :
653- (dragArea.dragging ? 0.001 : 0)
654+ (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
655
656 readonly property bool shown: panel.x > -panel.width
657
658@@ -245,7 +244,7 @@
659 if (!dragging) {
660 if (distance > panel.width / 2) {
661 if (distance > minimizeDistance) {
662- root.dash()
663+ root.dash();
664 } else {
665 root.switchToNextState("visible")
666 }
667
668=== modified file 'qml/Shell.qml'
669--- qml/Shell.qml 2014-07-29 23:36:16 +0000
670+++ qml/Shell.qml 2014-08-05 11:53:58 +0000
671@@ -25,7 +25,6 @@
672 import LightDM 0.1 as LightDM
673 import Powerd 0.1
674 import SessionBroadcast 0.1
675-import "Dash"
676 import "Greeter"
677 import "Launcher"
678 import "Panel"
679@@ -34,6 +33,7 @@
680 import "Stages"
681 import Unity.Notifications 1.0 as NotificationBackend
682 import Unity.Session 0.1
683+import Unity.DashCommunicator 0.1
684
685 Item {
686 id: shell
687@@ -48,8 +48,6 @@
688 property url background
689 readonly property real panelHeight: panel.panelHeight
690
691- property bool dashShown: dash.shown && dash.available && underlay.visible
692-
693 property bool sideStageEnabled: shell.width >= units.gu(100)
694 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
695
696@@ -59,7 +57,6 @@
697 } else {
698 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
699 ApplicationManager.startApplication(appId, execFlags);
700- stages.show();
701 }
702 }
703
704@@ -86,6 +83,11 @@
705 id: volumeControl
706 }
707
708+ DashCommunicator {
709+ id: dash
710+ objectName: "dashCommunicator"
711+ }
712+
713 WindowKeysFilter {
714 // Handle but do not filter out volume keys
715 Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
716@@ -121,64 +123,12 @@
717 visible: !fullyCovered
718
719 Image {
720- anchors.fill: dash
721+ anchors.fill: underlay
722 source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
723 fillMode: Image.PreserveAspectCrop
724 horizontalAlignment: Image.AlignRight
725 verticalAlignment: Image.AlignTop
726 }
727-
728- Dash {
729- id: dash
730- objectName: "dash"
731-
732- available: !LightDM.Greeter.active
733- hides: [stages, launcher, panel.indicators]
734- shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0 &&
735- !(panel.indicators.fullyOpened && !sideStageEnabled)
736- enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
737-
738- anchors {
739- fill: parent
740- topMargin: panel.panelHeight
741- }
742-
743- contentScale: 1.0 - 0.2 * disappearingAnimationProgress
744- opacity: 1.0 - disappearingAnimationProgress
745- property real disappearingAnimationProgress: stages.showProgress
746-
747- // FIXME: only necessary because stages.showProgress is not animated
748- Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
749- }
750- }
751-
752- EdgeDragArea {
753- id: stagesDragArea
754- direction: Direction.Leftwards
755-
756- anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
757- width: shell.edgeSize
758-
759- property real progress: stages.width
760-
761- onTouchXChanged: {
762- if (status == DirectionalDragArea.Recognized) {
763- if (ApplicationManager.empty) {
764- progress = Math.max(stages.width - stagesDragArea.width + touchX, stages.width * .3);
765- } else {
766- progress = stages.width - stagesDragArea.width + touchX;
767- }
768- }
769- }
770-
771- onDraggingChanged: {
772- if (!dragging) {
773- if (!ApplicationManager.empty && progress < stages.width - units.gu(10)) {
774- stages.show();
775- }
776- stagesDragArea.progress = Qt.binding(function () { return stages.width; });
777- }
778- }
779 }
780
781 Item {
782@@ -186,55 +136,7 @@
783 objectName: "stages"
784 width: parent.width
785 height: parent.height
786-
787- visible: !fullyHidden && !ApplicationManager.empty
788-
789- x: {
790- if (shown) {
791- if (locked || greeter.fakeActiveForApp !== "") {
792- return 0;
793- }
794- return launcher.progress;
795- } else {
796- return stagesDragArea.progress
797- }
798- }
799- Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
800-
801- property bool shown: false
802- onShownChanged: {
803- if (shown) {
804- if (ApplicationManager.count > 0) {
805- ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
806- }
807- } else {
808- if (ApplicationManager.focusedApplicationId) {
809- ApplicationManager.updateScreenshot(ApplicationManager.focusedApplicationId);
810- ApplicationManager.unfocusCurrentApplication();
811- }
812- }
813- }
814-
815- // Avoid a silent "divide by zero -> NaN" situation during init as shell.width will be
816- // zero. That breaks the property binding and the function won't be reevaluated once
817- // shell.width is set, with the NaN result staying there for good.
818- property real showProgress: shell.width ? MathUtils.clamp(1 - x / shell.width, 0, 1) : 0
819-
820- property bool fullyShown: x == 0
821- property bool fullyHidden: x == width
822-
823- property bool locked: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.locked : false
824-
825- // It might technically not be fullyShown but visually it just looks so.
826- property bool roughlyFullyShown: x >= 0 && x <= units.gu(1)
827-
828- function show() {
829- shown = true;
830- }
831-
832- function hide() {
833- shown = false;
834- }
835+ visible: !ApplicationManager.empty
836
837 Connections {
838 target: ApplicationManager
839@@ -243,7 +145,6 @@
840 lockscreen.show();
841 }
842 greeter.hide();
843- stages.show();
844 }
845
846 onFocusedApplicationIdChanged: {
847@@ -254,18 +155,9 @@
848 }
849
850 onApplicationAdded: {
851- if (greeter.shown) {
852+ if (greeter.shown && appId != "unity8-dash") {
853 greeter.hide();
854 }
855- if (!stages.shown) {
856- stages.show();
857- }
858- }
859-
860- onEmptyChanged: {
861- if (ApplicationManager.empty) {
862- stages.hide();
863- }
864 }
865 }
866
867@@ -294,14 +186,18 @@
868 Binding {
869 target: applicationsDisplayLoader.item
870 property: "interactive"
871- value: stages.roughlyFullyShown && !greeter.shown && !lockscreen.shown
872- && panel.indicators.fullyClosed
873+ value: !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
874 }
875 Binding {
876 target: applicationsDisplayLoader.item
877 property: "spreadEnabled"
878 value: greeter.fakeActiveForApp === "" // to support emergency dialer hack
879 }
880+ Binding {
881+ target: applicationsDisplayLoader.item
882+ property: "inverseProgress"
883+ value: launcher.progress
884+ }
885 }
886 }
887
888@@ -531,25 +427,20 @@
889
890 var animate = !LightDM.Greeter.active && !stages.shown
891 dash.setCurrentScope("clickscope", animate, false)
892- stages.hide()
893+ ApplicationManager.requestFocusApplication("unity8-dash")
894 }
895
896 function showDash() {
897 if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
898 return;
899 }
900-
901- if (!stages.locked) {
902- stages.hide();
903- launcher.fadeOut();
904- } else {
905- launcher.switchToNextState("visible");
906- }
907-
908 if (greeter.shown) {
909 greeter.hideRight();
910 launcher.fadeOut();
911 }
912+
913+ ApplicationManager.requestFocusApplication("unity8-dash")
914+ launcher.fadeOut();
915 }
916
917 Item {
918@@ -574,8 +465,8 @@
919 ApplicationManager.focusedApplicationId &&
920 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
921
922- fullscreenMode: (stages.roughlyFullyShown && topmostApplicationIsFullscreen
923- && !LightDM.Greeter.active) || greeter.fakeActiveForApp !== ""
924+ fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
925+ || greeter.fakeActiveForApp !== ""
926 }
927
928 Launcher {
929@@ -592,7 +483,11 @@
930
931 onShowDashHome: showHome()
932 onDash: showDash()
933- onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
934+ onDashSwipeChanged: {
935+ if (dashSwipe && ApplicationManager.focusedApplicationId !== "unity8-dash") {
936+ dash.setCurrentScope("clickscope", false, true)
937+ }
938+ }
939 onLauncherApplicationSelected: {
940 if (greeter.fakeActiveForApp !== "") {
941 lockscreen.show()
942@@ -684,7 +579,6 @@
943 z: alphaDisclaimerLabel.z + 10
944 greeter: greeter
945 launcher: launcher
946- dash: dash
947 indicators: panel.indicators
948 underlay: underlay
949 }
950
951=== modified file 'qml/Stages/PhoneStage.qml'
952--- qml/Stages/PhoneStage.qml 2014-07-22 15:16:32 +0000
953+++ qml/Stages/PhoneStage.qml 2014-08-05 11:53:58 +0000
954@@ -21,7 +21,7 @@
955 import Utils 0.1
956 import "../Components"
957
958-Item {
959+Rectangle {
960 id: root
961
962 // Controls to be set from outside
963@@ -29,9 +29,9 @@
964 property real maximizedAppTopMargin
965 property bool interactive
966 property bool spreadEnabled: true // If false, animations and right edge will be disabled
967+ property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
968
969- // State information propagated to the outside
970- readonly property bool locked: spreadView.phase == 2
971+ color: "black"
972
973 function select(appId) {
974 spreadView.snapTo(priv.indexOf(appId));
975@@ -43,6 +43,16 @@
976 spreadView.contentX = -spreadView.shift;
977 }
978
979+ onInverseProgressChanged: {
980+ if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
981+ // left edge drag released. Minimum distance is given by design.
982+ if (priv.oldInverseProgress > units.gu(22)) {
983+ ApplicationManager.focusApplication("unity8-dash");
984+ }
985+ }
986+ priv.oldInverseProgress = inverseProgress;
987+ }
988+
989 Connections {
990 target: ApplicationManager
991
992@@ -50,7 +60,7 @@
993 if (spreadView.phase > 0) {
994 spreadView.snapTo(priv.indexOf(appId));
995 } else {
996- priv.switchToApp(appId);
997+ ApplicationManager.focusApplication(appId);
998 }
999 }
1000
1001@@ -60,7 +70,7 @@
1002 } else {
1003 spreadView.phase = 0;
1004 spreadView.contentX = -spreadView.shift;
1005- priv.switchToApp(appId);
1006+ ApplicationManager.focusApplication(appId);
1007 }
1008 }
1009
1010@@ -79,15 +89,11 @@
1011
1012 property string focusedAppId: ApplicationManager.focusedApplicationId
1013 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
1014-
1015- function switchToApp(appId) {
1016- if (priv.focusedAppId) {
1017- spreadView.focusChanging = true;
1018- ApplicationManager.focusApplication(appId);
1019- } else {
1020- ApplicationManager.focusApplication(appId);
1021- }
1022- }
1023+ property var focusedAppDelegate: null
1024+
1025+ property real oldInverseProgress: 0
1026+
1027+ onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
1028
1029 function indexOf(appId) {
1030 for (var i = 0; i < ApplicationManager.count; i++) {
1031@@ -100,14 +106,6 @@
1032
1033 }
1034
1035- Rectangle {
1036- id: coverFlipBackground
1037- anchors.fill: parent
1038- color: "black"
1039- visible: spreadView.visible
1040- }
1041-
1042-
1043 Flickable {
1044 id: spreadView
1045 objectName: "spreadView"
1046@@ -116,6 +114,10 @@
1047 contentWidth: spreadRow.width - shift
1048 contentX: -shift
1049
1050+ // This indicates when the spreadView is active. That means, all the animations
1051+ // are activated and tiles need to line up for the spread.
1052+ readonly property bool active: shiftedContentX > 0 || spreadDragArea.dragging
1053+
1054 // The flickable needs to fill the screen in order to get touch events all over.
1055 // However, we don't want to the user to be able to scroll back all the way. For
1056 // that, the beginning of the gesture starts with a negative value for contentX
1057@@ -198,6 +200,12 @@
1058 snapAnimation.start();
1059 }
1060
1061+ // In case the ApplicationManager already holds an app when starting up we're missing animations
1062+ // Make sure we end up in the same state
1063+ Component.onCompleted: {
1064+ spreadView.contentX = -spreadView.shift
1065+ }
1066+
1067 SequentialAnimation {
1068 id: snapAnimation
1069 property int targetContentX: -spreadView.shift
1070@@ -260,14 +268,33 @@
1071 && spreadView.shiftedContentX === 0 && root.interactive && index === 0
1072 swipeToCloseEnabled: spreadView.interactive
1073 maximizedAppTopMargin: root.maximizedAppTopMargin
1074- dropShadow: spreadView.shiftedContentX > 0 || spreadDragArea.status == DirectionalDragArea.Undecided
1075-
1076- z: behavioredIndex
1077- x: index == 0 ? 0 : spreadView.width + (index - 1) * spreadView.tileDistance
1078+ dropShadow: spreadView.active ||
1079+ priv.focusedAppDelegate.x !== 0
1080+
1081+ readonly property bool isDash: model.appId == "unity8-dash"
1082+
1083+ z: isDash && !spreadView.active ? -1 : behavioredIndex
1084+
1085+ x: {
1086+ // focused app is always positioned at 0 except when following left edge drag
1087+ if (index == 0) {
1088+ if (!isDash && root.inverseProgress > 0) {
1089+ return root.inverseProgress;
1090+ }
1091+ return 0;
1092+ }
1093+ if (isDash && !spreadView.active && !spreadDragArea.dragging) {
1094+ return 0;
1095+ }
1096+
1097+ // Otherwise line up for the spread
1098+ return spreadView.width + (index - 1) * spreadView.tileDistance;
1099+ }
1100 property real behavioredIndex: index
1101 Behavior on behavioredIndex {
1102 enabled: spreadView.closingIndex >= 0
1103 UbuntuNumberAnimation {
1104+ id: appXAnimation
1105 onRunningChanged: {
1106 if (!running) {
1107 spreadView.closingIndex = -1;
1108@@ -277,11 +304,13 @@
1109 }
1110
1111 Behavior on x {
1112- enabled: spreadView.focusChanging && index == 0 && root.spreadEnabled
1113+ enabled: root.spreadEnabled &&
1114+ !spreadView.active &&
1115+ !snapAnimation.running
1116 UbuntuNumberAnimation {
1117 duration: UbuntuAnimation.FastDuration
1118 onRunningChanged: {
1119- if (!running) {
1120+ if (!running && root.inverseProgress == 0) {
1121 spreadView.focusChanging = false;
1122 }
1123 }
1124@@ -322,6 +351,10 @@
1125 return progress;
1126 }
1127
1128+ // Hiding tiles when their progress is negative or reached the maximum
1129+ visible: (progress >= 0 && progress < 1.7) ||
1130+ (isDash && priv.focusedAppDelegate.x !== 0)
1131+
1132 EasingCurve {
1133 id: snappingCurve
1134 type: EasingCurve.Linear
1135
1136=== modified file 'qml/Stages/SpreadDelegate.qml'
1137--- qml/Stages/SpreadDelegate.qml 2014-07-23 12:20:45 +0000
1138+++ qml/Stages/SpreadDelegate.qml 2014-08-05 11:53:58 +0000
1139@@ -37,6 +37,7 @@
1140
1141 SurfaceContainer {
1142 id: surfaceContainer
1143+ objectName: "surfaceContainer"
1144 anchors.fill: parent
1145 surface: model.surface
1146 property bool appHasCreatedASurface: false
1147@@ -172,6 +173,11 @@
1148 }
1149
1150 onDragEnd: {
1151+ if (model.appId == "unity8-dash") {
1152+ animation.animate("center")
1153+ return;
1154+ }
1155+
1156 // velocity and distance values specified by design prototype
1157 if ((dragVelocity < -units.gu(40) && distance < -units.gu(8)) || distance < -root.height / 2) {
1158 animation.animate("up")
1159
1160=== modified file 'qml/Stages/TabletStage.qml'
1161--- qml/Stages/TabletStage.qml 2014-07-21 08:05:38 +0000
1162+++ qml/Stages/TabletStage.qml 2014-08-05 11:53:58 +0000
1163@@ -21,10 +21,11 @@
1164 import Utils 0.1
1165 import "../Components"
1166
1167-Item {
1168+Rectangle {
1169 id: root
1170 objectName: "stages"
1171 anchors.fill: parent
1172+ color: "black"
1173
1174 // Controls to be set from outside
1175 property bool shown: false
1176@@ -32,9 +33,17 @@
1177 property int dragAreaWidth
1178 property real maximizedAppTopMargin
1179 property bool interactive
1180+ property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
1181
1182- // State information propagated to the outside
1183- readonly property bool locked: spreadView.phase == 2
1184+ onInverseProgressChanged: {
1185+ if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
1186+ // left edge drag released. Minimum distance is given by design.
1187+ if (priv.oldInverseProgress > units.gu(22)) {
1188+ ApplicationManager.focusApplication("unity8-dash");
1189+ }
1190+ }
1191+ priv.oldInverseProgress = inverseProgress;
1192+ }
1193
1194 QtObject {
1195 id: priv
1196@@ -49,6 +58,8 @@
1197 property string appId0
1198 property string appId1
1199
1200+ property int oldInverseProgress: 0
1201+
1202 onFocusedAppIdChanged: {
1203 if (priv.focusedAppId.length > 0) {
1204 var focusedApp = ApplicationManager.findApplication(focusedAppId);
1205@@ -107,16 +118,26 @@
1206 }
1207 }
1208
1209+ onApplicationAdded: {
1210+ if (spreadView.phase == 2) {
1211+ spreadView.snapTo(ApplicationManager.count - 1);
1212+ } else {
1213+ spreadView.phase = 0;
1214+ spreadView.contentX = -spreadView.shift;
1215+ ApplicationManager.focusApplication(appId);
1216+ }
1217+ }
1218+
1219 onApplicationRemoved: {
1220 if (priv.mainStageAppId == appId) {
1221- priv.mainStageAppId = "";
1222+ ApplicationManager.focusApplication("unity8-dash")
1223 }
1224 if (priv.sideStageAppId == appId) {
1225 priv.sideStageAppId = "";
1226 }
1227 if (ApplicationManager.count == 0) {
1228 spreadView.phase = 0;
1229- spreadView.contentX = 0;
1230+ spreadView.contentX = -spreadView.shift;
1231 }
1232 }
1233 }
1234@@ -124,13 +145,26 @@
1235 Flickable {
1236 id: spreadView
1237 anchors.fill: parent
1238- contentWidth: spreadRow.width
1239 interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) && draggedIndex == -1
1240+ contentWidth: spreadRow.width - shift
1241+ contentX: -shift
1242
1243 property int tileDistance: units.gu(20)
1244 property int sideStageWidth: units.gu(40)
1245 property bool sideStageVisible: priv.sideStageAppId
1246
1247+ // This indicates when the spreadView is active. That means, all the animations
1248+ // are activated and tiles need to line up for the spread.
1249+ readonly property bool active: shiftedContentX > 0 || spreadDragArea.dragging
1250+
1251+ // The flickable needs to fill the screen in order to get touch events all over.
1252+ // However, we don't want to the user to be able to scroll back all the way. For
1253+ // that, the beginning of the gesture starts with a negative value for contentX
1254+ // so the flickable wants to pull it into the view already. "shift" tunes the
1255+ // distance where to "lock" the content.
1256+ readonly property real shift: width / 2
1257+ readonly property real shiftedContentX: contentX + shift
1258+
1259 // Phase of the animation:
1260 // 0: Starting from right edge, a new app (index 1) comes in from the right
1261 // 1: The app has reached the first snap position.
1262@@ -168,6 +202,12 @@
1263 }
1264 }
1265
1266+ // In case the ApplicationManager already holds an app when starting up we're missing animations
1267+ // Make sure we end up in the same state
1268+ Component.onCompleted: {
1269+ spreadView.contentX = -spreadView.shift
1270+ }
1271+
1272 property int nextInStack: {
1273 switch (state) {
1274 case "main":
1275@@ -224,31 +264,31 @@
1276 return "empty";
1277 }
1278
1279- onContentXChanged: {
1280- if (spreadView.phase == 0 && spreadView.contentX > spreadView.width * spreadView.positionMarker2) {
1281+ onShiftedContentXChanged: {
1282+ if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {
1283 spreadView.phase = 1;
1284- } else if (spreadView.phase == 1 && spreadView.contentX > spreadView.width * spreadView.positionMarker4) {
1285+ } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {
1286 spreadView.phase = 2;
1287- } else if (spreadView.phase == 1 && spreadView.contentX < spreadView.width * spreadView.positionMarker2) {
1288+ } else if (spreadView.phase == 1 && spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) {
1289 spreadView.phase = 0;
1290 }
1291 }
1292
1293 function snap() {
1294- if (contentX < phase0Width) {
1295- snapAnimation.targetContentX = 0;
1296+ if (shiftedContentX < phase0Width) {
1297+ snapAnimation.targetContentX = -shift;
1298 snapAnimation.start();
1299- } else if (contentX < phase1Width) {
1300+ } else if (shiftedContentX < phase1Width) {
1301 snapTo(1);
1302 } else {
1303 // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
1304- snapAnimation.targetContentX = spreadView.width * spreadView.positionMarker4 + 1;
1305+ snapAnimation.targetContentX = spreadView.width * spreadView.positionMarker4 + 1 - shift;
1306 snapAnimation.start();
1307 }
1308 }
1309 function snapTo(index) {
1310 spreadView.selectedIndex = index;
1311- snapAnimation.targetContentX = 0;
1312+ snapAnimation.targetContentX = -shift;
1313 snapAnimation.start();
1314 }
1315
1316@@ -261,12 +301,12 @@
1317 return index;
1318 }
1319
1320- var isActive = app.appId == priv.mainStageAppId || app.appId == priv.sideStageAppId;
1321- if (isActive && app.stage == ApplicationInfoInterface.MainStage) {
1322+ var active = app.appId == priv.mainStageAppId || app.appId == priv.sideStageAppId;
1323+ if (active && app.stage == ApplicationInfoInterface.MainStage) {
1324 // if this app is active, and its the MainStage, always put it to index 0
1325 return 0;
1326 }
1327- if (isActive && app.stage == ApplicationInfoInterface.SideStage) {
1328+ if (active && app.stage == ApplicationInfoInterface.SideStage) {
1329 if (!priv.mainStageAppId) {
1330 // Only have SS apps running. Put the active one at 0
1331 return 0;
1332@@ -309,7 +349,7 @@
1333
1334 SequentialAnimation {
1335 id: snapAnimation
1336- property int targetContentX: 0
1337+ property int targetContentX: -spreadView.shift
1338
1339 UbuntuNumberAnimation {
1340 target: spreadView
1341@@ -325,15 +365,14 @@
1342 spreadView.selectedIndex = -1;
1343 ApplicationManager.focusApplication(ApplicationManager.get(newIndex).appId);
1344 spreadView.phase = 0;
1345- spreadView.contentX = 0;
1346+ spreadView.contentX = -spreadView.shift;
1347 }
1348 }
1349 }
1350 }
1351
1352- Rectangle {
1353+ Item {
1354 id: spreadRow
1355- color: "black"
1356 x: spreadView.contentX
1357 height: root.height
1358 width: spreadView.width + Math.max(spreadView.width, ApplicationManager.count * spreadView.tileDistance)
1359@@ -380,7 +419,7 @@
1360 MouseArea {
1361 id: sideStageDragHandleMouseArea
1362 anchors.fill: parent
1363- enabled: spreadView.contentX == 0
1364+ enabled: spreadView.shiftedContentX == 0
1365 property int startX
1366 property var gesturePoints: new Array()
1367
1368@@ -413,7 +452,7 @@
1369
1370 onRunningChanged: {
1371 if (!running) {
1372- sideStageDragHandle.dragging = false;;
1373+ sideStageDragHandle.dragging = false;
1374 }
1375 }
1376 }
1377@@ -427,17 +466,26 @@
1378 id: spreadTile
1379 height: spreadView.height
1380 width: model.stage == ApplicationInfoInterface.MainStage ? spreadView.width : spreadView.sideStageWidth
1381- x: spreadView.width
1382- z: spreadView.indexToZIndex(index)
1383 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
1384- zIndex: z
1385+ zIndex: spreadView.indexToZIndex(index)
1386 selected: spreadView.selectedIndex == index
1387 otherSelected: spreadView.selectedIndex >= 0 && !selected
1388 isInSideStage: priv.sideStageAppId == model.appId
1389 interactive: !spreadView.interactive && spreadView.phase === 0 && root.interactive
1390 swipeToCloseEnabled: spreadView.interactive
1391 maximizedAppTopMargin: root.maximizedAppTopMargin
1392- dropShadow: spreadView.contentX > 0 || spreadDragArea.status == DirectionalDragArea.Undecided
1393+ dragOffset: !isDash && model.appId == priv.mainStageAppId && root.inverseProgress > 0 ? root.inverseProgress : 0
1394+
1395+ readonly property bool isDash: model.appId == "unity8-dash"
1396+
1397+ // FIXME: A regular binding doesn't update any more after closing an app.
1398+ // Using a Binding for now.
1399+ Binding {
1400+ target: spreadTile
1401+ property: "z"
1402+ value: (!spreadView.active && isDash && !active) ? -1 : spreadTile.zIndex
1403+ }
1404+ x: spreadView.width
1405
1406 property real behavioredZIndex: zIndex
1407 Behavior on behavioredZIndex {
1408@@ -458,7 +506,7 @@
1409 }
1410
1411 progress: {
1412- var tileProgress = (spreadView.contentX - behavioredZIndex * spreadView.tileDistance) / spreadView.width;
1413+ var tileProgress = (spreadView.shiftedContentX - behavioredZIndex * spreadView.tileDistance) / spreadView.width;
1414 // Some tiles (nextInStack, active) need to move directly from the beginning, normalize progress to immediately start at 0
1415 if ((index == spreadView.nextInStack && spreadView.phase < 2) || (active && spreadView.phase < 1)) {
1416 tileProgress += behavioredZIndex * spreadView.tileDistance / spreadView.width;
1417@@ -481,11 +529,7 @@
1418
1419 onClicked: {
1420 if (spreadView.phase == 2) {
1421- if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) {
1422- spreadView.snapTo(index);
1423- } else {
1424- ApplicationManager.requestFocusApplication(ApplicationManager.get(index).appId);
1425- }
1426+ spreadView.snapTo(index);
1427 }
1428 }
1429
1430@@ -518,12 +562,12 @@
1431 onTouchXChanged: {
1432 if (!dragging) {
1433 spreadView.phase = 0;
1434- spreadView.contentX = 0;
1435+ spreadView.contentX = -spreadView.shift;
1436 }
1437
1438- if (attachedToView) {
1439- spreadView.contentX = -touchX + spreadDragArea.width;
1440- if (spreadView.contentX > spreadView.phase0Width + spreadView.phase1Width / 2) {
1441+ if (dragging && attachedToView) {
1442+ spreadView.contentX = -touchX + spreadDragArea.width - spreadView.shift;
1443+ if (spreadView.shiftedContentX > spreadView.phase0Width + spreadView.phase1Width / 2) {
1444 attachedToView = false;
1445 spreadView.snap();
1446 }
1447@@ -548,14 +592,14 @@
1448 var oneWayFlick = priv.evaluateOneWayFlick(gesturePoints);
1449 gesturePoints = [];
1450
1451- if (oneWayFlick && spreadView.contentX < spreadView.positionMarker1 * spreadView.width) {
1452+ if (oneWayFlick && spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) {
1453 // If it was a short one-way movement, do the Alt+Tab switch
1454 // no matter if we didn't cross positionMarker1 yet.
1455 spreadView.snapTo(spreadView.nextInStack);
1456 } else if (!dragging && attachedToView) {
1457- if (spreadView.contentX < spreadView.width * spreadView.positionMarker1) {
1458+ if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker1) {
1459 spreadView.snap();
1460- } else if (spreadView.contentX < spreadView.width * spreadView.positionMarker2) {
1461+ } else if (spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) {
1462 spreadView.snapTo(spreadView.nextInStack);
1463 } else {
1464 // otherwise snap to the closest snap position we can find
1465
1466=== modified file 'qml/Stages/TransformedSpreadDelegate.qml'
1467--- qml/Stages/TransformedSpreadDelegate.qml 2014-07-21 08:13:44 +0000
1468+++ qml/Stages/TransformedSpreadDelegate.qml 2014-08-05 11:53:58 +0000
1469@@ -46,9 +46,6 @@
1470 property real startDistance: units.gu(5)
1471 property real endDistance: units.gu(.5)
1472
1473- // Hiding tiles when their progress is negative or reached the maximum
1474- visible: progress >= 0 && progress < 1.7
1475-
1476 onSelectedChanged: {
1477 if (selected) {
1478 priv.snapshot();
1479@@ -132,6 +129,10 @@
1480 // the selected tile, which is animated from the snapshotted position to be fullscreen.
1481
1482 readonly property real xTranslate: {
1483+ if (!spreadView.active) {
1484+ return 0;
1485+ }
1486+
1487 if (otherSelected) {
1488 if (spreadView.phase < 2 && index == 0) {
1489 return linearAnimation(selectedProgress, 0, selectedXTranslate,
1490@@ -183,7 +184,7 @@
1491 }
1492
1493 readonly property real angle: {
1494- if (spreadView.focusChanging) {
1495+ if (!spreadView.active) {
1496 return 0;
1497 }
1498
1499@@ -216,7 +217,7 @@
1500 }
1501
1502 readonly property real scale: {
1503- if (spreadView.focusChanging) {
1504+ if (!spreadView.active) {
1505 return 1;
1506 }
1507 if (priv.otherSelected) {
1508
1509=== modified file 'qml/Stages/TransformedTabletSpreadDelegate.qml'
1510--- qml/Stages/TransformedTabletSpreadDelegate.qml 2014-07-21 08:17:07 +0000
1511+++ qml/Stages/TransformedTabletSpreadDelegate.qml 2014-08-05 11:53:58 +0000
1512@@ -47,6 +47,11 @@
1513
1514 property bool isInSideStage: false
1515
1516+ property int dragOffset: 0
1517+
1518+ dropShadow: spreadView.active ||
1519+ (active && model.stage == ApplicationInfoInterface.MainStage && priv.xTranslate != 0)
1520+
1521 onSelectedChanged: {
1522 if (selected) {
1523 priv.snapshot();
1524@@ -129,6 +134,16 @@
1525 return helperEasingCurve.value * (endValue - startValue) + startValue;
1526 }
1527
1528+ Behavior on xTranslate {
1529+ enabled: !spreadView.active &&
1530+ !snapAnimation.running &&
1531+ model.appId !== "unity8-dash" &&
1532+ !spreadView.sideStageDragging
1533+ UbuntuNumberAnimation {
1534+ duration: UbuntuAnimation.FastDuration
1535+ }
1536+ }
1537+
1538 property real xTranslate: {
1539 var newTranslate = 0;
1540
1541@@ -155,7 +170,12 @@
1542 if (spreadView.phase == 0 && shouldMoveAway) {
1543 newTranslate += linearAnimation(0, spreadView.positionMarker2, 0, -units.gu(4), root.animatedProgress);
1544 }
1545- }
1546+ newTranslate += root.dragOffset;
1547+ }
1548+ if (!spreadView.active && model.appId == "unity8-dash" && !root.active) {
1549+ newTranslate -= root.width;
1550+ }
1551+
1552 if (nextInStack && spreadView.phase == 0) {
1553 if (model.stage == ApplicationInfoInterface.MainStage) {
1554 if (spreadView.sideStageVisible && root.progress > 0) {
1555@@ -205,6 +225,10 @@
1556 }
1557
1558 property real scale: {
1559+ if (!spreadView.active) {
1560+ return 1;
1561+ }
1562+
1563 if (otherSelected) {
1564 return selectedScale;
1565 }
1566@@ -249,6 +273,10 @@
1567 }
1568
1569 property real angle: {
1570+ if (!spreadView.active) {
1571+ return 0;
1572+ }
1573+
1574 if (otherSelected) {
1575 return selectedAngle;
1576 }
1577
1578=== modified file 'src/CMakeLists.txt'
1579--- src/CMakeLists.txt 2014-07-03 20:28:32 +0000
1580+++ src/CMakeLists.txt 2014-08-05 11:53:58 +0000
1581@@ -35,3 +35,4 @@
1582 )
1583
1584 add_subdirectory(Panel)
1585+add_subdirectory(Dash)
1586
1587=== added directory 'src/Dash'
1588=== added file 'src/Dash/CMakeLists.txt'
1589--- src/Dash/CMakeLists.txt 1970-01-01 00:00:00 +0000
1590+++ src/Dash/CMakeLists.txt 2014-08-05 11:53:58 +0000
1591@@ -0,0 +1,12 @@
1592+set(DASH_SRCS
1593+ main.cpp
1594+)
1595+
1596+add_executable(unity8-dash ${DASH_SRCS})
1597+
1598+qt5_use_modules(unity8-dash Gui Qml Quick Test)
1599+
1600+# install binaries
1601+install(TARGETS ${DASH_APP}
1602+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
1603+)
1604
1605=== added file 'src/Dash/main.cpp'
1606--- src/Dash/main.cpp 1970-01-01 00:00:00 +0000
1607+++ src/Dash/main.cpp 2014-08-05 11:53:58 +0000
1608@@ -0,0 +1,74 @@
1609+/*
1610+ * Copyright (C) 2014 Canonical, Ltd.
1611+ *
1612+ * Authors:
1613+ * Michael Zanetti <michael.zanetti@canonical.com>
1614+ *
1615+ * This program is free software; you can redistribute it and/or modify
1616+ * it under the terms of the GNU General Public License as published by
1617+ * the Free Software Foundation; version 3.
1618+ *
1619+ * This program is distributed in the hope that it will be useful,
1620+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1621+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1622+ * GNU General Public License for more details.
1623+ *
1624+ * You should have received a copy of the GNU General Public License
1625+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1626+ */
1627+
1628+#include <QtQuick/QQuickView>
1629+#include <QtGui/QGuiApplication>
1630+#include <QtQml/QQmlEngine>
1631+#include <QtQml/QQmlContext>
1632+#include <QDebug>
1633+#include <QCommandLineParser>
1634+#include <QLibrary>
1635+
1636+#include <paths.h>
1637+
1638+int main(int argc, const char *argv[])
1639+{
1640+ QGuiApplication *application = new QGuiApplication(argc, (char**)argv);
1641+
1642+ QCommandLineParser parser;
1643+ parser.setApplicationDescription("Description: Unity 8 Shell Dash");
1644+ parser.addHelpOption();
1645+
1646+ QCommandLineOption testabilityOption("testability",
1647+ "Load the testability driver (Alternatively export QT_LOAD_TESTABILITY");
1648+ parser.addOption(testabilityOption);
1649+
1650+ if (parser.isSet(testabilityOption) || getenv("QT_LOAD_TESTABILITY")) {
1651+ QLibrary testLib(QLatin1String("qttestability"));
1652+ if (testLib.load()) {
1653+ typedef void (*TasInitialize)(void);
1654+ TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
1655+ if (initFunction) {
1656+ initFunction();
1657+ } else {
1658+ qCritical("Library qttestability resolve failed!");
1659+ }
1660+ } else {
1661+ qCritical("Library qttestability load failed!");
1662+ }
1663+ }
1664+
1665+ QQuickView* view = new QQuickView();
1666+ view->setResizeMode(QQuickView::SizeRootObjectToView);
1667+ view->setTitle("Unity Dash");
1668+
1669+ QUrl source(::qmlDirectory()+"Dash/DashApplication.qml");
1670+ prependImportPaths(view->engine(), ::overrideImportPaths());
1671+ appendImportPaths(view->engine(), ::fallbackImportPaths());
1672+
1673+ view->setSource(source);
1674+ view->show();
1675+
1676+ int result = application->exec();
1677+
1678+ delete view;
1679+ delete application;
1680+
1681+ return result;
1682+}
1683
1684=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp'
1685--- tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-07-24 19:22:20 +0000
1686+++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-08-05 11:53:58 +0000
1687@@ -31,8 +31,6 @@
1688 , m_state(Starting)
1689 , m_focused(false)
1690 , m_fullscreen(false)
1691- , m_windowItem(0)
1692- , m_windowComponent(0)
1693 , m_parentItem(0)
1694 , m_surface(0)
1695 {
1696@@ -45,8 +43,6 @@
1697 , m_state(Starting)
1698 , m_focused(false)
1699 , m_fullscreen(false)
1700- , m_windowItem(0)
1701- , m_windowComponent(0)
1702 , m_parentItem(0)
1703 , m_surface(0)
1704 {
1705@@ -61,12 +57,6 @@
1706 }
1707 }
1708
1709-void ApplicationInfo::onWindowComponentStatusChanged(QQmlComponent::Status status)
1710-{
1711- if (status == QQmlComponent::Ready && !m_windowItem)
1712- doCreateWindowItem();
1713-}
1714-
1715 void ApplicationInfo::onStateChanged(State state)
1716 {
1717 if (state == ApplicationInfo::Running) {
1718@@ -108,55 +98,3 @@
1719 Q_EMIT surfaceChanged(m_surface);
1720 SurfaceManager::singleton()->registerSurface(m_surface);
1721 }
1722-
1723-void ApplicationInfo::createWindowComponent()
1724-{
1725- // The assumptions I make here really should hold.
1726- QQuickView *quickView =
1727- qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
1728-
1729- QQmlEngine *engine = quickView->engine();
1730-
1731- m_windowComponent = new QQmlComponent(engine, this);
1732- m_windowComponent->setData(m_windowQml.toLatin1(), QUrl());
1733-}
1734-
1735-void ApplicationInfo::doCreateWindowItem()
1736-{
1737- m_windowItem = qobject_cast<QQuickItem *>(m_windowComponent->create());
1738- m_windowItem->setParentItem(m_parentItem);
1739-}
1740-
1741-void ApplicationInfo::createWindowItem()
1742-{
1743- if (!m_windowComponent)
1744- createWindowComponent();
1745-
1746- // only create the windowItem once the component is ready
1747- if (!m_windowComponent->isReady()) {
1748- connect(m_windowComponent, &QQmlComponent::statusChanged,
1749- this, &ApplicationInfo::onWindowComponentStatusChanged);
1750- } else {
1751- doCreateWindowItem();
1752- }
1753-}
1754-
1755-void ApplicationInfo::showWindow(QQuickItem *parent)
1756-{
1757- m_parentItem = parent;
1758-
1759- if (!m_windowItem)
1760- createWindowItem();
1761-
1762- if (m_windowItem) {
1763- m_windowItem->setVisible(true);
1764- }
1765-}
1766-
1767-void ApplicationInfo::hideWindow()
1768-{
1769- if (!m_windowItem)
1770- return;
1771-
1772- m_windowItem->setVisible(false);
1773-}
1774
1775=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.h'
1776--- tests/mocks/Unity/Application/ApplicationInfo.h 2014-07-21 09:17:12 +0000
1777+++ tests/mocks/Unity/Application/ApplicationInfo.h 2014-08-05 11:53:58 +0000
1778@@ -88,22 +88,12 @@
1779 Q_SIGNALS:
1780 void surfaceChanged(MirSurfaceItem*);
1781
1782-public:
1783- void showWindow(QQuickItem *parent);
1784- void hideWindow();
1785-
1786 private Q_SLOTS:
1787- void onWindowComponentStatusChanged(QQmlComponent::Status status);
1788 void onStateChanged(State state);
1789
1790 void createSurface();
1791
1792 private:
1793- void createWindowItem();
1794- void doCreateWindowItem();
1795- void createWindowComponent();
1796- QQuickItem *m_windowItem;
1797- QQmlComponent *m_windowComponent;
1798 QQuickItem *m_parentItem;
1799 MirSurfaceItem* m_surface;
1800 };
1801
1802=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
1803--- tests/mocks/Unity/Application/ApplicationManager.cpp 2014-07-24 19:22:20 +0000
1804+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2014-08-05 11:53:58 +0000
1805@@ -48,16 +48,14 @@
1806 ApplicationManager::ApplicationManager(QObject *parent)
1807 : ApplicationManagerInterface(parent)
1808 , m_suspended(false)
1809- , m_mainStageComponent(0)
1810- , m_mainStage(0)
1811- , m_sideStageComponent(0)
1812- , m_sideStage(0)
1813- , m_rightMargin(0)
1814 {
1815 m_roleNames.insert(RoleSurface, "surface");
1816 m_roleNames.insert(RoleFullscreen, "fullscreen");
1817
1818 buildListOfAvailableApplications();
1819+
1820+ startApplication("unity8-dash");
1821+ focusApplication("unity8-dash");
1822 }
1823
1824 ApplicationManager::~ApplicationManager()
1825@@ -136,7 +134,6 @@
1826 Q_EMIT applicationAdded(application->appId());
1827 Q_EMIT countChanged();
1828 if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
1829- Q_EMIT focusRequested(application->appId());
1830
1831 connect(application, &ApplicationInfo::surfaceChanged, this, [application, this]() {
1832 QModelIndex appIndex = findIndex(application);
1833@@ -222,6 +219,10 @@
1834
1835 bool ApplicationManager::stopApplication(const QString &appId)
1836 {
1837+ if (appId == "unity8-dash") {
1838+ return false;
1839+ }
1840+
1841 ApplicationInfo *application = findApplication(appId);
1842 if (application == nullptr)
1843 return false;
1844@@ -294,39 +295,25 @@
1845 for (ApplicationInfo *app : m_runningApplications) {
1846 if (app->focused() && app->stage() == ApplicationInfo::MainStage) {
1847 app->setFocused(false);
1848- app->hideWindow();
1849 app->setState(ApplicationInfo::Suspended);
1850 }
1851 }
1852
1853 // focus this app
1854 application->setFocused(true);
1855- if (!m_mainStage)
1856- createMainStage();
1857 application->setState(ApplicationInfo::Running);
1858- application->showWindow(m_mainStage);
1859- m_mainStage->setZ(-1000);
1860- if (m_sideStage)
1861- m_sideStage->setZ(-2000);
1862 } else if (application->stage() == ApplicationInfo::SideStage) {
1863 // unfocus currently focused sidestage app
1864 for (ApplicationInfo *app : m_runningApplications) {
1865 if (app->focused() && app->stage() == ApplicationInfo::SideStage) {
1866 app->setFocused(false);
1867- app->hideWindow();
1868 app->setState(ApplicationInfo::Suspended);
1869 }
1870 }
1871
1872 // focus this app
1873 application->setFocused(true);
1874- if (!m_sideStage)
1875- createSideStage();
1876 application->setState(ApplicationInfo::Running);
1877- application->showWindow(m_sideStage);
1878- m_sideStage->setZ(-1000);
1879- if (m_mainStage)
1880- m_mainStage->setZ(-2000);
1881 }
1882
1883 // move app to top of stack
1884@@ -337,18 +324,14 @@
1885
1886 bool ApplicationManager::requestFocusApplication(const QString &appId)
1887 {
1888- if (appId != focusedApplicationId()) {
1889- QMetaObject::invokeMethod(this, "focusRequested", Qt::QueuedConnection, Q_ARG(QString, appId));
1890- return true;
1891- }
1892- return false;
1893+ QMetaObject::invokeMethod(this, "focusRequested", Qt::QueuedConnection, Q_ARG(QString, appId));
1894+ return true;
1895 }
1896
1897 void ApplicationManager::unfocusCurrentApplication()
1898 {
1899 for (ApplicationInfo *app : m_runningApplications) {
1900 if (app->focused()) {
1901- app->hideWindow();
1902 app->setFocused(false);
1903 }
1904 }
1905@@ -357,42 +340,6 @@
1906
1907 void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
1908 {
1909- // TODO: Is there a better way of solving this fullscreen vs. regular
1910- // application height?
1911- QString topMargin;
1912- if (application->fullscreen()) {
1913- topMargin.append("0");
1914- } else {
1915- // Taken from Panel.panelHeight
1916- topMargin.append("units.gu(3) + units.dp(2)");
1917- }
1918-
1919- QString windowQml = QString(
1920- "import QtQuick 2.0\n"
1921- "Image {\n"
1922- " anchors.fill: parent\n"
1923- " anchors.topMargin: %1\n"
1924- " anchors.rightMargin: %2\n"
1925- " source: \"file://%3/Dash/graphics/phone/screenshots/%4.png\"\n"
1926- " smooth: true\n"
1927- " fillMode: Image.PreserveAspectCrop\n"
1928- "}").arg(topMargin)
1929- .arg(m_rightMargin)
1930- .arg(qmlDirectory())
1931- .arg(application->icon().toString());
1932- application->setWindowQml(windowQml);
1933-
1934- QString imageQml = QString(
1935- "import QtQuick 2.0\n"
1936- "Image {\n"
1937- " anchors.fill: parent\n"
1938- " source: \"file://%1/Dash/graphics/phone/screenshots/%2.png\"\n"
1939- " smooth: true\n"
1940- " fillMode: Image.PreserveAspectCrop\n"
1941- "}").arg(qmlDirectory())
1942- .arg(application->icon().toString());
1943- application->setImageQml(imageQml);
1944-
1945 application->setScreenshot(QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory())
1946 .arg(application->icon().toString()));
1947 }
1948@@ -402,6 +349,14 @@
1949 ApplicationInfo *application;
1950
1951 application = new ApplicationInfo(this);
1952+ application->setAppId("unity8-dash");
1953+ application->setName("Unity 8 Mock Dash");
1954+ application->setIcon(QUrl("unity8-dash"));
1955+ application->setStage(ApplicationInfo::MainStage);
1956+ generateQmlStrings(application);
1957+ m_availableApplications.append(application);
1958+
1959+ application = new ApplicationInfo(this);
1960 application->setAppId("dialer-app");
1961 application->setName("Dialer");
1962 application->setIcon(QUrl("dialer"));
1963@@ -521,78 +476,6 @@
1964 m_availableApplications.append(application);
1965 }
1966
1967-void ApplicationManager::createMainStageComponent()
1968-{
1969- // The assumptions I make here really should hold.
1970- QQuickView *quickView =
1971- qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
1972-
1973- QQmlEngine *engine = quickView->engine();
1974-
1975- m_mainStageComponent = new QQmlComponent(engine, this);
1976- QString mainStageQml =
1977- "import QtQuick 2.0\n"
1978- "Rectangle {\n"
1979- " anchors.fill: parent\n"
1980- " color: 'black'\n"
1981- " z: -2000\n"
1982- "}\n";
1983- m_mainStageComponent->setData(mainStageQml.toLatin1(), QUrl());
1984-}
1985-
1986-void ApplicationManager::createMainStage()
1987-{
1988- if (!m_mainStageComponent)
1989- createMainStageComponent();
1990-
1991- // The assumptions I make here really should hold.
1992- QQuickView *quickView =
1993- qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
1994-
1995- QQuickItem *shell = quickView->rootObject();
1996-
1997- m_mainStage = qobject_cast<QQuickItem *>(m_mainStageComponent->create());
1998- m_mainStage->setParentItem(shell);
1999-}
2000-
2001-void ApplicationManager::createSideStageComponent()
2002-{
2003- // The assumptions I make here really should hold.
2004- QQuickView *quickView =
2005- qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
2006-
2007- QQmlEngine *engine = quickView->engine();
2008-
2009- m_sideStageComponent = new QQmlComponent(engine, this);
2010- QString sideStageQml =
2011- "import QtQuick 2.0\n"
2012- "import Ubuntu.Components 0.1\n"
2013- "Item {\n"
2014- " width: units.gu(40)\n" // from SideStage in Shell.qml
2015- " anchors.top: parent.top\n"
2016- " anchors.bottom: parent.bottom\n"
2017- " anchors.right: parent.right\n"
2018- " z: -1000\n"
2019- "}\n";
2020- m_sideStageComponent->setData(sideStageQml.toLatin1(), QUrl());
2021-}
2022-
2023-void ApplicationManager::createSideStage()
2024-{
2025- if (!m_sideStageComponent)
2026- createSideStageComponent();
2027-
2028- // The assumptions I make here really should hold.
2029- QQuickView *quickView =
2030- qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
2031-
2032- QQuickItem *shell = quickView->rootObject();
2033-
2034- m_sideStage = qobject_cast<QQuickItem *>(m_sideStageComponent->create());
2035- m_sideStage->setParentItem(shell);
2036- m_sideStage->setFlag(QQuickItem::ItemHasContents, false);
2037-}
2038-
2039 QStringList ApplicationManager::availableApplications()
2040 {
2041 QStringList appIds;
2042@@ -602,19 +485,6 @@
2043 return appIds;
2044 }
2045
2046-int ApplicationManager::rightMargin() const
2047-{
2048- return m_rightMargin;
2049-}
2050-
2051-void ApplicationManager::setRightMargin(int rightMargin)
2052-{
2053- m_rightMargin = rightMargin;
2054- Q_FOREACH(ApplicationInfo *app, m_availableApplications) {
2055- generateQmlStrings(app);
2056- }
2057-}
2058-
2059 bool ApplicationManager::isEmpty() const
2060 {
2061 return m_runningApplications.isEmpty();
2062
2063=== modified file 'tests/mocks/Unity/Application/ApplicationManager.h'
2064--- tests/mocks/Unity/Application/ApplicationManager.h 2014-07-24 19:22:20 +0000
2065+++ tests/mocks/Unity/Application/ApplicationManager.h 2014-08-05 11:53:58 +0000
2066@@ -44,10 +44,6 @@
2067
2068 Q_PROPERTY(bool fake READ fake CONSTANT)
2069
2070- // Only for testing
2071- // This can be used to place some controls to right, like make tryPhoneStage for example
2072- Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin)
2073-
2074 public:
2075 ApplicationManager(QObject *parent = NULL);
2076 virtual ~ApplicationManager();
2077@@ -108,8 +104,6 @@
2078
2079 // Only for testing
2080 Q_INVOKABLE QStringList availableApplications();
2081- int rightMargin() const;
2082- void setRightMargin(int rightMargin);
2083
2084 QModelIndex findIndex(ApplicationInfo* application);
2085
2086@@ -126,19 +120,9 @@
2087 void showApplicationWindow(ApplicationInfo *application);
2088 void buildListOfAvailableApplications();
2089 void generateQmlStrings(ApplicationInfo *application);
2090- void createMainStageComponent();
2091- void createMainStage();
2092- void createSideStageComponent();
2093- void createSideStage();
2094 bool m_suspended;
2095 QList<ApplicationInfo*> m_runningApplications;
2096 QList<ApplicationInfo*> m_availableApplications;
2097- QQmlComponent *m_mainStageComponent;
2098- QQuickItem *m_mainStage;
2099- QQmlComponent *m_sideStageComponent;
2100- QQuickItem *m_sideStage;
2101-
2102- int m_rightMargin;
2103
2104 static ApplicationManager *the_application_manager;
2105 };
2106
2107=== modified file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp'
2108--- tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-04-02 15:33:33 +0000
2109+++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-08-05 11:53:58 +0000
2110@@ -64,7 +64,7 @@
2111 Q_FOREACH (QWindow *win, unity->allWindows()) {
2112 QQuickWindow *quickWin = qobject_cast<QQuickWindow*>(win);
2113 if (quickWin) {
2114- image = image.scaledToWidth(quickWin->width() - m_appManager->rightMargin());
2115+ image = image.scaledToWidth(quickWin->width());
2116 break;
2117 }
2118 }
2119
2120=== modified file 'tests/mocks/Unity/CMakeLists.txt'
2121--- tests/mocks/Unity/CMakeLists.txt 2014-07-25 13:25:45 +0000
2122+++ tests/mocks/Unity/CMakeLists.txt 2014-08-05 11:53:58 +0000
2123@@ -2,6 +2,7 @@
2124 add_subdirectory(Indicators)
2125 add_subdirectory(Launcher)
2126 add_subdirectory(Notifications)
2127+add_subdirectory(DashCommunicator)
2128
2129 pkg_search_module(DEE dee-1.0 REQUIRED)
2130 pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
2131
2132=== added directory 'tests/mocks/Unity/DashCommunicator'
2133=== added file 'tests/mocks/Unity/DashCommunicator/CMakeLists.txt'
2134--- tests/mocks/Unity/DashCommunicator/CMakeLists.txt 1970-01-01 00:00:00 +0000
2135+++ tests/mocks/Unity/DashCommunicator/CMakeLists.txt 2014-08-05 11:53:58 +0000
2136@@ -0,0 +1,18 @@
2137+include_directories(
2138+ ${CMAKE_CURRENT_SOURCE_DIR}
2139+)
2140+
2141+set(QMLDASHCOMMUNICATORPLUGIN_SRC
2142+ plugin.cpp
2143+ dashcommunicatorservice.cpp
2144+ dashcommunicator.cpp
2145+ )
2146+
2147+add_library(MockDashCommunicator-qml MODULE
2148+ ${QMLDASHCOMMUNICATORPLUGIN_SRC}
2149+ )
2150+
2151+qt5_use_modules(MockDashCommunicator-qml DBus Qml)
2152+
2153+# export the qmldir and qmltypes files
2154+add_unity8_mock(Unity.DashCommunicator 0.1 Unity/DashCommunicator TARGETS MockDashCommunicator-qml)
2155
2156=== added file 'tests/mocks/Unity/DashCommunicator/dashcommunicator.cpp'
2157--- tests/mocks/Unity/DashCommunicator/dashcommunicator.cpp 1970-01-01 00:00:00 +0000
2158+++ tests/mocks/Unity/DashCommunicator/dashcommunicator.cpp 2014-08-05 11:53:58 +0000
2159@@ -0,0 +1,37 @@
2160+/*
2161+ * Copyright (C) 2014 Canonical, Ltd.
2162+ *
2163+ * This program is free software: you can redistribute it and/or modify it under
2164+ * the terms of the GNU Lesser General Public License version 3, as published by
2165+ * the Free Software Foundation.
2166+ *
2167+ * This program is distributed in the hope that it will be useful, but WITHOUT
2168+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2169+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2170+ * Lesser General Public License for more details.
2171+ *
2172+ * You should have received a copy of the GNU Lesser General Public License
2173+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2174+ */
2175+
2176+#include "dashcommunicator.h"
2177+
2178+#include <QObject>
2179+#include <QDBusConnection>
2180+#include <QDBusInterface>
2181+#include <QDebug>
2182+
2183+DashCommunicator::DashCommunicator(QObject *parent):
2184+ QObject(parent)
2185+{
2186+}
2187+
2188+DashCommunicator::~DashCommunicator()
2189+{
2190+}
2191+
2192+
2193+void DashCommunicator::setCurrentScope(const QString &scopeId, bool animate, bool reset)
2194+{
2195+ Q_EMIT setCurrentScopeCalled(scopeId, animate, reset);
2196+}
2197
2198=== added file 'tests/mocks/Unity/DashCommunicator/dashcommunicator.h'
2199--- tests/mocks/Unity/DashCommunicator/dashcommunicator.h 1970-01-01 00:00:00 +0000
2200+++ tests/mocks/Unity/DashCommunicator/dashcommunicator.h 2014-08-05 11:53:58 +0000
2201@@ -0,0 +1,39 @@
2202+/*
2203+ * Copyright (C) 2014 Canonical, Ltd.
2204+ *
2205+ * This program is free software: you can redistribute it and/or modify it under
2206+ * the terms of the GNU Lesser General Public License version 3, as published by
2207+ * the Free Software Foundation.
2208+ *
2209+ * This program is distributed in the hope that it will be useful, but WITHOUT
2210+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2211+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2212+ * Lesser General Public License for more details.
2213+ *
2214+ * You should have received a copy of the GNU Lesser General Public License
2215+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2216+ */
2217+
2218+#ifndef DASHCOMMUNICATOR_H
2219+#define DASHCOMMUNICATOR_H
2220+
2221+#include <QObject>
2222+
2223+class DashCommunicator: public QObject
2224+{
2225+ Q_OBJECT
2226+ Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.DashCommunicator")
2227+
2228+public:
2229+ DashCommunicator(QObject *parent = 0);
2230+ ~DashCommunicator();
2231+
2232+public Q_SLOTS:
2233+ void setCurrentScope(const QString &scopeId, bool animate, bool reset);
2234+
2235+Q_SIGNALS:
2236+ // This mock just emits calls back to the QML api for the plugin to verify calls
2237+ void setCurrentScopeCalled(const QString &scopeId, bool animate, bool reset);
2238+};
2239+
2240+#endif
2241
2242=== added file 'tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.cpp'
2243--- tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.cpp 1970-01-01 00:00:00 +0000
2244+++ tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.cpp 2014-08-05 11:53:58 +0000
2245@@ -0,0 +1,33 @@
2246+/*
2247+ * Copyright (C) 2014 Canonical, Ltd.
2248+ *
2249+ * This program is free software: you can redistribute it and/or modify it under
2250+ * the terms of the GNU Lesser General Public License version 3, as published by
2251+ * the Free Software Foundation.
2252+ *
2253+ * This program is distributed in the hope that it will be useful, but WITHOUT
2254+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2255+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2256+ * Lesser General Public License for more details.
2257+ *
2258+ * You should have received a copy of the GNU Lesser General Public License
2259+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2260+ */
2261+
2262+#include "dashcommunicatorservice.h"
2263+
2264+DashCommunicatorService::DashCommunicatorService(QObject *parent):
2265+ QObject(parent)
2266+{
2267+}
2268+
2269+
2270+DashCommunicatorService::~DashCommunicatorService()
2271+{
2272+
2273+}
2274+
2275+void DashCommunicatorService::mockSetCurrentScope(const QString &scopeId, bool animate, bool reset)
2276+{
2277+ Q_EMIT setCurrentScopeRequested(scopeId, animate, reset);
2278+}
2279
2280=== added file 'tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.h'
2281--- tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.h 1970-01-01 00:00:00 +0000
2282+++ tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.h 2014-08-05 11:53:58 +0000
2283@@ -0,0 +1,36 @@
2284+/*
2285+ * Copyright (C) 2014 Canonical, Ltd.
2286+ *
2287+ * This program is free software: you can redistribute it and/or modify it under
2288+ * the terms of the GNU Lesser General Public License version 3, as published by
2289+ * the Free Software Foundation.
2290+ *
2291+ * This program is distributed in the hope that it will be useful, but WITHOUT
2292+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2293+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2294+ * Lesser General Public License for more details.
2295+ *
2296+ * You should have received a copy of the GNU Lesser General Public License
2297+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2298+ */
2299+
2300+#ifndef DASHCOMMUNICATORSERVICE_H
2301+#define DASHCOMMUNICATORSERVICE_H
2302+
2303+#include <QObject>
2304+
2305+class DashCommunicatorService: public QObject
2306+{
2307+ Q_OBJECT
2308+public:
2309+ DashCommunicatorService(QObject *parent = 0);
2310+ ~DashCommunicatorService();
2311+
2312+Q_SIGNALS:
2313+ void setCurrentScopeRequested(const QString &scopeId, bool animate, bool reset);
2314+
2315+public Q_SLOTS:
2316+ void mockSetCurrentScope(const QString &scopeId, bool animate, bool reset);
2317+};
2318+
2319+#endif // DBUSUNITYSESSIONSERVICE_H
2320
2321=== added file 'tests/mocks/Unity/DashCommunicator/plugin.cpp'
2322--- tests/mocks/Unity/DashCommunicator/plugin.cpp 1970-01-01 00:00:00 +0000
2323+++ tests/mocks/Unity/DashCommunicator/plugin.cpp 2014-08-05 11:53:58 +0000
2324@@ -0,0 +1,31 @@
2325+/*
2326+ * Copyright (C) 2014 Canonical, Ltd.
2327+ *
2328+ * This program is free software; you can redistribute it and/or modify
2329+ * it under the terms of the GNU General Public License as published by
2330+ * the Free Software Foundation; version 3.
2331+ *
2332+ * This program is distributed in the hope that it will be useful,
2333+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2334+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2335+ * GNU General Public License for more details.
2336+ *
2337+ * You should have received a copy of the GNU General Public License
2338+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2339+ *
2340+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
2341+ */
2342+
2343+#include "plugin.h"
2344+#include "dashcommunicator.h"
2345+#include "dashcommunicatorservice.h"
2346+
2347+#include <QDBusConnection>
2348+#include <QtQml/qqml.h>
2349+
2350+void DashCommunicatorPlugin::registerTypes(const char *uri)
2351+{
2352+ Q_ASSERT(uri == QStringLiteral("Unity.DashCommunicator"));
2353+ qmlRegisterType<DashCommunicatorService>(uri, 0, 1, "DashCommunicatorService");
2354+ qmlRegisterType<DashCommunicator>(uri, 0, 1, "DashCommunicator");
2355+}
2356
2357=== added file 'tests/mocks/Unity/DashCommunicator/plugin.h'
2358--- tests/mocks/Unity/DashCommunicator/plugin.h 1970-01-01 00:00:00 +0000
2359+++ tests/mocks/Unity/DashCommunicator/plugin.h 2014-08-05 11:53:58 +0000
2360@@ -0,0 +1,34 @@
2361+/*
2362+ * Copyright (C) 2014 Canonical, Ltd.
2363+ *
2364+ * This program is free software; you can redistribute it and/or modify
2365+ * it under the terms of the GNU General Public License as published by
2366+ * the Free Software Foundation; version 3.
2367+ *
2368+ * This program is distributed in the hope that it will be useful,
2369+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2370+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2371+ * GNU General Public License for more details.
2372+ *
2373+ * You should have received a copy of the GNU General Public License
2374+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2375+ *
2376+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
2377+ */
2378+
2379+#ifndef DASHCOMMUNICATOR_PLUGIN_H
2380+#define DASHCOMMUNICATOR_PLUGIN_H
2381+
2382+#include <QtQml/QQmlEngine>
2383+#include <QtQml/QQmlExtensionPlugin>
2384+
2385+class DashCommunicatorPlugin : public QQmlExtensionPlugin
2386+{
2387+ Q_OBJECT
2388+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
2389+
2390+public:
2391+ void registerTypes(const char *uri);
2392+};
2393+
2394+#endif
2395
2396=== added file 'tests/mocks/Unity/DashCommunicator/qmldir'
2397--- tests/mocks/Unity/DashCommunicator/qmldir 1970-01-01 00:00:00 +0000
2398+++ tests/mocks/Unity/DashCommunicator/qmldir 2014-08-05 11:53:58 +0000
2399@@ -0,0 +1,3 @@
2400+module Unity.DashCommunicator
2401+plugin MockDashCommunicator-qml
2402+typeinfo DashCommunicator.qmltypes
2403
2404=== modified file 'tests/qmltests/Dash/tst_Dash.qml'
2405--- tests/qmltests/Dash/tst_Dash.qml 2014-07-11 11:45:45 +0000
2406+++ tests/qmltests/Dash/tst_Dash.qml 2014-08-05 11:53:58 +0000
2407@@ -59,6 +59,7 @@
2408 verify(dashContentList != undefined);
2409 tryCompare(dashContentList, "count", 0);
2410 scopes.load();
2411+ tryCompare(dashContentList, "currentIndex", 0);
2412 }
2413
2414 function get_scope_data() {
2415@@ -91,5 +92,23 @@
2416 verify(dashContentList != undefined);
2417 tryCompare(dashContentList, "currentIndex", data.visualIndex);
2418 }
2419+
2420+ function test_setCurrentScope() {
2421+ var dashContentList = findChild(dash, "dashContentList");
2422+ var startX = dash.width - units.gu(1);
2423+ var startY = dash.height / 2;
2424+ var stopX = units.gu(1)
2425+ var stopY = startY;
2426+ var retry = 0;
2427+ while (dashContentList.currentIndex != 2 && retry <= 5) {
2428+ mouseFlick(dash, startX, startY, stopX, stopY)
2429+ waitForRendering(dashContentList)
2430+ retry++;
2431+ }
2432+ compare(dashContentList.currentIndex, 2);
2433+ var dashCommunicatorService = findInvisibleChild(dash, "dashCommunicatorService");
2434+ dashCommunicatorService.mockSetCurrentScope("clickscope", true, true);
2435+ tryCompare(dashContentList, "currentIndex", 1)
2436+ }
2437 }
2438 }
2439
2440=== modified file 'tests/qmltests/Stages/tst_PhoneStage.qml'
2441--- tests/qmltests/Stages/tst_PhoneStage.qml 2014-07-24 21:56:42 +0000
2442+++ tests/qmltests/Stages/tst_PhoneStage.qml 2014-08-05 11:53:58 +0000
2443@@ -231,9 +231,10 @@
2444 }
2445
2446 function cleanup() {
2447- while (ApplicationManager.count > 0) {
2448+ while (ApplicationManager.count > 1) {
2449 var oldCount = ApplicationManager.count;
2450- ApplicationManager.stopApplication(ApplicationManager.get(0).appId)
2451+ var closingIndex = ApplicationManager.focusedApplicationId == "unity8-dash" ? 1 : 0
2452+ ApplicationManager.stopApplication(ApplicationManager.get(closingIndex).appId)
2453 tryCompare(ApplicationManager, "count", oldCount - 1)
2454 }
2455 }
2456
2457=== modified file 'tests/qmltests/tst_Shell.qml'
2458--- tests/qmltests/tst_Shell.qml 2014-07-28 12:48:29 +0000
2459+++ tests/qmltests/tst_Shell.qml 2014-08-05 11:53:58 +0000
2460@@ -56,49 +56,20 @@
2461 signalName: "sessionStarted"
2462 }
2463
2464+ SignalSpy {
2465+ id: dashCommunicatorSpy
2466+ signalName: "setCurrentScopeCalled"
2467+ }
2468+
2469 UT.UnityTestCase {
2470 name: "Shell"
2471 when: windowShown
2472
2473 function initTestCase() {
2474- var ok = false;
2475- var attempts = 0;
2476- var maxAttempts = 1000;
2477-
2478- // Qt loads a qml scene asynchronously. So early on, some findChild() calls made in
2479- // tests may fail because the desired child item wasn't loaded yet.
2480- // Thus here we try to ensure the scene has been fully loaded before proceeding with the tests.
2481- // As I couldn't find an API in QQuickView & friends to tell me that the scene is 100% loaded
2482- // (all items instantiated, etc), I resort to checking the existence of some key items until
2483- // repeatedly until they're all there.
2484- do {
2485- var dashContentList = findChild(shell, "dashContentList");
2486- waitForRendering(dashContentList);
2487- var homeLoader = findChild(dashContentList, "clickscope loader");
2488- ok = homeLoader !== null
2489- && homeLoader.item !== undefined;
2490-
2491- var greeter = findChild(shell, "greeter");
2492- ok &= greeter !== null;
2493-
2494- var launcherPanel = findChild(shell, "launcherPanel");
2495- ok &= launcherPanel !== null;
2496-
2497- attempts++;
2498- if (!ok) {
2499- console.log("Attempt " + attempts + " failed. Waiting a bit before trying again.");
2500- // wait a bit before retrying
2501- wait(100);
2502- } else {
2503- console.log("All seem fine after " + attempts + " attempts.");
2504- }
2505- } while (!ok && attempts <= maxAttempts);
2506-
2507- verify(ok);
2508-
2509 swipeAwayGreeter();
2510
2511 sessionSpy.target = findChild(shell, "greeter")
2512+ dashCommunicatorSpy.target = findInvisibleChild(shell, "dashCommunicator");
2513 }
2514
2515 function cleanup() {
2516@@ -111,56 +82,16 @@
2517 // kill all (fake) running apps
2518 killApps(ApplicationManager);
2519
2520- var dashContent = findChild(shell, "dashContent");
2521- dashContent.closePreview();
2522-
2523- var dashHome = findChild(shell, "clickscope loader");
2524- swipeUntilScopeViewIsReached(dashHome);
2525-
2526+ waitForUIToSettle();
2527 hideIndicators();
2528 }
2529
2530- function killApps(apps) {
2531- if (!apps) return;
2532- while (apps.count > 0) {
2533- ApplicationManager.stopApplication(apps.get(0).appId);
2534+ function killApps() {
2535+ while (ApplicationManager.count > 1) {
2536+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
2537+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId);
2538 }
2539- compare(ApplicationManager.count, 0)
2540- }
2541-
2542- /*
2543- Test the effect of a right-edge drag on the dash in 3 situations:
2544- 1 - when no application has been launched yet
2545- 2 - when there's a minimized application
2546- 3 - after the last running application has been closed/stopped
2547-
2548- The behavior of Dash on 3 should be the same as on 1.
2549- */
2550- function test_rightEdgeDrag() {
2551- checkRightEdgeDragWithNoRunningApps();
2552-
2553- dragLauncherIntoView();
2554-
2555- // Launch an app from the launcher
2556- tapOnAppIconInLauncher();
2557- waitUntilApplicationWindowIsFullyVisible();
2558-
2559- // Minimize the application we just launched
2560- swipeFromLeftEdge(units.gu(27));
2561-
2562- waitForUIToSettle();
2563-
2564- checkRightEdgeDragWithMinimizedApp();
2565-
2566- // Minimize that application once again
2567- swipeFromLeftEdge(units.gu(27));
2568-
2569- // Right edge behavior should now be the same as before that app,
2570- // was launched. Manually cleanup beforehand to get to initial
2571- // state.
2572- cleanup();
2573- waitForUIToSettle();
2574- checkRightEdgeDragWithNoRunningApps();
2575+ compare(ApplicationManager.count, 1)
2576 }
2577
2578 function test_leftEdgeDrag_data() {
2579@@ -183,7 +114,7 @@
2580
2581 swipeFromLeftEdge(data.swipeLength);
2582 if (data.appHides)
2583- waitUntilApplicationWindowIsFullyHidden();
2584+ waitUntilDashIsFocused();
2585 else
2586 waitUntilApplicationWindowIsFullyVisible();
2587 }
2588@@ -240,99 +171,17 @@
2589 }
2590
2591 /*
2592- Perform a right-edge drag when the Dash is being show and there are
2593- no running/minimized apps to be restored.
2594-
2595- The expected behavior is that an animation should be played to hint the
2596- user that his right-edge drag gesture has been successfully recognized
2597- but there is no application to be brought to foreground.
2598- */
2599- function checkRightEdgeDragWithNoRunningApps() {
2600- var touchX = shell.width - (shell.edgeSize / 2);
2601- var touchY = shell.height / 2;
2602-
2603- var dash = findChild(shell, "dash");
2604- // check that dash has normal scale and opacity
2605- tryCompare(dash, "contentScale", 1.0);
2606- tryCompare(dash, "opacity", 1.0);
2607-
2608- touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
2609- true /* beginTouch */, false /* endTouch */, units.gu(10), 50);
2610-
2611- // check that Dash has been scaled down and had its opacity reduced
2612- tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
2613- tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
2614-
2615- touchRelease(shell, shell.width * 0.1, touchY);
2616-
2617- // and now everything should have gone back to normal
2618- tryCompare(dash, "contentScale", 1.0);
2619- tryCompare(dash, "opacity", 1.0);
2620- }
2621-
2622- /*
2623- Perform a right-edge drag when the Dash is being show and there is
2624- a running/minimized app to be restored.
2625-
2626- The expected behavior is that the dash should fade away and ultimately be
2627- made invisible once the gesture is finished as the restored app will now
2628- be on foreground.
2629- */
2630- function checkRightEdgeDragWithMinimizedApp() {
2631- var touchX = shell.width - (shell.edgeSize / 2);
2632- var touchY = shell.height / 2;
2633-
2634- var dash = findChild(shell, "dash");
2635- // check that dash has normal scale and opacity
2636- tryCompare(dash, "contentScale", 1.0);
2637- tryCompare(dash, "opacity", 1.0);
2638-
2639- touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
2640- true /* beginTouch */, false /* endTouch */, units.gu(10), 50);
2641-
2642- // check that Dash has been scaled down and had its opacity reduced
2643- tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
2644- tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
2645-
2646- touchRelease(shell, shell.width * 0.1, touchY);
2647-
2648- // dash should have gone away, now that the app is on foreground
2649- tryCompare(dash, "visible", false);
2650- }
2651-
2652- /*
2653 Regression test for bug https://bugs.launchpad.net/touch-preview-images/+bug/1193419
2654
2655- When the user minimizes an application (left-edge swipe) he should always end up in the "Running Apps"
2656- category of the "Applications" scope view.
2657+ When the user minimizes an application (left-edge swipe) he should always end up in the
2658+ "Applications" scope view.
2659
2660 Steps:
2661- - go to apps lens
2662- - scroll to the bottom
2663- - reveal launcher and launch an app
2664+ - reveal launcher and launch an app that covers the dash
2665 - perform long left edge swipe to go minimize the app and go back to the dash.
2666-
2667- Expected Results
2668- - apps lens shown
2669+ - verify the setCurrentScope() D-Bus call to the dash has been called for the correct scope id.
2670 */
2671 function test_minimizingAppTakesToDashApps() {
2672- var dashApps = findChild(shell, "clickscope");
2673- swipeUntilScopeViewIsReached(dashApps);
2674-
2675- // swipe finger up until the running/recent apps section (which we assume
2676- // it's the first one) is as far from view as possible.
2677- // We also assume that DashApps is tall enough that it's scrollable
2678- var appsCategoryListView = findChild(dashApps, "categoryListView");
2679- while (!appsCategoryListView.atYEnd) {
2680- swipeUpFromCenter();
2681- tryCompare(appsCategoryListView, "moving", false);
2682- }
2683-
2684- // Switch away from the Applications scope.
2685- swipeRightFromCenter();
2686- waitUntilItemStopsMoving(dashApps);
2687- verify(!itemIsOnScreen(dashApps));
2688-
2689 dragLauncherIntoView();
2690
2691 // Launch an app from the launcher
2692@@ -340,19 +189,16 @@
2693
2694 waitUntilApplicationWindowIsFullyVisible();
2695
2696- // Dragging launcher into view with a little bit of gap (units.gu(1)) should switch to Apps scope
2697- dragLauncherIntoView();
2698- verify(itemIsOnScreen(dashApps));
2699+ verify(ApplicationManager.focusedApplicationId !== "unity8-dash")
2700
2701+ dashCommunicatorSpy.clear();
2702 // Minimize the application we just launched
2703 swipeFromLeftEdge(units.gu(27));
2704
2705- // Wait for the whole UI to settle down
2706- waitUntilApplicationWindowIsFullyHidden();
2707- waitUntilItemStopsMoving(dashApps);
2708- tryCompare(appsCategoryListView, "moving", false);
2709+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2710
2711- verify(itemIsOnScreen(dashApps));
2712+ compare(dashCommunicatorSpy.count, 1);
2713+ compare(dashCommunicatorSpy.signalArguments[0][0], "clickscope");
2714 }
2715
2716 function test_showInputMethod() {
2717@@ -409,9 +255,14 @@
2718
2719 // Wait for the whole UI to settle down
2720 function waitForUIToSettle() {
2721- waitUntilApplicationWindowIsFullyHidden();
2722- var dashContentList = findChild(shell, "dashContentList");
2723- tryCompare(dashContentList, "moving", false);
2724+ var launcher = findChild(shell, "launcherPanel")
2725+ tryCompareFunction(function() {return launcher.x === 0 || launcher.x === -launcher.width;}, true);
2726+ if (launcher.x === 0) {
2727+ mouseClick(shell, shell.width / 2, shell.height / 2)
2728+ }
2729+ tryCompare(launcher, "x", -launcher.width)
2730+
2731+ waitForRendering(shell)
2732 }
2733
2734 function dragToCloseIndicatorsPanel() {
2735@@ -468,24 +319,13 @@
2736 }
2737
2738 function waitUntilApplicationWindowIsFullyVisible() {
2739- var underlay = findChild(shell, "underlay");
2740- tryCompare(underlay, "visible", false);
2741- }
2742-
2743- function waitUntilApplicationWindowIsFullyHidden() {
2744- var stages = findChild(shell, "stages");
2745- tryCompare(stages, "fullyHidden", true);
2746- }
2747-
2748- function swipeUntilScopeViewIsReached(scopeView) {
2749- while (!itemIsOnScreen(scopeView)) {
2750- if (itemIsToLeftOfScreen(scopeView)) {
2751- swipeRightFromCenter();
2752- } else {
2753- swipeLeftFromCenter();
2754- }
2755- waitUntilItemStopsMoving(scopeView);
2756- }
2757+ var appDelegate = findChild(shell, "appDelegate0")
2758+ var surfaceContainer = findChild(appDelegate, "surfaceContainer");
2759+ tryCompareFunction(function() { return surfaceContainer.surface !== null; }, true);
2760+ }
2761+
2762+ function waitUntilDashIsFocused() {
2763+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2764 }
2765
2766 function swipeFromLeftEdge(swipeLength) {
2767@@ -494,24 +334,6 @@
2768 touchFlick(shell, touchStartX, touchStartY, swipeLength, touchStartY);
2769 }
2770
2771- function swipeLeftFromCenter() {
2772- var touchStartX = shell.width * 3 / 4;
2773- var touchStartY = shell.height / 2;
2774- touchFlick(shell, touchStartX, touchStartY, 0, touchStartY);
2775- }
2776-
2777- function swipeRightFromCenter() {
2778- var touchStartX = shell.width * 3 / 4;
2779- var touchStartY = shell.height / 2;
2780- touchFlick(shell, touchStartX, touchStartY, shell.width, touchStartY);
2781- }
2782-
2783- function swipeUpFromCenter() {
2784- var touchStartX = shell.width / 2;
2785- var touchStartY = shell.height / 2;
2786- touchFlick(shell, touchStartX, touchStartY, touchStartX, 0);
2787- }
2788-
2789 function itemIsOnScreen(item) {
2790 var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
2791
2792@@ -521,64 +343,6 @@
2793 && itemRectInShell.y + itemRectInShell.height <= shell.height;
2794 }
2795
2796- function itemIsToLeftOfScreen(item) {
2797- var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
2798- return itemRectInShell.x < 0;
2799- }
2800-
2801- function waitUntilItemStopsMoving(item) {
2802- var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
2803- var previousX = itemRectInShell.x;
2804- var previousY = itemRectInShell.y;
2805- var isStill = false;
2806-
2807- do {
2808- wait(100);
2809- itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
2810- if (itemRectInShell.x == previousX && itemRectInShell.y == previousY) {
2811- isStill = true;
2812- } else {
2813- previousX = itemRectInShell.x;
2814- previousY = itemRectInShell.y;
2815- }
2816- } while (!isStill);
2817- }
2818-
2819- function test_DashShown_data() {
2820- return [
2821- {tag: "in focus", greeter: false, app: false, launcher: false, indicators: false, expectedShown: true},
2822- {tag: "under greeter", greeter: true, app: false, launcher: false, indicators: false, expectedShown: false},
2823- {tag: "under app", greeter: false, app: true, launcher: false, indicators: false, expectedShown: false},
2824- {tag: "under launcher", greeter: false, app: false, launcher: true, indicators: false, expectedShown: true},
2825- {tag: "under indicators", greeter: false, app: false, launcher: false, indicators: true, expectedShown: false},
2826- ]
2827- }
2828-
2829- function test_DashShown(data) {
2830- if (data.greeter) {
2831- // Swipe the greeter in
2832- var greeter = findChild(shell, "greeter");
2833- Powerd.displayPowerStateChange(Powerd.Off, 0);
2834- tryCompare(greeter, "showProgress", 1);
2835- }
2836-
2837- if (data.app) {
2838- dragLauncherIntoView();
2839- tapOnAppIconInLauncher();
2840- }
2841-
2842- if (data.launcher) {
2843- dragLauncherIntoView();
2844- }
2845-
2846- if (data.indicators) {
2847- showIndicators();
2848- }
2849-
2850- var dash = findChild(shell, "dash");
2851- tryCompare(dash, "shown", data.expectedShown);
2852- }
2853-
2854 function test_focusRequestedHidesGreeter() {
2855 var greeter = findChild(shell, "greeter");
2856
2857@@ -587,10 +351,9 @@
2858 tryCompareFunction(function() { return app.surface != null }, true);
2859
2860 // Minimize the application we just launched
2861- swipeFromLeftEdge(units.gu(27));
2862+ swipeFromLeftEdge(units.gu(26) + 1);
2863
2864- // Wait for the whole UI to settle down
2865- waitUntilApplicationWindowIsFullyHidden();
2866+ waitUntilDashIsFocused();
2867
2868 greeter.show();
2869 tryCompare(greeter, "showProgress", 1);
2870@@ -606,8 +369,9 @@
2871
2872 showIndicators();
2873
2874+ var oldCount = ApplicationManager.count;
2875 ApplicationManager.startApplication("camera-app");
2876- tryCompare(ApplicationManager, "count", 1);
2877+ tryCompare(ApplicationManager, "count", oldCount + 1);
2878
2879 tryCompare(indicators, "fullyClosed", true);
2880 }
2881@@ -616,6 +380,7 @@
2882 function test_showGreeterDBusCall() {
2883 var greeter = findChild(shell, "greeter")
2884 tryCompare(greeter, "showProgress", 0)
2885+ waitForRendering(greeter);
2886 LightDM.Greeter.showGreeter()
2887 tryCompare(greeter, "showProgress", 1)
2888 }
2889@@ -624,6 +389,7 @@
2890 sessionSpy.clear()
2891
2892 var greeter = findChild(shell, "greeter")
2893+ waitForRendering(greeter)
2894 greeter.show()
2895 tryCompare(greeter, "showProgress", 1)
2896
2897@@ -644,5 +410,26 @@
2898 ApplicationManager.requestFocusApplication("gallery-app");
2899 tryCompare(panel, "fullscreenMode", false);
2900 }
2901+
2902+ function test_leftEdgeDragFullscreen() {
2903+ var panel = findChild(shell, "panel");
2904+ tryCompare(panel, "fullscreenMode", false)
2905+
2906+ ApplicationManager.startApplication("camera-app");
2907+ tryCompare(panel, "fullscreenMode", true)
2908+
2909+ var touchStartX = 2;
2910+ var touchStartY = shell.height / 2;
2911+
2912+ touchFlick(shell, touchStartX, touchStartY, units.gu(2), touchStartY, true, false);
2913+
2914+ compare(panel.fullscreenMode, true);
2915+
2916+ touchFlick(shell, units.gu(2), touchStartY, units.gu(10), touchStartY, false, false);
2917+
2918+ tryCompare(panel, "fullscreenMode", false);
2919+
2920+ touchRelease(shell);
2921+ }
2922 }
2923 }
2924
2925=== modified file 'tests/qmltests/tst_ShellWithPin.qml'
2926--- tests/qmltests/tst_ShellWithPin.qml 2014-07-15 18:26:25 +0000
2927+++ tests/qmltests/tst_ShellWithPin.qml 2014-08-05 11:53:58 +0000
2928@@ -58,40 +58,6 @@
2929 when: windowShown
2930
2931 function initTestCase() {
2932- var ok = false;
2933- var attempts = 0;
2934- var maxAttempts = 1000;
2935-
2936- // Qt loads a qml scene asynchronously. So early on, some findChild() calls made in
2937- // tests may fail because the desired child item wasn't loaded yet.
2938- // Thus here we try to ensure the scene has been fully loaded before proceeding with the tests.
2939- // As I couldn't find an API in QQuickView & friends to tell me that the scene is 100% loaded
2940- // (all items instantiated, etc), I resort to checking the existence of some key items until
2941- // repeatedly until they're all there.
2942- do {
2943- var dashContentList = findChild(shell, "dashContentList");
2944- waitForRendering(dashContentList);
2945- var homeLoader = findChild(dashContentList, "clickscope loader");
2946- ok = homeLoader !== null
2947- && homeLoader.item !== undefined;
2948-
2949- var greeter = findChild(shell, "greeter");
2950- ok &= greeter !== null;
2951-
2952- var launcherPanel = findChild(shell, "launcherPanel");
2953- ok &= launcherPanel !== null;
2954-
2955- attempts++;
2956- if (!ok) {
2957- console.log("Attempt " + attempts + " failed. Waiting a bit before trying again.");
2958- // wait a bit before retrying
2959- wait(100);
2960- } else {
2961- console.log("All seem fine after " + attempts + " attempts.");
2962- }
2963- } while (!ok && attempts <= maxAttempts);
2964-
2965- verify(ok);
2966
2967 sessionSpy.target = findChild(shell, "greeter")
2968 }
2969@@ -110,10 +76,11 @@
2970 }
2971
2972 function killApps() {
2973- while (ApplicationManager.count > 0) {
2974- ApplicationManager.stopApplication(ApplicationManager.get(0).appId)
2975+ while (ApplicationManager.count > 1) {
2976+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
2977+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId);
2978 }
2979- compare(ApplicationManager.count, 0)
2980+ compare(ApplicationManager.count, 1)
2981 }
2982
2983 function swipeAwayGreeter() {

Subscribers

People subscribed via source and target branches