Merge lp:~gerboland/unity8/initialSurfaceGeometry into lp:unity8
- initialSurfaceGeometry
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~gerboland/unity8/initialSurfaceGeometry |
Merge into: | lp:unity8 |
Diff against target: |
3235 lines (+1428/-772) 41 files modified
debian/control (+4/-4) include/paths.h.in (+8/-0) plugins/Unity/Launcher/CMakeLists.txt (+1/-1) qml/Panel/Panel.qml (+4/-8) qml/Shell.qml (+9/-10) qml/Stages/AppSurfaceContainer.qml (+0/-96) qml/Stages/ApplicationWindow.qml (+258/-0) qml/Stages/PhoneStage.qml (+29/-4) qml/Stages/SpreadDelegate.qml (+34/-59) qml/Stages/SurfaceContainer.qml (+1/-1) qml/Stages/TabletStage.qml (+34/-3) qml/Stages/TransformedSpreadDelegate.qml (+1/-1) tests/mocks/Unity/Application/Application.qmltypes (+0/-19) tests/mocks/Unity/Application/ApplicationImage.cpp (+0/-123) tests/mocks/Unity/Application/ApplicationImage.h (+0/-79) tests/mocks/Unity/Application/ApplicationInfo.cpp (+84/-16) tests/mocks/Unity/Application/ApplicationInfo.h (+52/-46) tests/mocks/Unity/Application/ApplicationManager.cpp (+109/-104) tests/mocks/Unity/Application/ApplicationManager.h (+14/-6) tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp (+2/-4) tests/mocks/Unity/Application/CMakeLists.txt (+1/-3) tests/mocks/Unity/Application/InputFilterArea.qml (+0/-21) tests/mocks/Unity/Application/MirSurfaceItem.cpp (+87/-16) tests/mocks/Unity/Application/MirSurfaceItem.h (+14/-11) tests/mocks/Unity/Application/MirSurfaceItem.qml (+57/-0) tests/mocks/Unity/Application/OSKController.qml (+0/-20) tests/mocks/Unity/Application/SurfaceManager.cpp (+14/-3) tests/mocks/Unity/Application/SurfaceManager.h (+1/-2) tests/mocks/Unity/Application/VirtualKeyboard.cpp (+0/-55) tests/mocks/Unity/Application/VirtualKeyboard.h (+0/-35) tests/mocks/Unity/Application/VirtualKeyboard.qml (+40/-0) tests/mocks/Unity/Application/plugin.cpp (+0/-3) tests/mocks/Unity/Application/qmldir (+0/-3) tests/plugins/Unity/Launcher/CMakeLists.txt (+2/-2) tests/plugins/Unity/Launcher/launchermodeltest.cpp (+2/-1) tests/qmltests/CMakeLists.txt (+2/-0) tests/qmltests/Stages/tst_ApplicationWindow.qml (+346/-0) tests/qmltests/Stages/tst_PhoneStage.qml (+44/-9) tests/qmltests/Stages/tst_SpreadDelegate.qml (+167/-0) tests/qmltests/tst_Shell.qml (+2/-2) tests/utils/modules/Unity/Test/UnityTestCase.qml (+5/-2) |
To merge this branch: | bzr merge lp:~gerboland/unity8/initialSurfaceGeometry |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michał Sawicz | Needs Information | ||
Albert Astals Cid (community) | Abstain | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Daniel d'Andrada (community) | Approve | ||
Review via email: mp+230490@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-08-21.
Commit message
Implement a surfaceSizer exported by qtmir to override the initial surface geometry requested by clients. Also fix small surface size & position bug.
The SurfaceSizer is a Javascript function defined by unity8 which is registered with QtMir as a callback function whenever a client requests a new surface from Mir. It allows unity8 to override the client-requested width & height of the surface. This fixes the startup-resize visual glitching evident right now.
While implementing the surfaceSizer function, I discovered that all non-fullscreen surfaces were 2DP too tall and being occluded by the orange line of the panel. This MR fixes that fact and cleans up what "panelHeight" refers to in Shell.qml - it is the height of the indicator bar plus the orange line.
Description of the change
Implement a surfaceSizer exported by qtmir to override the initial surface geometry requested by clients
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Y
* Did you make sure that your branch does not contain spurious tags?
Y
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
* If you changed the UI, has there been a design review?
N/A
Michał Sawicz (saviq) wrote : | # |
Oh and you need to depend on the new unity-api.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1142
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1143. By Gerry Boland
-
Adjjust to newer API
- 1144. By Gerry Boland
-
[debian] depend on unity-api 7.89 (supplying unity-applicati
on-impl3) and qtmir 0.4.2
Gerry Boland (gerboland) wrote : | # |
Updated to newer unity-api and comments addressed
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1143
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1144
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
Commented in the diff.
Gerry Boland (gerboland) : | # |
Gerry Boland (gerboland) : | # |
Daniel d'Andrada (dandrader) : | # |
Albert Astals Cid (aacid) wrote : | # |
Text conflict in debian/control
1 conflicts encountered.
Gerry Boland (gerboland) : | # |
- 1145. By Gerry Boland
-
Merge trunk & fix conflict
Gerry Boland (gerboland) wrote : | # |
@Daniel: replied to your question (sorry for delay, forgot to hit "save comment" until now)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1145
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
See diff comment.
- 1146. By Gerry Boland
-
Merge trunk
- 1147. By Gerry Boland
-
Remove test crash fix
Gerry Boland (gerboland) wrote : | # |
Reply inline
Daniel d'Andrada (dandrader) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1147
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Code does merge properly now
Michał Sawicz (saviq) : | # |
Michał Sawicz (saviq) wrote : | # |
This conflicts with lp:~dandrader/unity8/lifecycle that's already approved and slated for release soon, maybe rebase on that one and we'll land them together?
- 1148. By Gerry Boland
-
Merge lp:~dandrader/unity8/lifecycle and fix conflicts
- 1149. By Gerry Boland
-
Merge trunk
- 1150. By Gerry Boland
-
Merge trunk
- 1151. By Gerry Boland
-
merge old trunk
- 1152. By Gerry Boland
-
Merge current trunk
- 1153. By Gerry Boland
-
Undo all changes to Shell and Panel, start afresh
- 1154. By Gerry Boland
-
I hate you whitespace cheker
- 1155. By Gerry Boland
-
Bump unity-api & qtmir dep
- 1156. By Gerry Boland
-
Merge trunk
- 1157. By Gerry Boland
-
Delay Dash DBus service creation slightly, to avoid possible shell deadlock
- 1158. By Gerry Boland
-
Merge trunk
- 1159. By Gerry Boland
-
Merge trunk
- 1160. By Gerry Boland
-
Remove Dash block workaround
- 1161. By Gerry Boland
-
Merge trunk
Unmerged revisions
- 1161. By Gerry Boland
-
Merge trunk
- 1160. By Gerry Boland
-
Remove Dash block workaround
- 1159. By Gerry Boland
-
Merge trunk
- 1158. By Gerry Boland
-
Merge trunk
- 1157. By Gerry Boland
-
Delay Dash DBus service creation slightly, to avoid possible shell deadlock
- 1156. By Gerry Boland
-
Merge trunk
- 1155. By Gerry Boland
-
Bump unity-api & qtmir dep
- 1154. By Gerry Boland
-
I hate you whitespace cheker
- 1153. By Gerry Boland
-
Undo all changes to Shell and Panel, start afresh
- 1152. By Gerry Boland
-
Merge current trunk
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2014-08-15 17:37:07 +0000 |
3 | +++ debian/control 2014-08-21 13:12:27 +0000 |
4 | @@ -24,7 +24,7 @@ |
5 | libpulse-dev, |
6 | libqmenumodel-dev (>= 0.2.8), |
7 | libqt5xmlpatterns5-dev, |
8 | - libunity-api-dev (>= 7.88), |
9 | + libunity-api-dev (>= 7.89), |
10 | libusermetricsoutput1-dev, |
11 | libxcb1-dev, |
12 | pkg-config, |
13 | @@ -84,7 +84,7 @@ |
14 | qmenumodel-qml (>= 0.2.8), |
15 | qml-module-qtquick-xmllistmodel, |
16 | qtdeclarative5-gsettings1.0, |
17 | - qtdeclarative5-qtmir-plugin (>= 0.4.1), |
18 | + qtdeclarative5-qtmir-plugin (>= 0.4.2), |
19 | qtdeclarative5-ubuntu-telephony0.1, |
20 | unity-launcher-impl-3, |
21 | unity8-common (= ${source:Version}), |
22 | @@ -111,7 +111,7 @@ |
23 | qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.49) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 0.1.49), |
24 | qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl, |
25 | ubuntu-thumbnailer-impl-0, |
26 | - unity-application-impl-2, |
27 | + unity-application-impl-3, |
28 | unity-notifications-impl-3, |
29 | unity-plugin-scopes | unity-scopes-impl, |
30 | unity-scopes-impl-4, |
31 | @@ -158,7 +158,7 @@ |
32 | Depends: ${misc:Depends}, |
33 | ${shlibs:Depends}, |
34 | Provides: unity-application-impl, |
35 | - unity-application-impl-2, |
36 | + unity-application-impl-3, |
37 | Description: Fake environment for running Unity 8 shell |
38 | Provides fake implementations of some QML modules used by Unity 8 shell |
39 | (e.g Ubuntu.Application) so that you can run it in a sandboxed environment. |
40 | |
41 | === modified file 'include/paths.h.in' |
42 | --- include/paths.h.in 2014-04-17 08:06:29 +0000 |
43 | +++ include/paths.h.in 2014-08-21 13:12:27 +0000 |
44 | @@ -80,6 +80,14 @@ |
45 | return paths; |
46 | } |
47 | |
48 | +inline QString mockPluginsDir() { |
49 | + if (isRunningInstalled()) { |
50 | + return QString("@CMAKE_INSTALL_PREFIX@/@SHELL_INSTALL_QML@/mocks"); |
51 | + } else { |
52 | + return QString("@CMAKE_BINARY_DIR@/tests/mocks"); |
53 | + } |
54 | +} |
55 | + |
56 | inline QStringList shellDataDirs() { |
57 | QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); |
58 | if (!isRunningInstalled()) { |
59 | |
60 | === modified file 'plugins/Unity/Launcher/CMakeLists.txt' |
61 | --- plugins/Unity/Launcher/CMakeLists.txt 2014-05-30 09:22:58 +0000 |
62 | +++ plugins/Unity/Launcher/CMakeLists.txt 2014-08-21 13:12:27 +0000 |
63 | @@ -1,6 +1,6 @@ |
64 | include(FindPkgConfig) |
65 | pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3) |
66 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=1) |
67 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3) |
68 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
69 | |
70 | add_definitions(-DSM_BUSNAME=systemBus) |
71 | |
72 | === modified file 'qml/Dash/graphics/phone/screenshots/vkb_portrait.png' |
73 | Binary files qml/Dash/graphics/phone/screenshots/vkb_portrait.png 2014-07-22 10:29:25 +0000 and qml/Dash/graphics/phone/screenshots/vkb_portrait.png 2014-08-21 13:12:27 +0000 differ |
74 | === modified file 'qml/Panel/Panel.qml' |
75 | --- qml/Panel/Panel.qml 2014-07-10 13:36:41 +0000 |
76 | +++ qml/Panel/Panel.qml 2014-08-21 13:12:27 +0000 |
77 | @@ -22,7 +22,8 @@ |
78 | |
79 | Item { |
80 | id: root |
81 | - readonly property real panelHeight: indicatorArea.y + d.indicatorHeight |
82 | + readonly property real panelHeight: indicators.panelHeight + indicatorsSeparatorLine.height |
83 | + readonly property real panelBottomY: indicatorArea.y + panelHeight |
84 | property alias indicators: __indicators |
85 | property alias callHint: __callHint |
86 | property bool fullscreenMode: false |
87 | @@ -32,7 +33,7 @@ |
88 | property real darkenedOpacity: 0.6 |
89 | anchors { |
90 | top: parent.top |
91 | - topMargin: panelHeight |
92 | + topMargin: panelBottomY |
93 | left: parent.left |
94 | right: parent.right |
95 | bottom: parent.bottom |
96 | @@ -165,11 +166,6 @@ |
97 | } |
98 | } |
99 | |
100 | - QtObject { |
101 | - id: d |
102 | - readonly property real indicatorHeight: indicators.panelHeight + indicatorsSeparatorLine.height |
103 | - } |
104 | - |
105 | states: [ |
106 | State { |
107 | name: "onscreen" //fully opaque and visible at top edge of screen |
108 | @@ -184,7 +180,7 @@ |
109 | when: fullscreenMode |
110 | PropertyChanges { |
111 | target: indicatorArea; |
112 | - anchors.topMargin: indicators.state === "initial" ? -d.indicatorHeight : 0 |
113 | + anchors.topMargin: indicators.state === "initial" ? -panelHeight : 0 |
114 | } |
115 | } |
116 | ] |
117 | |
118 | === modified file 'qml/Shell.qml' |
119 | --- qml/Shell.qml 2014-08-20 09:19:32 +0000 |
120 | +++ qml/Shell.qml 2014-08-21 13:12:27 +0000 |
121 | @@ -185,8 +185,7 @@ |
122 | Binding { |
123 | target: applicationsDisplayLoader.item |
124 | property: "maximizedAppTopMargin" |
125 | - // Not just using panel.panelHeight as that changes depending on the focused app. |
126 | - value: panel.indicators.panelHeight |
127 | + value: panel.panelHeight |
128 | } |
129 | Binding { |
130 | target: applicationsDisplayLoader.item |
131 | @@ -209,7 +208,7 @@ |
132 | InputMethod { |
133 | id: inputMethod |
134 | objectName: "inputMethod" |
135 | - anchors { fill: parent; topMargin: panel.panelHeight } |
136 | + anchors { fill: parent; topMargin: panel.panelBottomY } |
137 | z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1 |
138 | } |
139 | |
140 | @@ -237,17 +236,17 @@ |
141 | id: lockscreen |
142 | objectName: "lockscreen" |
143 | |
144 | - readonly property int backgroundTopMargin: -panel.panelHeight |
145 | + readonly property int backgroundTopMargin: -panel.panelBottomY |
146 | |
147 | hides: [launcher, panel.indicators] |
148 | shown: false |
149 | enabled: true |
150 | showAnimation: StandardAnimation { property: "opacity"; to: 1 } |
151 | hideAnimation: StandardAnimation { property: "opacity"; to: 0 } |
152 | - y: panel.panelHeight |
153 | + y: panel.panelBottomY |
154 | visible: required |
155 | width: parent.width |
156 | - height: parent.height - panel.panelHeight |
157 | + height: parent.height - panel.panelBottomY |
158 | background: shell.background |
159 | alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard |
160 | minPinLength: 4 |
161 | @@ -354,9 +353,9 @@ |
162 | // Just a tiny wrapper to adjust greeter's x without messing with its own dragging |
163 | id: greeterWrapper |
164 | x: launcher.progress |
165 | - y: panel.panelHeight |
166 | + y: panel.panelBottomY |
167 | width: parent.width |
168 | - height: parent.height - panel.panelHeight |
169 | + height: parent.height - panel.panelBottomY |
170 | |
171 | Behavior on x { |
172 | enabled: !launcher.dashSwipe |
173 | @@ -562,9 +561,9 @@ |
174 | model: NotificationBackend.Model |
175 | margin: units.gu(1) |
176 | |
177 | - y: panel.panelHeight |
178 | + y: panel.panelBottomY |
179 | width: parent.width |
180 | - height: parent.height - panel.panelHeight |
181 | + height: parent.height - panel.panelBottomY |
182 | |
183 | states: [ |
184 | State { |
185 | |
186 | === removed file 'qml/Stages/AppSurfaceContainer.qml' |
187 | --- qml/Stages/AppSurfaceContainer.qml 2014-08-08 09:40:41 +0000 |
188 | +++ qml/Stages/AppSurfaceContainer.qml 1970-01-01 00:00:00 +0000 |
189 | @@ -1,96 +0,0 @@ |
190 | -/* |
191 | - * Copyright 2014 Canonical Ltd. |
192 | - * |
193 | - * This program is free software; you can redistribute it and/or modify |
194 | - * it under the terms of the GNU Lesser General Public License as published by |
195 | - * the Free Software Foundation; version 3. |
196 | - * |
197 | - * This program is distributed in the hope that it will be useful, |
198 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
199 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
200 | - * GNU Lesser General Public License for more details. |
201 | - * |
202 | - * You should have received a copy of the GNU Lesser General Public License |
203 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
204 | -*/ |
205 | - |
206 | -import QtQuick 2.0 |
207 | -import "Animations" |
208 | - |
209 | -SurfaceContainer { |
210 | - id: container |
211 | - property var promptSurfaces |
212 | - |
213 | - property bool appHasCreatedASurface: false |
214 | - |
215 | - onSurfaceChanged: { |
216 | - if (surface) { |
217 | - if (!appHasCreatedASurface) { |
218 | - surface.visible = false; // hide until splash screen removed |
219 | - appHasCreatedASurface = true; |
220 | - } |
221 | - } |
222 | - } |
223 | - |
224 | - function revealSurface() { |
225 | - surface.visible = true; |
226 | - splashLoader.source = ""; |
227 | - } |
228 | - |
229 | - Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete |
230 | - id: surfaceRevealDelay |
231 | - interval: 100 |
232 | - onTriggered: surfaceContainer.revealSurface() |
233 | - } |
234 | - |
235 | - Loader { |
236 | - z: 3 |
237 | - id: splashLoader |
238 | - anchors.fill: parent |
239 | - } |
240 | - |
241 | - Repeater { |
242 | - model: container.promptSurfaces |
243 | - |
244 | - delegate: SurfaceContainer { |
245 | - anchors { |
246 | - fill: container |
247 | - topMargin: container.surface.anchors.topMargin |
248 | - rightMargin: container.surface.anchors.rightMargin |
249 | - bottomMargin: container.surface.anchors.bottomMargin |
250 | - leftMargin: container.surface.anchors.leftMargin |
251 | - } |
252 | - |
253 | - z: 4 + index |
254 | - surface: modelData |
255 | - |
256 | - Component.onCompleted: { |
257 | - animateIn(); |
258 | - } |
259 | - } |
260 | - } |
261 | - |
262 | - StateGroup { |
263 | - id: appSurfaceState |
264 | - states: [ |
265 | - State { |
266 | - name: "noSurfaceYet" |
267 | - when: !surfaceContainer.appHasCreatedASurface |
268 | - StateChangeScript { |
269 | - script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); } |
270 | - } |
271 | - }, |
272 | - State { |
273 | - name: "hasSurface" |
274 | - when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null) |
275 | - StateChangeScript { script: { surfaceRevealDelay.start(); } } |
276 | - }, |
277 | - State { |
278 | - name: "surfaceLostButAppStillAlive" |
279 | - when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null) |
280 | - // TODO - use app snapshot |
281 | - } |
282 | - ] |
283 | - state: "noSurfaceYet" |
284 | - } |
285 | -} |
286 | |
287 | === added file 'qml/Stages/ApplicationWindow.qml' |
288 | --- qml/Stages/ApplicationWindow.qml 1970-01-01 00:00:00 +0000 |
289 | +++ qml/Stages/ApplicationWindow.qml 2014-08-21 13:12:27 +0000 |
290 | @@ -0,0 +1,258 @@ |
291 | +/* |
292 | + * Copyright 2014 Canonical Ltd. |
293 | + * |
294 | + * This program is free software; you can redistribute it and/or modify |
295 | + * it under the terms of the GNU Lesser General Public License as published by |
296 | + * the Free Software Foundation; version 3. |
297 | + * |
298 | + * This program is distributed in the hope that it will be useful, |
299 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
300 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
301 | + * GNU Lesser General Public License for more details. |
302 | + * |
303 | + * You should have received a copy of the GNU Lesser General Public License |
304 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
305 | + */ |
306 | + |
307 | +import QtQuick 2.0 |
308 | +import Ubuntu.Components 1.1 |
309 | +import Unity.Application 0.1 |
310 | + |
311 | +Item { |
312 | + id: root |
313 | + |
314 | + // to be read from outside |
315 | + readonly property bool fullscreen: application ? application.fullscreen : false |
316 | + |
317 | + // to be set from outside |
318 | + property bool interactive: true |
319 | + property QtObject application |
320 | + |
321 | + QtObject { |
322 | + id: d |
323 | + |
324 | + // helpers so that we don't have to check for the existence of an application everywhere |
325 | + // (in order to avoid breaking qml binding due to a javascript exception) |
326 | + readonly property string name: root.application ? root.application.name : "" |
327 | + readonly property url icon: root.application ? root.application.icon : "" |
328 | + readonly property Item surface: root.application ? root.application.surface : null |
329 | + readonly property int applicationState: root.application ? root.application.state : -1 |
330 | + readonly property var promptSurfaces: root.application ? root.application.promptSurfaces : null |
331 | + |
332 | + // Whether the Application had a surface before but lost it. |
333 | + property bool hadSurface: false |
334 | + |
335 | + property bool needToTakeScreenshot: |
336 | + d.surface && d.surfaceInitialized && screenshotImage.status === Image.Null |
337 | + && d.applicationState === ApplicationInfo.Stopped |
338 | + onNeedToTakeScreenshotChanged: { |
339 | + if (needToTakeScreenshot) { |
340 | + screenshotImage.take(); |
341 | + } |
342 | + } |
343 | + |
344 | + //FIXME - this is a hack to avoid the first few rendered frames as they |
345 | + // might show the UI accommodating due to surface resizes on startup. |
346 | + // Remove this when possible |
347 | + property bool surfaceInitialized: false |
348 | + onSurfaceChanged: { |
349 | + if (surface) { |
350 | + surfaceInitTimer.start(); |
351 | + } else { |
352 | + hadSurface = true; |
353 | + surfaceInitialized = false; |
354 | + } |
355 | + } |
356 | + } |
357 | + |
358 | + Timer { |
359 | + id: surfaceInitTimer |
360 | + interval: 100 |
361 | + onTriggered: { if (d.surface) {d.surfaceInitialized = true;} } |
362 | + } |
363 | + |
364 | + Binding { |
365 | + target: d.surface |
366 | + when: d.surface |
367 | + property: "enabled" |
368 | + value: root.interactive |
369 | + } |
370 | + Binding { |
371 | + target: d.surface |
372 | + when: d.surface |
373 | + property: "focus" |
374 | + value: root.interactive |
375 | + } |
376 | + Connections { |
377 | + target: d.surface |
378 | + // FIXME: I would rather not need to do this, but currently it doesn't get |
379 | + // active focus without it and I don't know why. |
380 | + onFocusChanged: forceSurfaceActiveFocusIfReady(); |
381 | + onParentChanged: forceSurfaceActiveFocusIfReady(); |
382 | + onEnabledChanged: forceSurfaceActiveFocusIfReady(); |
383 | + function forceSurfaceActiveFocusIfReady() { |
384 | + if (d.surface.focus && d.surface.parent === surfaceContainer && d.surface.enabled) { |
385 | + d.surface.forceActiveFocus(); |
386 | + } |
387 | + } |
388 | + } |
389 | + |
390 | + SurfaceContainer { |
391 | + id: surfaceContainer |
392 | + objectName: "surfaceContainer" |
393 | + anchors.fill: parent |
394 | + surface: d.surface |
395 | + } |
396 | + |
397 | + Image { |
398 | + id: screenshotImage |
399 | + objectName: "screenshotImage" |
400 | + source: "" |
401 | + anchors.fill: parent |
402 | + |
403 | + function take() { |
404 | + // Format: "image://application/$APP_ID/$CURRENT_TIME_MS" |
405 | + // eg: "image://application/calculator-app/123456" |
406 | + var timeMs = new Date().getTime(); |
407 | + source = "image://application/" + root.application.appId + "/" + timeMs; |
408 | + } |
409 | + |
410 | + // Save memory by using a half-resolution (thus quarter size) screenshot |
411 | + sourceSize.width: root.width / 2 |
412 | + sourceSize.height: root.height / 2 |
413 | + } |
414 | + |
415 | + Loader { |
416 | + id: splashLoader |
417 | + visible: active |
418 | + active: false |
419 | + anchors.fill: surfaceContainer |
420 | + sourceComponent: Component { |
421 | + Splash { name: d.name; image: d.icon } |
422 | + } |
423 | + } |
424 | + |
425 | + Repeater { |
426 | + model: d.promptSurfaces |
427 | + |
428 | + delegate: SurfaceContainer { |
429 | + anchors { |
430 | + fill: container |
431 | + } |
432 | + |
433 | + surface: modelData |
434 | + |
435 | + Component.onCompleted: { |
436 | + animateIn(); |
437 | + } |
438 | + } |
439 | + } |
440 | + |
441 | + StateGroup { |
442 | + objectName: "applicationWindowStateGroup" |
443 | + states: [ |
444 | + State { |
445 | + name: "void" |
446 | + when: |
447 | + d.hadSurface && (!d.surface || !d.surfaceInitialized) |
448 | + && |
449 | + screenshotImage.status !== Image.Ready |
450 | + }, |
451 | + State { |
452 | + name: "splashScreen" |
453 | + when: |
454 | + !d.hadSurface && (!d.surface || !d.surfaceInitialized) |
455 | + && |
456 | + screenshotImage.status !== Image.Ready |
457 | + }, |
458 | + State { |
459 | + name: "surface" |
460 | + when: |
461 | + (d.surface && d.surfaceInitialized) |
462 | + && |
463 | + (d.applicationState !== ApplicationInfo.Stopped |
464 | + || screenshotImage.status !== Image.Ready) |
465 | + }, |
466 | + State { |
467 | + name: "screenshot" |
468 | + when: |
469 | + screenshotImage.status === Image.Ready |
470 | + && |
471 | + (d.applicationState === ApplicationInfo.Stopped |
472 | + || !d.surface || !d.surfaceInitialized) |
473 | + } |
474 | + ] |
475 | + |
476 | + transitions: [ |
477 | + Transition { |
478 | + from: ""; to: "splashScreen" |
479 | + PropertyAction { target: splashLoader; property: "active"; value: true } |
480 | + }, |
481 | + Transition { |
482 | + from: "splashScreen"; to: "surface" |
483 | + SequentialAnimation { |
484 | + PropertyAction { target: surfaceContainer |
485 | + property: "visible"; value: true } |
486 | + UbuntuNumberAnimation { target: splashLoader; property: "opacity"; |
487 | + from: 1.0; to: 0.0 |
488 | + duration: UbuntuAnimation.BriskDuration } |
489 | + PropertyAction { target: splashLoader; property: "active"; value: false } |
490 | + } |
491 | + }, |
492 | + Transition { |
493 | + from: "surface"; to: "splashScreen" |
494 | + SequentialAnimation { |
495 | + PropertyAction { target: splashLoader; property: "active"; value: true } |
496 | + PropertyAction { target: surfaceContainer |
497 | + property: "visible"; value: true } |
498 | + UbuntuNumberAnimation { target: splashLoader; property: "opacity"; |
499 | + from: 0.0; to: 1.0 |
500 | + duration: UbuntuAnimation.BriskDuration } |
501 | + } |
502 | + }, |
503 | + Transition { |
504 | + from: "surface"; to: "screenshot" |
505 | + SequentialAnimation { |
506 | + PropertyAction { target: screenshotImage |
507 | + property: "visible"; value: true } |
508 | + UbuntuNumberAnimation { target: screenshotImage; property: "opacity"; |
509 | + from: 0.0; to: 1.0 |
510 | + duration: UbuntuAnimation.BriskDuration } |
511 | + PropertyAction { target: surfaceContainer |
512 | + property: "visible"; value: false } |
513 | + ScriptAction { script: { if (d.surface) { d.surface.release(); } } } |
514 | + } |
515 | + }, |
516 | + Transition { |
517 | + from: "screenshot"; to: "surface" |
518 | + SequentialAnimation { |
519 | + PropertyAction { target: surfaceContainer |
520 | + property: "visible"; value: true } |
521 | + UbuntuNumberAnimation { target: screenshotImage; property: "opacity"; |
522 | + from: 1.0; to: 0.0 |
523 | + duration: UbuntuAnimation.BriskDuration } |
524 | + PropertyAction { target: screenshotImage; property: "visible"; value: false } |
525 | + PropertyAction { target: screenshotImage; property: "source"; value: "" } |
526 | + } |
527 | + }, |
528 | + Transition { |
529 | + from: "surface"; to: "void" |
530 | + SequentialAnimation { |
531 | + PropertyAction { target: surfaceContainer; property: "visible"; value: false } |
532 | + ScriptAction { script: { if (d.surface) { d.surface.release(); } } } |
533 | + } |
534 | + }, |
535 | + Transition { |
536 | + from: "void"; to: "surface" |
537 | + SequentialAnimation { |
538 | + PropertyAction { target: surfaceContainer; property: "opacity"; value: 0.0 } |
539 | + PropertyAction { target: surfaceContainer; property: "visible"; value: true } |
540 | + UbuntuNumberAnimation { target: surfaceContainer; property: "opacity"; |
541 | + from: 0.0; to: 1.0 |
542 | + duration: UbuntuAnimation.BriskDuration } |
543 | + } |
544 | + } |
545 | + ] |
546 | + } |
547 | + |
548 | +} |
549 | |
550 | === modified file 'qml/Stages/PhoneStage.qml' |
551 | --- qml/Stages/PhoneStage.qml 2014-07-29 15:22:08 +0000 |
552 | +++ qml/Stages/PhoneStage.qml 2014-08-21 13:12:27 +0000 |
553 | @@ -86,6 +86,7 @@ |
554 | |
555 | QtObject { |
556 | id: priv |
557 | + objectName: "priv" |
558 | |
559 | property string focusedAppId: ApplicationManager.focusedApplicationId |
560 | property var focusedApplication: ApplicationManager.findApplication(focusedAppId) |
561 | @@ -104,13 +105,26 @@ |
562 | return -1; |
563 | } |
564 | |
565 | + function surfaceSizer(surface) { |
566 | + surface.width = root.width; |
567 | + surface.height = root.height - maximizedAppTopMargin; |
568 | + return surface; |
569 | + } |
570 | + |
571 | + Component.onCompleted: { |
572 | + ApplicationManager.surfaceAboutToBeCreatedCallback = priv.surfaceSizer; |
573 | + } |
574 | + Component.onDestruction: { |
575 | + ApplicationManager.surfaceAboutToBeCreatedCallback = null; |
576 | + } |
577 | } |
578 | |
579 | Flickable { |
580 | id: spreadView |
581 | objectName: "spreadView" |
582 | anchors.fill: parent |
583 | - interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) && draggedIndex == -1 |
584 | + interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) |
585 | + && draggedDelegateCount === 0 |
586 | contentWidth: spreadRow.width - shift |
587 | contentX: -shift |
588 | |
589 | @@ -148,7 +162,7 @@ |
590 | property int phase: 0 |
591 | |
592 | property int selectedIndex: -1 |
593 | - property int draggedIndex: -1 |
594 | + property int draggedDelegateCount: 0 |
595 | property int closingIndex: -1 |
596 | |
597 | property bool focusChanging: false |
598 | @@ -269,7 +283,7 @@ |
599 | swipeToCloseEnabled: spreadView.interactive |
600 | maximizedAppTopMargin: root.maximizedAppTopMargin |
601 | dropShadow: spreadView.active || |
602 | - priv.focusedAppDelegate.x !== 0 |
603 | + (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0) |
604 | |
605 | readonly property bool isDash: model.appId == "unity8-dash" |
606 | |
607 | @@ -290,6 +304,10 @@ |
608 | // Otherwise line up for the spread |
609 | return spreadView.width + (index - 1) * spreadView.tileDistance; |
610 | } |
611 | + |
612 | + application: ApplicationManager.get(index) |
613 | + closeable: !isDash |
614 | + |
615 | property real behavioredIndex: index |
616 | Behavior on behavioredIndex { |
617 | enabled: spreadView.closingIndex >= 0 |
618 | @@ -372,8 +390,15 @@ |
619 | } |
620 | } |
621 | |
622 | + onDraggedChanged: { |
623 | + if (dragged) { |
624 | + spreadView.draggedDelegateCount++; |
625 | + } else { |
626 | + spreadView.draggedDelegateCount--; |
627 | + } |
628 | + } |
629 | + |
630 | onClosed: { |
631 | - spreadView.draggedIndex = -1; |
632 | spreadView.closingIndex = index; |
633 | ApplicationManager.stopApplication(ApplicationManager.get(index).appId); |
634 | } |
635 | |
636 | === modified file 'qml/Stages/SpreadDelegate.qml' |
637 | --- qml/Stages/SpreadDelegate.qml 2014-08-08 09:40:41 +0000 |
638 | +++ qml/Stages/SpreadDelegate.qml 2014-08-21 13:12:27 +0000 |
639 | @@ -14,75 +14,43 @@ |
640 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
641 | * |
642 | * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
643 | -*/ |
644 | + * Daniel d'Andrada <daniel.dandrada@canonical.com> |
645 | + */ |
646 | |
647 | import QtQuick 2.0 |
648 | -import Unity.Application 0.1 |
649 | import Ubuntu.Components 1.1 |
650 | import "../Components" |
651 | |
652 | Item { |
653 | id: root |
654 | |
655 | + // to be read from outside |
656 | + readonly property bool dragged: dragArea.moving |
657 | + signal clicked() |
658 | + signal closed() |
659 | + |
660 | // to be set from outside |
661 | property bool interactive: true |
662 | property bool dropShadow: true |
663 | property real maximizedAppTopMargin |
664 | property alias swipeToCloseEnabled: dragArea.enabled |
665 | - |
666 | - readonly property bool isFullscreen: surface !== null && surfaceContainer.surface.anchors.topMargin == 0 |
667 | - |
668 | - signal clicked() |
669 | - signal closed() |
670 | - |
671 | - AppSurfaceContainer { |
672 | - id: surfaceContainer |
673 | - objectName: "surfaceContainer" |
674 | - anchors.fill: parent |
675 | - surface: model.surface |
676 | - promptSurfaces: model.application.promptSurfaces |
677 | - |
678 | - Binding { |
679 | - target: surfaceContainer.surface |
680 | - property: "anchors.topMargin" |
681 | - value: { |
682 | - return surfaceContainer.surface.state === MirSurfaceItem.Fullscreen ? 0 : maximizedAppTopMargin; |
683 | - } |
684 | - } |
685 | - |
686 | - Binding { |
687 | - target: surface |
688 | - property: "enabled" |
689 | - value: root.interactive |
690 | - } |
691 | - Binding { |
692 | - target: surface |
693 | - property: "focus" |
694 | - value: root.interactive |
695 | - } |
696 | - |
697 | - Connections { |
698 | - target: surface |
699 | - // FIXME: I would rather not need to do this, but currently it doesn't get |
700 | - // active focus without it and I don't know why. |
701 | - onFocusChanged: forceSurfaceActiveFocusIfReady(); |
702 | - onParentChanged: forceSurfaceActiveFocusIfReady(); |
703 | - onEnabledChanged: forceSurfaceActiveFocusIfReady(); |
704 | - function forceSurfaceActiveFocusIfReady() { |
705 | - if (surface.focus && surface.parent === surfaceContainer && surface.enabled) { |
706 | - surface.forceActiveFocus(); |
707 | - } |
708 | - } |
709 | - } |
710 | + property bool closeable |
711 | + property alias application: appWindow.application |
712 | + |
713 | + Item { |
714 | + objectName: "appWindowWithShadow" |
715 | + |
716 | + y: dragArea.distance |
717 | + width: parent.width |
718 | + height: parent.height |
719 | |
720 | BorderImage { |
721 | - id: dropShadowImage |
722 | anchors { |
723 | - fill: parent |
724 | + fill: appWindow |
725 | leftMargin: -units.gu(2) |
726 | rightMargin: -units.gu(2) |
727 | bottomMargin: -units.gu(2) |
728 | - topMargin: -units.gu(2) + (root.isFullscreen ? 0 : maximizedAppTopMargin) |
729 | + topMargin: -units.gu(2) |
730 | } |
731 | source: "graphics/dropshadow.png" |
732 | border { left: 50; right: 50; top: 50; bottom: 50 } |
733 | @@ -90,21 +58,26 @@ |
734 | Behavior on opacity { UbuntuNumberAnimation {} } |
735 | } |
736 | |
737 | - transform: Translate { |
738 | - y: dragArea.distance |
739 | + ApplicationWindow { |
740 | + id: appWindow |
741 | + anchors { |
742 | + fill: parent |
743 | + topMargin: appWindow.fullscreen ? 0 : maximizedAppTopMargin |
744 | + } |
745 | + |
746 | + interactive: root.interactive |
747 | } |
748 | } |
749 | |
750 | DraggingArea { |
751 | id: dragArea |
752 | + objectName: "dragArea" |
753 | anchors.fill: parent |
754 | |
755 | property bool moving: false |
756 | property real distance: 0 |
757 | |
758 | - onMovingChanged: { |
759 | - spreadView.draggedIndex = moving ? index : -1 |
760 | - } |
761 | + readonly property real minSpeedToClose: units.gu(40) |
762 | |
763 | onDragValueChanged: { |
764 | if (!dragging) { |
765 | @@ -123,15 +96,15 @@ |
766 | } |
767 | |
768 | onDragEnd: { |
769 | - if (model.appId == "unity8-dash") { |
770 | + if (!root.closeable) { |
771 | animation.animate("center") |
772 | return; |
773 | } |
774 | |
775 | // velocity and distance values specified by design prototype |
776 | - if ((dragVelocity < -units.gu(40) && distance < -units.gu(8)) || distance < -root.height / 2) { |
777 | + if ((dragVelocity < -minSpeedToClose && distance < -units.gu(8)) || distance < -root.height / 2) { |
778 | animation.animate("up") |
779 | - } else if ((dragVelocity > units.gu(40) && distance > units.gu(8)) || distance > root.height / 2) { |
780 | + } else if ((dragVelocity > minSpeedToClose && distance > units.gu(8)) || distance > root.height / 2) { |
781 | animation.animate("down") |
782 | } else { |
783 | animation.animate("center") |
784 | @@ -140,6 +113,7 @@ |
785 | |
786 | UbuntuNumberAnimation { |
787 | id: animation |
788 | + objectName: "closeAnimation" |
789 | target: dragArea |
790 | property: "distance" |
791 | property bool requestClose: false |
792 | @@ -164,9 +138,10 @@ |
793 | onRunningChanged: { |
794 | if (!running) { |
795 | dragArea.moving = false; |
796 | - dragArea.distance = 0; |
797 | if (requestClose) { |
798 | root.closed(); |
799 | + } else { |
800 | + dragArea.distance = 0; |
801 | } |
802 | } |
803 | } |
804 | |
805 | === modified file 'qml/Stages/SurfaceContainer.qml' |
806 | --- qml/Stages/SurfaceContainer.qml 2014-08-07 17:15:00 +0000 |
807 | +++ qml/Stages/SurfaceContainer.qml 2014-08-21 13:12:27 +0000 |
808 | @@ -45,7 +45,7 @@ |
809 | } |
810 | |
811 | Repeater { |
812 | - model: surface.childSurfaces |
813 | + model: surface ? surface.childSurfaces : null |
814 | |
815 | delegate: Loader { |
816 | z: 2 |
817 | |
818 | === modified file 'qml/Stages/TabletStage.qml' |
819 | --- qml/Stages/TabletStage.qml 2014-07-29 13:45:30 +0000 |
820 | +++ qml/Stages/TabletStage.qml 2014-08-21 13:12:27 +0000 |
821 | @@ -106,6 +106,27 @@ |
822 | } |
823 | return oneWayFlick; |
824 | } |
825 | + |
826 | + function surfaceSizer(surface) { |
827 | + surface.width = root.width; |
828 | + surface.height = root.height - maximizedAppTopMargin; |
829 | + |
830 | + if (surface.appId) { // if app side stage, set different width |
831 | + var app = ApplicationManager.findApplication(surface.appId); |
832 | + if (app && app.stage === ApplicationInfoInterface.SideStage) { |
833 | + surface.width = spreadView.sideStageWidth; |
834 | + } |
835 | + } |
836 | + |
837 | + return surface; |
838 | + } |
839 | + |
840 | + Component.onCompleted: { |
841 | + ApplicationManager.surfaceAboutToBeCreatedCallback = priv.surfaceSizer; |
842 | + } |
843 | + Component.onDestruction: { |
844 | + ApplicationManager.surfaceAboutToBeCreatedCallback = null; |
845 | + } |
846 | } |
847 | |
848 | Connections { |
849 | @@ -145,7 +166,8 @@ |
850 | Flickable { |
851 | id: spreadView |
852 | anchors.fill: parent |
853 | - interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) && draggedIndex == -1 |
854 | + interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) |
855 | + && draggedDelegateCount === 0 |
856 | contentWidth: spreadRow.width - shift |
857 | contentX: -shift |
858 | |
859 | @@ -189,7 +211,7 @@ |
860 | readonly property real snapPosition: 0.75 |
861 | |
862 | property int selectedIndex: -1 |
863 | - property int draggedIndex: -1 |
864 | + property int draggedDelegateCount: 0 |
865 | property int closingIndex: -1 |
866 | |
867 | property bool sideStageDragging: sideStageDragHandle.dragging |
868 | @@ -475,6 +497,8 @@ |
869 | swipeToCloseEnabled: spreadView.interactive |
870 | maximizedAppTopMargin: root.maximizedAppTopMargin |
871 | dragOffset: !isDash && model.appId == priv.mainStageAppId && root.inverseProgress > 0 ? root.inverseProgress : 0 |
872 | + application: ApplicationManager.get(index) |
873 | + closeable: !isDash |
874 | |
875 | readonly property bool isDash: model.appId == "unity8-dash" |
876 | |
877 | @@ -533,8 +557,15 @@ |
878 | } |
879 | } |
880 | |
881 | + onDraggedChanged: { |
882 | + if (dragged) { |
883 | + spreadView.draggedDelegateCount++; |
884 | + } else { |
885 | + spreadView.draggedDelegateCount--; |
886 | + } |
887 | + } |
888 | + |
889 | onClosed: { |
890 | - spreadView.draggedIndex = -1; |
891 | spreadView.closingIndex = index; |
892 | ApplicationManager.stopApplication(ApplicationManager.get(index).appId); |
893 | } |
894 | |
895 | === modified file 'qml/Stages/TransformedSpreadDelegate.qml' |
896 | --- qml/Stages/TransformedSpreadDelegate.qml 2014-07-29 13:45:30 +0000 |
897 | +++ qml/Stages/TransformedSpreadDelegate.qml 2014-08-21 13:12:27 +0000 |
898 | @@ -309,7 +309,7 @@ |
899 | Scale { |
900 | origin { x: 0; y: (spreadView.height * priv.scale) + maximizedAppTopMargin * 3 } |
901 | xScale: 1 |
902 | - yScale: isFullscreen ? 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height : 1 |
903 | + yScale: fullscreen ? 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height : 1 |
904 | }, |
905 | Translate { |
906 | x: priv.xTranslate |
907 | |
908 | === modified file 'tests/mocks/Unity/Application/Application.qmltypes' |
909 | --- tests/mocks/Unity/Application/Application.qmltypes 2014-08-14 01:28:06 +0000 |
910 | +++ tests/mocks/Unity/Application/Application.qmltypes 2014-08-21 13:12:27 +0000 |
911 | @@ -8,25 +8,6 @@ |
912 | |
913 | Module { |
914 | Component { |
915 | - name: "ApplicationImage" |
916 | - defaultProperty: "data" |
917 | - prototype: "QQuickItem" |
918 | - exports: ["Unity.Application/ApplicationImage 0.1"] |
919 | - exportMetaObjectRevisions: [0] |
920 | - Enum { |
921 | - name: "FillMode" |
922 | - values: { |
923 | - "Stretch": 0, |
924 | - "PreserveAspectCrop": 1 |
925 | - } |
926 | - } |
927 | - Property { name: "source"; type: "ApplicationInfo"; isPointer: true } |
928 | - Property { name: "fillMode"; type: "FillMode" } |
929 | - Property { name: "ready"; type: "bool" } |
930 | - Method { name: "scheduleUpdate" } |
931 | - Method { name: "updateFromCache" } |
932 | - } |
933 | - Component { |
934 | name: "ApplicationInfo" |
935 | prototype: "unity::shell::application::ApplicationInfoInterface" |
936 | exports: ["Unity.Application/ApplicationInfo 0.1"] |
937 | |
938 | === removed file 'tests/mocks/Unity/Application/ApplicationImage.cpp' |
939 | --- tests/mocks/Unity/Application/ApplicationImage.cpp 2013-06-05 22:03:08 +0000 |
940 | +++ tests/mocks/Unity/Application/ApplicationImage.cpp 1970-01-01 00:00:00 +0000 |
941 | @@ -1,123 +0,0 @@ |
942 | -/* |
943 | - * Copyright (C) 2013 Canonical, Ltd. |
944 | - * |
945 | - * This program is free software; you can redistribute it and/or modify |
946 | - * it under the terms of the GNU General Public License as published by |
947 | - * the Free Software Foundation; version 3. |
948 | - * |
949 | - * This program is distributed in the hope that it will be useful, |
950 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
951 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
952 | - * GNU General Public License for more details. |
953 | - * |
954 | - * You should have received a copy of the GNU General Public License |
955 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
956 | - */ |
957 | - |
958 | -#include "ApplicationImage.h" |
959 | -#include "ApplicationInfo.h" |
960 | - |
961 | -#include <QQmlEngine> |
962 | -#include <QQmlComponent> |
963 | -#include <QQmlContext> |
964 | - |
965 | -ApplicationImage::ApplicationImage(QQuickItem* parent) |
966 | - : QQuickItem(parent), |
967 | - m_source(NULL), |
968 | - m_fillMode(Stretch), |
969 | - m_ready(false), |
970 | - m_imageComponent(0), |
971 | - m_imageItem(0) |
972 | -{ |
973 | -} |
974 | - |
975 | -void ApplicationImage::setSource(ApplicationInfo* source) |
976 | -{ |
977 | - if (m_source != source) { |
978 | - if (m_source) |
979 | - disconnect(m_source, &ApplicationInfo::imageQmlChanged, |
980 | - this, &ApplicationImage::updateImage); |
981 | - |
982 | - m_source = source; |
983 | - |
984 | - if (m_source) { |
985 | - connect(m_source, &ApplicationInfo::imageQmlChanged, |
986 | - this, &ApplicationImage::updateImage); |
987 | - } |
988 | - updateImage(); |
989 | - |
990 | - Q_EMIT sourceChanged(); |
991 | - } |
992 | -} |
993 | - |
994 | -void ApplicationImage::setFillMode(FillMode newFillMode) |
995 | -{ |
996 | - if (m_fillMode != newFillMode) { |
997 | - m_fillMode = newFillMode; |
998 | - Q_EMIT fillModeChanged(); |
999 | - } |
1000 | -} |
1001 | - |
1002 | -void ApplicationImage::setReady(bool value) |
1003 | -{ |
1004 | - if (value != m_ready) { |
1005 | - m_ready = value; |
1006 | - Q_EMIT readyChanged(); |
1007 | - } |
1008 | -} |
1009 | - |
1010 | -void ApplicationImage::destroyImage() |
1011 | -{ |
1012 | - delete m_imageItem; |
1013 | - m_imageItem = 0; |
1014 | - delete m_imageComponent; |
1015 | - m_imageComponent = 0; |
1016 | - m_qmlUsed.clear(); |
1017 | - setReady(false); |
1018 | -} |
1019 | - |
1020 | -void ApplicationImage::updateImage() |
1021 | -{ |
1022 | - if (!m_source || m_source->imageQml().isEmpty()) { |
1023 | - destroyImage(); |
1024 | - } else if (m_source->imageQml() != m_qmlUsed) { |
1025 | - destroyImage(); |
1026 | - createImageItem(); |
1027 | - } |
1028 | -} |
1029 | - |
1030 | -void ApplicationImage::createImageItem() |
1031 | -{ |
1032 | - |
1033 | - if (!m_imageComponent) |
1034 | - createImageComponent(); |
1035 | - |
1036 | - // only create the windowItem one the component is ready |
1037 | - if (!m_imageComponent->isReady()) { |
1038 | - connect(m_imageComponent, &QQmlComponent::statusChanged, |
1039 | - this, &ApplicationImage::onImageComponentStatusChanged); |
1040 | - } else { |
1041 | - doCreateImageItem(); |
1042 | - } |
1043 | - |
1044 | -} |
1045 | - |
1046 | -void ApplicationImage::createImageComponent() |
1047 | -{ |
1048 | - QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine(); |
1049 | - m_imageComponent = new QQmlComponent(engine, this); |
1050 | - m_imageComponent->setData(m_source->imageQml().toLatin1(), QUrl()); |
1051 | -} |
1052 | - |
1053 | -void ApplicationImage::doCreateImageItem() |
1054 | -{ |
1055 | - m_imageItem = qobject_cast<QQuickItem *>(m_imageComponent->create()); |
1056 | - m_imageItem->setParentItem(this); |
1057 | - setReady(true); |
1058 | -} |
1059 | - |
1060 | -void ApplicationImage::onImageComponentStatusChanged(QQmlComponent::Status status) |
1061 | -{ |
1062 | - if (status == QQmlComponent::Ready && !m_imageItem) |
1063 | - doCreateImageItem(); |
1064 | -} |
1065 | |
1066 | === removed file 'tests/mocks/Unity/Application/ApplicationImage.h' |
1067 | --- tests/mocks/Unity/Application/ApplicationImage.h 2013-06-05 22:03:08 +0000 |
1068 | +++ tests/mocks/Unity/Application/ApplicationImage.h 1970-01-01 00:00:00 +0000 |
1069 | @@ -1,79 +0,0 @@ |
1070 | -/* |
1071 | - * Copyright (C) 2013 Canonical, Ltd. |
1072 | - * |
1073 | - * This program is free software; you can redistribute it and/or modify |
1074 | - * it under the terms of the GNU General Public License as published by |
1075 | - * the Free Software Foundation; version 3. |
1076 | - * |
1077 | - * This program is distributed in the hope that it will be useful, |
1078 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1079 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1080 | - * GNU General Public License for more details. |
1081 | - * |
1082 | - * You should have received a copy of the GNU General Public License |
1083 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1084 | - */ |
1085 | - |
1086 | -#ifndef APPLICATION_IMAGE_H |
1087 | -#define APPLICATION_IMAGE_H |
1088 | - |
1089 | -#include <QQuickItem> |
1090 | - |
1091 | -class ApplicationInfo; |
1092 | - |
1093 | -/* Fake implementation of ApplicationImage |
1094 | - |
1095 | - That fake implementation is not made in QML just because we can only declare |
1096 | - enumerations in C++. We can't even make readonly properties to mimic an enum |
1097 | - because properties must begin with a lower case letter. |
1098 | -*/ |
1099 | -class ApplicationImage : public QQuickItem { |
1100 | - Q_OBJECT |
1101 | - Q_ENUMS(FillMode) |
1102 | - Q_PROPERTY(ApplicationInfo* source READ source WRITE setSource NOTIFY sourceChanged) |
1103 | - Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) |
1104 | - Q_PROPERTY(bool ready READ ready WRITE setReady NOTIFY readyChanged) |
1105 | - |
1106 | -public: |
1107 | - explicit ApplicationImage(QQuickItem* parent = 0); |
1108 | - virtual ~ApplicationImage() {} |
1109 | - |
1110 | - enum FillMode { Stretch, PreserveAspectCrop }; |
1111 | - |
1112 | - ApplicationInfo* source() const { return m_source; } |
1113 | - void setSource(ApplicationInfo* source); |
1114 | - |
1115 | - FillMode fillMode() const { return m_fillMode; } |
1116 | - void setFillMode(FillMode); |
1117 | - |
1118 | - void setReady(bool value); |
1119 | - bool ready() const { return m_ready; } |
1120 | - |
1121 | - Q_INVOKABLE void scheduleUpdate() {} |
1122 | - Q_INVOKABLE void updateFromCache() {} |
1123 | - |
1124 | -Q_SIGNALS: |
1125 | - void sourceChanged(); |
1126 | - void fillModeChanged(); |
1127 | - void readyChanged(); |
1128 | - |
1129 | -private Q_SLOTS: |
1130 | - void updateImage(); |
1131 | - void onImageComponentStatusChanged(QQmlComponent::Status status); |
1132 | - |
1133 | -private: |
1134 | - void createImageItem(); |
1135 | - void createImageComponent(); |
1136 | - void doCreateImageItem(); |
1137 | - void destroyImage(); |
1138 | - |
1139 | - ApplicationInfo* m_source; |
1140 | - FillMode m_fillMode; |
1141 | - bool m_ready; |
1142 | - QQmlComponent *m_imageComponent; |
1143 | - QQuickItem* m_imageItem; |
1144 | - // the QML script used to create the current m_imageItem |
1145 | - QString m_qmlUsed; |
1146 | -}; |
1147 | - |
1148 | -#endif // APPLICATION_IMAGE_H |
1149 | |
1150 | === modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp' |
1151 | --- tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-08-16 16:38:43 +0000 |
1152 | +++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-08-21 13:12:27 +0000 |
1153 | @@ -18,6 +18,8 @@ |
1154 | #include "MirSurfaceItem.h" |
1155 | #include "SurfaceManager.h" |
1156 | |
1157 | +#include <paths.h> |
1158 | + |
1159 | #include <QGuiApplication> |
1160 | #include <QQuickItem> |
1161 | #include <QQuickView> |
1162 | @@ -31,10 +33,10 @@ |
1163 | , m_state(Starting) |
1164 | , m_focused(false) |
1165 | , m_fullscreen(false) |
1166 | + , m_surface(0) |
1167 | + , m_manualSurfaceCreation(false) |
1168 | , m_parentItem(0) |
1169 | - , m_surface(0) |
1170 | { |
1171 | - connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged); |
1172 | } |
1173 | |
1174 | ApplicationInfo::ApplicationInfo(QObject *parent) |
1175 | @@ -43,10 +45,10 @@ |
1176 | , m_state(Starting) |
1177 | , m_focused(false) |
1178 | , m_fullscreen(false) |
1179 | + , m_surface(0) |
1180 | + , m_manualSurfaceCreation(false) |
1181 | , m_parentItem(0) |
1182 | - , m_surface(0) |
1183 | { |
1184 | - connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged); |
1185 | } |
1186 | |
1187 | ApplicationInfo::~ApplicationInfo() |
1188 | @@ -58,28 +60,21 @@ |
1189 | } |
1190 | } |
1191 | |
1192 | -void ApplicationInfo::onStateChanged(State state) |
1193 | -{ |
1194 | - if (state == ApplicationInfo::Running) { |
1195 | - QTimer::singleShot(1000, this, SLOT(createSurface())); |
1196 | - } else if (state == ApplicationInfo::Stopped) { |
1197 | - setSurface(nullptr); |
1198 | - } |
1199 | -} |
1200 | - |
1201 | void ApplicationInfo::createSurface() |
1202 | { |
1203 | if (m_surface || state() == ApplicationInfo::Stopped) return; |
1204 | |
1205 | + QUrl screenshotUrl = QString("file://%1").arg(m_screenshotFileName); |
1206 | + |
1207 | setSurface(new MirSurfaceItem(name(), |
1208 | MirSurfaceItem::Normal, |
1209 | fullscreen() ? MirSurfaceItem::Fullscreen : MirSurfaceItem::Maximized, |
1210 | - screenshot())); |
1211 | + screenshotUrl)); |
1212 | } |
1213 | |
1214 | void ApplicationInfo::setSurface(MirSurfaceItem* surface) |
1215 | { |
1216 | - qDebug() << "Application::setSurface - appId=" << appId() << "surface=" << surface; |
1217 | + qDebug() << "Application::setSurface - appId=" << appId() << "surface=" << (surface ? surface->name() : "null"); |
1218 | if (m_surface == surface) |
1219 | return; |
1220 | |
1221 | @@ -98,7 +93,6 @@ |
1222 | } |
1223 | |
1224 | Q_EMIT surfaceChanged(m_surface); |
1225 | - SurfaceManager::singleton()->registerSurface(m_surface); |
1226 | } |
1227 | |
1228 | void ApplicationInfo::addPromptSurface(MirSurfaceItem* surface) |
1229 | @@ -152,3 +146,77 @@ |
1230 | return nullptr; |
1231 | return p->m_promptSurfaces[index]; |
1232 | } |
1233 | + |
1234 | +void ApplicationInfo::setIconId(const QString &iconId) |
1235 | +{ |
1236 | + setIcon(QString("file://%1/graphics/applicationIcons/%2@18.png") |
1237 | + .arg(qmlDirectory()) |
1238 | + .arg(iconId)); |
1239 | +} |
1240 | + |
1241 | +void ApplicationInfo::setScreenshotId(const QString &screenshotId) |
1242 | +{ |
1243 | + m_screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png") |
1244 | + .arg(qmlDirectory()) |
1245 | + .arg(screenshotId); |
1246 | +} |
1247 | + |
1248 | +void ApplicationInfo::setName(const QString &value) |
1249 | +{ |
1250 | + if (value != m_name) { |
1251 | + m_name = value; |
1252 | + Q_EMIT nameChanged(value); |
1253 | + } |
1254 | +} |
1255 | + |
1256 | +void ApplicationInfo::setIcon(const QUrl &value) |
1257 | +{ |
1258 | + if (value != m_icon) { |
1259 | + m_icon = value; |
1260 | + Q_EMIT iconChanged(value); |
1261 | + } |
1262 | +} |
1263 | + |
1264 | +void ApplicationInfo::setStage(Stage value) |
1265 | +{ |
1266 | + if (value != m_stage) { |
1267 | + m_stage = value; |
1268 | + Q_EMIT stageChanged(value); |
1269 | + } |
1270 | +} |
1271 | + |
1272 | +void ApplicationInfo::setState(State value) |
1273 | +{ |
1274 | + if (value != m_state) { |
1275 | + m_state = value; |
1276 | + Q_EMIT stateChanged(value); |
1277 | + |
1278 | + if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) { |
1279 | + QTimer::singleShot(1000, this, SLOT(createSurface())); |
1280 | + } |
1281 | + } |
1282 | +} |
1283 | + |
1284 | +void ApplicationInfo::setFocused(bool value) |
1285 | +{ |
1286 | + if (value != m_focused) { |
1287 | + m_focused = value; |
1288 | + Q_EMIT focusedChanged(value); |
1289 | + } |
1290 | +} |
1291 | + |
1292 | +void ApplicationInfo::setFullscreen(bool value) |
1293 | +{ |
1294 | + if (value != m_fullscreen) { |
1295 | + m_fullscreen = value; |
1296 | + Q_EMIT fullscreenChanged(value); |
1297 | + } |
1298 | +} |
1299 | + |
1300 | +void ApplicationInfo::setManualSurfaceCreation(bool value) |
1301 | +{ |
1302 | + if (value != m_manualSurfaceCreation) { |
1303 | + m_manualSurfaceCreation = value; |
1304 | + Q_EMIT manualSurfaceCreationChanged(value); |
1305 | + } |
1306 | +} |
1307 | |
1308 | === modified file 'tests/mocks/Unity/Application/ApplicationInfo.h' |
1309 | --- tests/mocks/Unity/Application/ApplicationInfo.h 2014-08-07 17:15:00 +0000 |
1310 | +++ tests/mocks/Unity/Application/ApplicationInfo.h 2014-08-21 13:12:27 +0000 |
1311 | @@ -26,63 +26,52 @@ |
1312 | // unity-api |
1313 | #include <unity/shell/application/ApplicationInfoInterface.h> |
1314 | |
1315 | -// A pretty dumb file. Just a container for properties. |
1316 | -// Implemented in C++ instead of QML just because of the enumerations |
1317 | -// See QTBUG-14861 |
1318 | - |
1319 | using namespace unity::shell::application; |
1320 | |
1321 | class ApplicationInfo : public ApplicationInfoInterface { |
1322 | Q_OBJECT |
1323 | |
1324 | Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged) |
1325 | - Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged) |
1326 | Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged) |
1327 | Q_PROPERTY(QQmlListProperty<MirSurfaceItem> promptSurfaces READ promptSurfaces NOTIFY promptSurfacesChanged DESIGNABLE false) |
1328 | |
1329 | // Only exists in this fake implementation |
1330 | |
1331 | - // QML component used to represent its image/screenhot |
1332 | - Q_PROPERTY(QString imageQml READ imageQml WRITE setImageQml NOTIFY imageQmlChanged) |
1333 | - |
1334 | - // QML component used to represent the application window |
1335 | - Q_PROPERTY(QString windowQml READ windowQml WRITE setWindowQml NOTIFY windowQmlChanged) |
1336 | + // whether the test code will explicitly control the creation of the application surface |
1337 | + Q_PROPERTY(bool manualSurfaceCreation READ manualSurfaceCreation WRITE setManualSurfaceCreation NOTIFY manualSurfaceCreationChanged) |
1338 | |
1339 | public: |
1340 | ApplicationInfo(QObject *parent = NULL); |
1341 | ApplicationInfo(const QString &appId, QObject *parent = NULL); |
1342 | ~ApplicationInfo(); |
1343 | |
1344 | - #define IMPLEMENT_PROPERTY(name, Name, type) \ |
1345 | - public: \ |
1346 | - type name() const { return m_##name; } \ |
1347 | - void set##Name(const type& value) \ |
1348 | - { \ |
1349 | - if (m_##name != value) { \ |
1350 | - m_##name = value; \ |
1351 | - Q_EMIT name##Changed(value); \ |
1352 | - } \ |
1353 | - } \ |
1354 | - Q_SIGNALS: \ |
1355 | - void name##Changed(const type&); \ |
1356 | - private: \ |
1357 | - type m_##name; |
1358 | - |
1359 | - IMPLEMENT_PROPERTY(appId, AppId, QString) |
1360 | - IMPLEMENT_PROPERTY(name, Name, QString) |
1361 | - IMPLEMENT_PROPERTY(comment, Comment, QString) |
1362 | - IMPLEMENT_PROPERTY(icon, Icon, QUrl) |
1363 | - IMPLEMENT_PROPERTY(stage, Stage, Stage) |
1364 | - IMPLEMENT_PROPERTY(state, State, State) |
1365 | - IMPLEMENT_PROPERTY(focused, Focused, bool) |
1366 | - IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool) |
1367 | - IMPLEMENT_PROPERTY(imageQml, ImageQml, QString) |
1368 | - IMPLEMENT_PROPERTY(windowQml, WindowQml, QString) |
1369 | - IMPLEMENT_PROPERTY(screenshot, Screenshot, QUrl) |
1370 | - |
1371 | - #undef IMPLEMENT_PROPERTY |
1372 | - |
1373 | -public: |
1374 | + void setIconId(const QString &iconId); |
1375 | + void setScreenshotId(const QString &screenshotId); |
1376 | + |
1377 | + void setAppId(const QString &value) { m_appId = value; } |
1378 | + QString appId() const override { return m_appId; } |
1379 | + |
1380 | + void setName(const QString &value); |
1381 | + QString name() const override { return m_name; } |
1382 | + |
1383 | + QString comment() const override { return QString(); } |
1384 | + |
1385 | + QUrl icon() const override { return m_icon; } |
1386 | + |
1387 | + void setStage(Stage value); |
1388 | + Stage stage() const override { return m_stage; } |
1389 | + |
1390 | + Q_INVOKABLE void setState(State value); |
1391 | + State state() const override { return m_state; } |
1392 | + |
1393 | + void setFocused(bool value); |
1394 | + bool focused() const override { return m_focused; } |
1395 | + |
1396 | + QString screenshot() const { return m_screenshotFileName; } |
1397 | + |
1398 | + void setFullscreen(bool value); |
1399 | + bool fullscreen() const { return m_fullscreen; } |
1400 | + |
1401 | void setSurface(MirSurfaceItem* surface); |
1402 | MirSurfaceItem* surface() const { return m_surface; } |
1403 | |
1404 | @@ -92,21 +81,38 @@ |
1405 | QList<MirSurfaceItem*> promptSurfaceList() const; |
1406 | QQmlListProperty<MirSurfaceItem> promptSurfaces(); |
1407 | |
1408 | + bool manualSurfaceCreation() const { return m_manualSurfaceCreation; } |
1409 | + void setManualSurfaceCreation(bool value); |
1410 | + |
1411 | Q_SIGNALS: |
1412 | void surfaceChanged(MirSurfaceItem*); |
1413 | void promptSurfacesChanged(); |
1414 | - |
1415 | -private Q_SLOTS: |
1416 | - void onStateChanged(State state); |
1417 | - |
1418 | - void createSurface(); |
1419 | + void fullscreenChanged(bool value); |
1420 | + void manualSurfaceCreationChanged(bool value); |
1421 | + |
1422 | +public Q_SLOTS: |
1423 | + Q_INVOKABLE void createSurface(); |
1424 | |
1425 | private: |
1426 | static int promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop); |
1427 | static MirSurfaceItem* promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index); |
1428 | + void setIcon(const QUrl &value); |
1429 | + void setScreenshot(const QUrl &value); |
1430 | + |
1431 | + QString m_screenshotFileName; |
1432 | + |
1433 | + QString m_appId; |
1434 | + QString m_name; |
1435 | + QUrl m_icon; |
1436 | + Stage m_stage; |
1437 | + State m_state; |
1438 | + bool m_focused; |
1439 | + bool m_fullscreen; |
1440 | + MirSurfaceItem* m_surface; |
1441 | + |
1442 | + bool m_manualSurfaceCreation; |
1443 | |
1444 | QQuickItem *m_parentItem; |
1445 | - MirSurfaceItem* m_surface; |
1446 | QList<MirSurfaceItem*> m_promptSurfaces; |
1447 | }; |
1448 | |
1449 | |
1450 | === modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp' |
1451 | --- tests/mocks/Unity/Application/ApplicationManager.cpp 2014-08-07 17:15:00 +0000 |
1452 | +++ tests/mocks/Unity/Application/ApplicationManager.cpp 2014-08-21 13:12:27 +0000 |
1453 | @@ -48,6 +48,7 @@ |
1454 | ApplicationManager::ApplicationManager(QObject *parent) |
1455 | : ApplicationManagerInterface(parent) |
1456 | , m_suspended(false) |
1457 | + , m_surfaceAboutToBeCreatedCallback(QJSValue::UndefinedValue) |
1458 | { |
1459 | m_roleNames.insert(RoleSurface, "surface"); |
1460 | m_roleNames.insert(RoleFullscreen, "fullscreen"); |
1461 | @@ -55,14 +56,32 @@ |
1462 | |
1463 | buildListOfAvailableApplications(); |
1464 | |
1465 | + // polling to find out when the toplevel window has been created as there's |
1466 | + // no signal telling us that |
1467 | + connect(&m_windowCreatedTimer, &QTimer::timeout, |
1468 | + this, &ApplicationManager::onWindowCreatedTimerTimeout); |
1469 | + m_windowCreatedTimer.setSingleShot(false); |
1470 | + m_windowCreatedTimer.start(200); |
1471 | +} |
1472 | + |
1473 | +ApplicationManager::~ApplicationManager() |
1474 | +{ |
1475 | +} |
1476 | + |
1477 | +void ApplicationManager::onWindowCreatedTimerTimeout() |
1478 | +{ |
1479 | + if (QGuiApplication::topLevelWindows().count() > 0) { |
1480 | + m_windowCreatedTimer.stop(); |
1481 | + onWindowCreated(); |
1482 | + } |
1483 | +} |
1484 | + |
1485 | +void ApplicationManager::onWindowCreated() |
1486 | +{ |
1487 | startApplication("unity8-dash"); |
1488 | focusApplication("unity8-dash"); |
1489 | } |
1490 | |
1491 | -ApplicationManager::~ApplicationManager() |
1492 | -{ |
1493 | -} |
1494 | - |
1495 | int ApplicationManager::rowCount(const QModelIndex& parent) const { |
1496 | return !parent.isValid() ? m_runningApplications.size() : 0; |
1497 | } |
1498 | @@ -87,8 +106,6 @@ |
1499 | return app->state(); |
1500 | case RoleFocused: |
1501 | return app->focused(); |
1502 | - case RoleScreenshot: |
1503 | - return app->screenshot(); |
1504 | case RoleSurface: |
1505 | return QVariant::fromValue(app->surface()); |
1506 | case RoleFullscreen: |
1507 | @@ -143,6 +160,16 @@ |
1508 | if (!appIndex.isValid()) return; |
1509 | Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleSurface); |
1510 | }); |
1511 | + connect(application, &ApplicationInfo::focusedChanged, this, [application, this]() { |
1512 | + QModelIndex appIndex = findIndex(application); |
1513 | + if (!appIndex.isValid()) return; |
1514 | + Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleFocused); |
1515 | + }); |
1516 | + connect(application, &ApplicationInfo::stateChanged, this, [application, this]() { |
1517 | + QModelIndex appIndex = findIndex(application); |
1518 | + if (!appIndex.isValid()) return; |
1519 | + Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleState); |
1520 | + }); |
1521 | } |
1522 | |
1523 | void ApplicationManager::remove(ApplicationInfo *application) { |
1524 | @@ -155,7 +182,7 @@ |
1525 | Q_EMIT countChanged(); |
1526 | if (isEmpty()) Q_EMIT emptyChanged(isEmpty()); |
1527 | } |
1528 | - disconnect(application, &ApplicationInfo::surfaceChanged, this, 0); |
1529 | + disconnect(application, 0, this, 0); |
1530 | } |
1531 | |
1532 | void ApplicationManager::move(int from, int to) { |
1533 | @@ -198,15 +225,7 @@ |
1534 | const QStringList &arguments) |
1535 | { |
1536 | Q_UNUSED(arguments) |
1537 | - ApplicationInfo *application = 0; |
1538 | - |
1539 | - for (ApplicationInfo *availableApp : m_availableApplications) { |
1540 | - if (availableApp->appId() == appId) { |
1541 | - application = availableApp; |
1542 | - break; |
1543 | - } |
1544 | - } |
1545 | - |
1546 | + ApplicationInfo *application = add(appId); |
1547 | if (!application) |
1548 | return 0; |
1549 | |
1550 | @@ -214,12 +233,28 @@ |
1551 | && application->stage() == ApplicationInfo::SideStage) { |
1552 | application->setStage(ApplicationInfo::MainStage); |
1553 | } |
1554 | - add(application); |
1555 | application->setState(ApplicationInfo::Running); |
1556 | |
1557 | return application; |
1558 | } |
1559 | |
1560 | +ApplicationInfo* ApplicationManager::add(QString appId) |
1561 | +{ |
1562 | + ApplicationInfo *application = 0; |
1563 | + |
1564 | + for (ApplicationInfo *availableApp : m_availableApplications) { |
1565 | + if (availableApp->appId() == appId) { |
1566 | + application = availableApp; |
1567 | + break; |
1568 | + } |
1569 | + } |
1570 | + |
1571 | + if (application) |
1572 | + add(application); |
1573 | + |
1574 | + return application; |
1575 | +} |
1576 | + |
1577 | bool ApplicationManager::stopApplication(const QString &appId) |
1578 | { |
1579 | if (appId == "unity8-dash") { |
1580 | @@ -238,27 +273,6 @@ |
1581 | return true; |
1582 | } |
1583 | |
1584 | -bool ApplicationManager::updateScreenshot(const QString &appId) |
1585 | -{ |
1586 | - int idx = -1; |
1587 | - ApplicationInfo *application = nullptr; |
1588 | - for (int i = 0; i < m_availableApplications.count(); ++i) { |
1589 | - application = m_availableApplications.at(i); |
1590 | - if (application->appId() == appId) { |
1591 | - idx = i; |
1592 | - break; |
1593 | - } |
1594 | - } |
1595 | - |
1596 | - if (idx == -1) { |
1597 | - return false; |
1598 | - } |
1599 | - |
1600 | - QModelIndex appIndex = index(idx); |
1601 | - Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleScreenshot); |
1602 | - return true; |
1603 | -} |
1604 | - |
1605 | QString ApplicationManager::focusedApplicationId() const { |
1606 | for (ApplicationInfo *app : m_runningApplications) { |
1607 | if (app->focused()) { |
1608 | @@ -293,32 +307,18 @@ |
1609 | if (application == nullptr) |
1610 | return false; |
1611 | |
1612 | - if (application->stage() == ApplicationInfo::MainStage) { |
1613 | - // unfocus currently focused mainstage app |
1614 | - for (ApplicationInfo *app : m_runningApplications) { |
1615 | - if (app->focused() && app->stage() == ApplicationInfo::MainStage) { |
1616 | - app->setFocused(false); |
1617 | - app->setState(ApplicationInfo::Suspended); |
1618 | - } |
1619 | - } |
1620 | - |
1621 | - // focus this app |
1622 | - application->setFocused(true); |
1623 | - application->setState(ApplicationInfo::Running); |
1624 | - } else if (application->stage() == ApplicationInfo::SideStage) { |
1625 | - // unfocus currently focused sidestage app |
1626 | - for (ApplicationInfo *app : m_runningApplications) { |
1627 | - if (app->focused() && app->stage() == ApplicationInfo::SideStage) { |
1628 | - app->setFocused(false); |
1629 | - app->setState(ApplicationInfo::Suspended); |
1630 | - } |
1631 | - } |
1632 | - |
1633 | - // focus this app |
1634 | - application->setFocused(true); |
1635 | - application->setState(ApplicationInfo::Running); |
1636 | + // unfocus currently focused app |
1637 | + for (ApplicationInfo *app : m_runningApplications) { |
1638 | + if (app->focused()) { |
1639 | + app->setFocused(false); |
1640 | + app->setState(ApplicationInfo::Suspended); |
1641 | + } |
1642 | } |
1643 | |
1644 | + // focus this app |
1645 | + application->setFocused(true); |
1646 | + application->setState(ApplicationInfo::Running); |
1647 | + |
1648 | // move app to top of stack |
1649 | move(m_runningApplications.indexOf(application), 0); |
1650 | Q_EMIT focusedApplicationIdChanged(); |
1651 | @@ -341,10 +341,23 @@ |
1652 | Q_EMIT focusedApplicationIdChanged(); |
1653 | } |
1654 | |
1655 | -void ApplicationManager::generateQmlStrings(ApplicationInfo *application) |
1656 | -{ |
1657 | - application->setScreenshot(QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory()) |
1658 | - .arg(application->icon().toString())); |
1659 | +QJSValue ApplicationManager::surfaceAboutToBeCreatedCallback() const |
1660 | +{ |
1661 | + return m_surfaceAboutToBeCreatedCallback; |
1662 | +} |
1663 | + |
1664 | +void ApplicationManager::setSurfaceAboutToBeCreatedCallback(const QJSValue &callback) |
1665 | +{ |
1666 | + if (m_surfaceAboutToBeCreatedCallback.equals(callback)) |
1667 | + return; |
1668 | + |
1669 | + if (callback.isCallable()) { |
1670 | + m_surfaceAboutToBeCreatedCallback = callback; |
1671 | + } else { |
1672 | + qWarning() << "ApplicationManager::setSurfaceAboutToBeCreatedCallback - attempted to register a non-function!"; |
1673 | + m_surfaceAboutToBeCreatedCallback = QJSValue::UndefinedValue; |
1674 | + } |
1675 | + Q_EMIT surfaceAboutToBeCreatedCallbackChanged(); |
1676 | } |
1677 | |
1678 | void ApplicationManager::buildListOfAvailableApplications() |
1679 | @@ -354,128 +367,120 @@ |
1680 | application = new ApplicationInfo(this); |
1681 | application->setAppId("unity8-dash"); |
1682 | application->setName("Unity 8 Mock Dash"); |
1683 | - application->setIcon(QUrl("unity8-dash")); |
1684 | + application->setScreenshotId("unity8-dash"); |
1685 | application->setStage(ApplicationInfo::MainStage); |
1686 | - generateQmlStrings(application); |
1687 | m_availableApplications.append(application); |
1688 | |
1689 | application = new ApplicationInfo(this); |
1690 | application->setAppId("dialer-app"); |
1691 | application->setName("Dialer"); |
1692 | - application->setIcon(QUrl("dialer")); |
1693 | + application->setScreenshotId("dialer"); |
1694 | + application->setIconId("dialer-app"); |
1695 | application->setStage(ApplicationInfo::SideStage); |
1696 | - generateQmlStrings(application); |
1697 | m_availableApplications.append(application); |
1698 | |
1699 | application = new ApplicationInfo(this); |
1700 | application->setAppId("camera-app"); |
1701 | application->setName("Camera"); |
1702 | - application->setIcon(QUrl("camera")); |
1703 | + application->setScreenshotId("camera"); |
1704 | + application->setIconId("camera"); |
1705 | application->setFullscreen(true); |
1706 | - generateQmlStrings(application); |
1707 | m_availableApplications.append(application); |
1708 | |
1709 | application = new ApplicationInfo(this); |
1710 | application->setAppId("gallery-app"); |
1711 | application->setName("Gallery"); |
1712 | - application->setIcon(QUrl("gallery")); |
1713 | - generateQmlStrings(application); |
1714 | + application->setScreenshotId("gallery"); |
1715 | + application->setIconId("gallery"); |
1716 | + application->setFullscreen(true); |
1717 | m_availableApplications.append(application); |
1718 | |
1719 | application = new ApplicationInfo(this); |
1720 | application->setAppId("facebook-webapp"); |
1721 | application->setName("Facebook"); |
1722 | - application->setIcon(QUrl("facebook")); |
1723 | + application->setScreenshotId("facebook"); |
1724 | + application->setIconId("facebook"); |
1725 | application->setStage(ApplicationInfo::SideStage); |
1726 | - generateQmlStrings(application); |
1727 | m_availableApplications.append(application); |
1728 | |
1729 | application = new ApplicationInfo(this); |
1730 | application->setAppId("webbrowser-app"); |
1731 | application->setFullscreen(true); |
1732 | application->setName("Browser"); |
1733 | - application->setIcon(QUrl("browser")); |
1734 | - generateQmlStrings(application); |
1735 | + application->setScreenshotId("browser"); |
1736 | + application->setIconId("browser"); |
1737 | m_availableApplications.append(application); |
1738 | |
1739 | application = new ApplicationInfo(this); |
1740 | application->setAppId("twitter-webapp"); |
1741 | application->setName("Twitter"); |
1742 | - application->setIcon(QUrl("twitter")); |
1743 | + application->setScreenshotId("twitter"); |
1744 | + application->setIconId("twitter"); |
1745 | application->setStage(ApplicationInfo::SideStage); |
1746 | - generateQmlStrings(application); |
1747 | + m_availableApplications.append(application); |
1748 | + |
1749 | + application = new ApplicationInfo(this); |
1750 | + application->setAppId("map"); |
1751 | + application->setName("Map"); |
1752 | + application->setIconId("map"); |
1753 | + application->setScreenshotId("map"); |
1754 | m_availableApplications.append(application); |
1755 | |
1756 | application = new ApplicationInfo(this); |
1757 | application->setAppId("gmail-webapp"); |
1758 | application->setName("GMail"); |
1759 | - application->setIcon(QUrl("gmail")); |
1760 | + application->setIconId("gmail"); |
1761 | m_availableApplications.append(application); |
1762 | |
1763 | application = new ApplicationInfo(this); |
1764 | application->setAppId("ubuntu-weather-app"); |
1765 | application->setName("Weather"); |
1766 | - application->setIcon(QUrl("weather")); |
1767 | + application->setIconId("weather"); |
1768 | application->setStage(ApplicationInfo::SideStage); |
1769 | - generateQmlStrings(application); |
1770 | m_availableApplications.append(application); |
1771 | |
1772 | application = new ApplicationInfo(this); |
1773 | application->setAppId("notes-app"); |
1774 | application->setName("Notepad"); |
1775 | - application->setIcon(QUrl("notepad")); |
1776 | + application->setIconId("notepad"); |
1777 | application->setStage(ApplicationInfo::SideStage); |
1778 | m_availableApplications.append(application); |
1779 | |
1780 | application = new ApplicationInfo(this); |
1781 | application->setAppId("calendar-app"); |
1782 | application->setName("Calendar"); |
1783 | - application->setIcon(QUrl("calendar")); |
1784 | + application->setIconId("calendar"); |
1785 | application->setStage(ApplicationInfo::SideStage); |
1786 | m_availableApplications.append(application); |
1787 | |
1788 | application = new ApplicationInfo(this); |
1789 | - application->setAppId("mediaplayer-app"); |
1790 | - application->setName("Media Player"); |
1791 | - application->setIcon(QUrl("mediaplayer-app")); |
1792 | - application->setFullscreen(true); |
1793 | - m_availableApplications.append(application); |
1794 | - |
1795 | - application = new ApplicationInfo(this); |
1796 | application->setAppId("evernote"); |
1797 | application->setName("Evernote"); |
1798 | - application->setIcon(QUrl("evernote")); |
1799 | - m_availableApplications.append(application); |
1800 | - |
1801 | - application = new ApplicationInfo(this); |
1802 | - application->setAppId("map"); |
1803 | - application->setName("Map"); |
1804 | - application->setIcon(QUrl("map")); |
1805 | - generateQmlStrings(application); |
1806 | + application->setIconId("evernote"); |
1807 | m_availableApplications.append(application); |
1808 | |
1809 | application = new ApplicationInfo(this); |
1810 | application->setAppId("pinterest"); |
1811 | application->setName("Pinterest"); |
1812 | - application->setIcon(QUrl("pinterest")); |
1813 | + application->setIconId("pinterest"); |
1814 | m_availableApplications.append(application); |
1815 | |
1816 | application = new ApplicationInfo(this); |
1817 | application->setAppId("soundcloud"); |
1818 | application->setName("SoundCloud"); |
1819 | - application->setIcon(QUrl("soundcloud")); |
1820 | + application->setIconId("soundcloud"); |
1821 | m_availableApplications.append(application); |
1822 | |
1823 | application = new ApplicationInfo(this); |
1824 | application->setAppId("wikipedia"); |
1825 | application->setName("Wikipedia"); |
1826 | - application->setIcon(QUrl("wikipedia")); |
1827 | + application->setIconId("wikipedia"); |
1828 | m_availableApplications.append(application); |
1829 | |
1830 | application = new ApplicationInfo(this); |
1831 | application->setAppId("youtube"); |
1832 | application->setName("YouTube"); |
1833 | - application->setIcon(QUrl("youtube")); |
1834 | + application->setIconId("youtube"); |
1835 | m_availableApplications.append(application); |
1836 | } |
1837 | |
1838 | |
1839 | === modified file 'tests/mocks/Unity/Application/ApplicationManager.h' |
1840 | --- tests/mocks/Unity/Application/ApplicationManager.h 2014-08-07 17:15:00 +0000 |
1841 | +++ tests/mocks/Unity/Application/ApplicationManager.h 2014-08-21 13:12:27 +0000 |
1842 | @@ -20,6 +20,7 @@ |
1843 | #include <QObject> |
1844 | #include <QList> |
1845 | #include <QStringList> |
1846 | +#include <QTimer> |
1847 | #include "ApplicationInfo.h" |
1848 | |
1849 | // unity-api |
1850 | @@ -51,7 +52,7 @@ |
1851 | static ApplicationManager *singleton(); |
1852 | |
1853 | enum MoreRoles { |
1854 | - RoleSurface = RoleScreenshot+1, |
1855 | + RoleSurface = RoleFocused+1, |
1856 | RoleFullscreen, |
1857 | RoleApplication, |
1858 | }; |
1859 | @@ -97,14 +98,17 @@ |
1860 | Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override; |
1861 | Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList()); |
1862 | Q_INVOKABLE bool stopApplication(const QString &appId) override; |
1863 | - Q_INVOKABLE bool updateScreenshot(const QString &appId) override; |
1864 | |
1865 | QString focusedApplicationId() const override; |
1866 | - bool suspended() const; |
1867 | - void setSuspended(bool suspended); |
1868 | + bool suspended() const override; |
1869 | + void setSuspended(bool suspended) override; |
1870 | + |
1871 | + QJSValue surfaceAboutToBeCreatedCallback() const override; |
1872 | + void setSurfaceAboutToBeCreatedCallback(const QJSValue &callback) override; |
1873 | |
1874 | // Only for testing |
1875 | Q_INVOKABLE QStringList availableApplications(); |
1876 | + Q_INVOKABLE ApplicationInfo* add(QString appId); |
1877 | |
1878 | QModelIndex findIndex(ApplicationInfo* application); |
1879 | |
1880 | @@ -115,15 +119,19 @@ |
1881 | void focusRequested(const QString &appId); |
1882 | void emptyChanged(bool empty); |
1883 | |
1884 | + private Q_SLOTS: |
1885 | + void onWindowCreatedTimerTimeout(); |
1886 | + |
1887 | private: |
1888 | void add(ApplicationInfo *application); |
1889 | void remove(ApplicationInfo* application); |
1890 | - void showApplicationWindow(ApplicationInfo *application); |
1891 | void buildListOfAvailableApplications(); |
1892 | - void generateQmlStrings(ApplicationInfo *application); |
1893 | + void onWindowCreated(); |
1894 | bool m_suspended; |
1895 | + QJSValue m_surfaceAboutToBeCreatedCallback; |
1896 | QList<ApplicationInfo*> m_runningApplications; |
1897 | QList<ApplicationInfo*> m_availableApplications; |
1898 | + QTimer m_windowCreatedTimer; |
1899 | |
1900 | static ApplicationManager *the_application_manager; |
1901 | }; |
1902 | |
1903 | === modified file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp' |
1904 | --- tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-07-25 00:10:11 +0000 |
1905 | +++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-08-21 13:12:27 +0000 |
1906 | @@ -44,11 +44,9 @@ |
1907 | return QImage(); |
1908 | } |
1909 | |
1910 | - QString filePath = QString("%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory()).arg(app->icon().toString()); |
1911 | - |
1912 | QImage image; |
1913 | - if (!image.load(filePath)) { |
1914 | - qWarning() << "failed loading app image" << filePath; |
1915 | + if (!image.load(app->screenshot())) { |
1916 | + qWarning() << "failed loading app image" << app->screenshot(); |
1917 | } |
1918 | |
1919 | |
1920 | |
1921 | === modified file 'tests/mocks/Unity/Application/CMakeLists.txt' |
1922 | --- tests/mocks/Unity/Application/CMakeLists.txt 2014-07-22 13:24:37 +0000 |
1923 | +++ tests/mocks/Unity/Application/CMakeLists.txt 2014-08-21 13:12:27 +0000 |
1924 | @@ -1,15 +1,13 @@ |
1925 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application) |
1926 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3) |
1927 | |
1928 | set(FakeUnityApplicationQml_SOURCES |
1929 | plugin.cpp |
1930 | ApplicationDBusAdaptor.cpp |
1931 | ApplicationInfo.cpp |
1932 | - ApplicationImage.cpp |
1933 | ApplicationManager.cpp |
1934 | ApplicationScreenshotProvider.cpp |
1935 | MirSurfaceItem.cpp |
1936 | SurfaceManager.cpp |
1937 | - VirtualKeyboard.cpp |
1938 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h |
1939 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h |
1940 | ) |
1941 | |
1942 | === removed file 'tests/mocks/Unity/Application/InputFilterArea.qml' |
1943 | --- tests/mocks/Unity/Application/InputFilterArea.qml 2013-06-05 22:03:08 +0000 |
1944 | +++ tests/mocks/Unity/Application/InputFilterArea.qml 1970-01-01 00:00:00 +0000 |
1945 | @@ -1,21 +0,0 @@ |
1946 | -/* |
1947 | - * Copyright (C) 2013 Canonical, Ltd. |
1948 | - * |
1949 | - * This program is free software; you can redistribute it and/or modify |
1950 | - * it under the terms of the GNU General Public License as published by |
1951 | - * the Free Software Foundation; version 3. |
1952 | - * |
1953 | - * This program is distributed in the hope that it will be useful, |
1954 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1955 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1956 | - * GNU General Public License for more details. |
1957 | - * |
1958 | - * You should have received a copy of the GNU General Public License |
1959 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1960 | - */ |
1961 | - |
1962 | -import QtQuick 2.0; |
1963 | - |
1964 | -Item { |
1965 | - property bool blockInput: false |
1966 | -} |
1967 | |
1968 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp' |
1969 | --- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-08-08 09:40:50 +0000 |
1970 | +++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-08-21 13:12:27 +0000 |
1971 | @@ -17,33 +17,67 @@ |
1972 | #include "MirSurfaceItem.h" |
1973 | #include "ApplicationInfo.h" |
1974 | |
1975 | -#include <QPainter> |
1976 | +#include <paths.h> |
1977 | + |
1978 | +#include <QGuiApplication> |
1979 | +#include <QQuickView> |
1980 | +#include <QQmlProperty> |
1981 | #include <QQmlEngine> |
1982 | +#include <QString> |
1983 | + |
1984 | +#include <QDebug> |
1985 | |
1986 | MirSurfaceItem::MirSurfaceItem(const QString& name, |
1987 | MirSurfaceItem::Type type, |
1988 | MirSurfaceItem::State state, |
1989 | const QUrl& screenshot, |
1990 | + const QString &qmlFilePath, |
1991 | QQuickItem *parent) |
1992 | - : QQuickPaintedItem(parent) |
1993 | + : QQuickItem(parent) |
1994 | , m_application(nullptr) |
1995 | , m_name(name) |
1996 | , m_type(type) |
1997 | , m_state(state) |
1998 | - , m_img(screenshot.isLocalFile() ? screenshot.toLocalFile() : screenshot.toString()) |
1999 | , m_parentSurface(nullptr) |
2000 | - , m_haveInputMethod(false) |
2001 | + , m_qmlItem(nullptr) |
2002 | + , m_screenshotUrl(screenshot) |
2003 | { |
2004 | qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name(); |
2005 | |
2006 | QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); |
2007 | |
2008 | - // The virtual keyboard (input method) has a big transparent area so that |
2009 | - // content behind it show through |
2010 | - setFillColor(Qt::transparent); |
2011 | - |
2012 | connect(this, &QQuickItem::focusChanged, |
2013 | this, &MirSurfaceItem::onFocusChanged); |
2014 | + |
2015 | + // The assumptions I make here really should hold. |
2016 | + QQuickView *quickView = |
2017 | + qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]); |
2018 | + |
2019 | + QString qmlComponentFilePath; |
2020 | + if (!qmlFilePath.isEmpty()) { |
2021 | + qmlComponentFilePath.append(qmlFilePath); |
2022 | + } else { |
2023 | + qmlComponentFilePath = QString("%1/Unity/Application/MirSurfaceItem.qml") |
2024 | + .arg(mockPluginsDir()); |
2025 | + } |
2026 | + |
2027 | + m_qmlContentComponent = new QQmlComponent(quickView->engine(), qmlComponentFilePath); |
2028 | + |
2029 | + switch (m_qmlContentComponent->status()) { |
2030 | + case QQmlComponent::Ready: |
2031 | + createQmlContentItem(); |
2032 | + break; |
2033 | + case QQmlComponent::Loading: |
2034 | + connect(m_qmlContentComponent, &QQmlComponent::statusChanged, |
2035 | + this, &MirSurfaceItem::onComponentStatusChanged); |
2036 | + break; |
2037 | + case QQmlComponent::Error: |
2038 | + printComponentErrors(); |
2039 | + qFatal("MirSurfaceItem: failed to create content component."); |
2040 | + break; |
2041 | + default: |
2042 | + qFatal("MirSurfaceItem: Unhandled component status"); |
2043 | + } |
2044 | } |
2045 | |
2046 | MirSurfaceItem::~MirSurfaceItem() |
2047 | @@ -61,10 +95,11 @@ |
2048 | m_application->removeSurface(this); |
2049 | } |
2050 | |
2051 | -void MirSurfaceItem::paint(QPainter * painter) |
2052 | +void MirSurfaceItem::printComponentErrors() |
2053 | { |
2054 | - if (!m_img.isNull()) { |
2055 | - painter->drawImage(contentsBoundingRect(), m_img, QRect(QPoint(0,0), m_img.size())); |
2056 | + QList<QQmlError> errors = m_qmlContentComponent->errors(); |
2057 | + for (int i = 0; i < errors.count(); ++i) { |
2058 | + qDebug() << errors[i]; |
2059 | } |
2060 | } |
2061 | |
2062 | @@ -155,19 +190,24 @@ |
2063 | } |
2064 | |
2065 | |
2066 | -void MirSurfaceItem::touchEvent(QTouchEvent * event) |
2067 | +void MirSurfaceItem::onQmlWantInputMethodChanged() |
2068 | { |
2069 | - if (event->type() == QEvent::TouchBegin && hasFocus()) { |
2070 | + QQmlProperty prop(m_qmlItem, "wantInputMethod"); |
2071 | + bool wantInputMethod = prop.read().toBool(); |
2072 | + |
2073 | + if (hasFocus() && wantInputMethod) { |
2074 | Q_EMIT inputMethodRequested(); |
2075 | - m_haveInputMethod = true; |
2076 | } |
2077 | } |
2078 | |
2079 | void MirSurfaceItem::onFocusChanged() |
2080 | { |
2081 | - if (!hasFocus() && m_haveInputMethod) { |
2082 | + QQmlProperty prop(m_qmlItem, "wantInputMethod"); |
2083 | + bool wantInputMethod = prop.read().toBool(); |
2084 | + |
2085 | + if (!hasFocus() && wantInputMethod) { |
2086 | Q_EMIT inputMethodDismissed(); |
2087 | - m_haveInputMethod = false; |
2088 | + prop.write(QVariant::fromValue(false)); |
2089 | } |
2090 | } |
2091 | |
2092 | @@ -178,3 +218,34 @@ |
2093 | Q_EMIT stateChanged(newState); |
2094 | } |
2095 | } |
2096 | + |
2097 | +void MirSurfaceItem::onComponentStatusChanged(QQmlComponent::Status status) |
2098 | +{ |
2099 | + if (status == QQmlComponent::Ready) { |
2100 | + createQmlContentItem(); |
2101 | + } |
2102 | +} |
2103 | + |
2104 | +void MirSurfaceItem::createQmlContentItem() |
2105 | +{ |
2106 | + qDebug() << "MirSurfaceItem::createQmlContentItem()"; |
2107 | + |
2108 | + m_qmlItem = qobject_cast<QQuickItem*>(m_qmlContentComponent->create()); |
2109 | + m_qmlItem->setParentItem(this); |
2110 | + |
2111 | + setImplicitWidth(m_qmlItem->implicitWidth()); |
2112 | + setImplicitHeight(m_qmlItem->implicitHeight()); |
2113 | + |
2114 | + { |
2115 | + QQmlProperty screenshotSource(m_qmlItem, "screenshotSource"); |
2116 | + screenshotSource.write(QVariant::fromValue(m_screenshotUrl)); |
2117 | + } |
2118 | + |
2119 | + { |
2120 | + QQmlProperty prop(m_qmlItem, "wantInputMethod"); |
2121 | + if (prop.type() == QQmlProperty::Property) { |
2122 | + bool ok = prop.connectNotifySignal(this, SLOT(onQmlWantInputMethodChanged())); |
2123 | + if (!ok) qCritical("MirSurfaceItem: failed to connect to wantInputMethod notify signal"); |
2124 | + } |
2125 | + } |
2126 | +} |
2127 | |
2128 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h' |
2129 | --- tests/mocks/Unity/Application/MirSurfaceItem.h 2014-08-07 17:15:00 +0000 |
2130 | +++ tests/mocks/Unity/Application/MirSurfaceItem.h 2014-08-21 13:12:27 +0000 |
2131 | @@ -17,12 +17,13 @@ |
2132 | #ifndef MIRSURFACEITEM_H |
2133 | #define MIRSURFACEITEM_H |
2134 | |
2135 | -#include <QQuickPaintedItem> |
2136 | -#include <QImage> |
2137 | +#include <QQuickItem> |
2138 | +#include <QQmlComponent> |
2139 | +#include <QUrl> |
2140 | |
2141 | class ApplicationInfo; |
2142 | |
2143 | -class MirSurfaceItem : public QQuickPaintedItem |
2144 | +class MirSurfaceItem : public QQuickItem |
2145 | { |
2146 | Q_OBJECT |
2147 | Q_ENUMS(Type) |
2148 | @@ -59,6 +60,7 @@ |
2149 | Type type, |
2150 | State state, |
2151 | const QUrl& screenshot, |
2152 | + const QString &qmlFilePath = QString(), |
2153 | QQuickItem *parent = 0); |
2154 | ~MirSurfaceItem(); |
2155 | |
2156 | @@ -76,9 +78,6 @@ |
2157 | Q_INVOKABLE void setState(State newState); |
2158 | Q_INVOKABLE void release(); |
2159 | |
2160 | - void paint(QPainter * painter) override; |
2161 | - void touchEvent(QTouchEvent * event) override; |
2162 | - |
2163 | Q_SIGNALS: |
2164 | void typeChanged(Type); |
2165 | void stateChanged(State); |
2166 | @@ -93,9 +92,8 @@ |
2167 | |
2168 | private Q_SLOTS: |
2169 | void onFocusChanged(); |
2170 | - |
2171 | -protected: |
2172 | - const QImage &screenshotImage() { return m_img; } |
2173 | + void onComponentStatusChanged(QQmlComponent::Status status); |
2174 | + void onQmlWantInputMethodChanged(); |
2175 | |
2176 | private: |
2177 | void addChildSurface(MirSurfaceItem* surface); |
2178 | @@ -105,15 +103,20 @@ |
2179 | static int childSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop); |
2180 | static MirSurfaceItem* childSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index); |
2181 | |
2182 | + void createQmlContentItem(); |
2183 | + void printComponentErrors(); |
2184 | + |
2185 | ApplicationInfo* m_application; |
2186 | const QString m_name; |
2187 | const Type m_type; |
2188 | State m_state; |
2189 | - const QImage m_img; |
2190 | |
2191 | MirSurfaceItem* m_parentSurface; |
2192 | QList<MirSurfaceItem*> m_children; |
2193 | - bool m_haveInputMethod; |
2194 | + |
2195 | + QQmlComponent *m_qmlContentComponent; |
2196 | + QQuickItem *m_qmlItem; |
2197 | + QUrl m_screenshotUrl; |
2198 | }; |
2199 | |
2200 | Q_DECLARE_METATYPE(MirSurfaceItem*) |
2201 | |
2202 | === added file 'tests/mocks/Unity/Application/MirSurfaceItem.qml' |
2203 | --- tests/mocks/Unity/Application/MirSurfaceItem.qml 1970-01-01 00:00:00 +0000 |
2204 | +++ tests/mocks/Unity/Application/MirSurfaceItem.qml 2014-08-21 13:12:27 +0000 |
2205 | @@ -0,0 +1,57 @@ |
2206 | +/* |
2207 | + * Copyright 2014 Canonical Ltd. |
2208 | + * |
2209 | + * This program is free software; you can redistribute it and/or modify |
2210 | + * it under the terms of the GNU Lesser General Public License as published by |
2211 | + * the Free Software Foundation; version 3. |
2212 | + * |
2213 | + * This program is distributed in the hope that it will be useful, |
2214 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2215 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2216 | + * GNU Lesser General Public License for more details. |
2217 | + * |
2218 | + * You should have received a copy of the GNU Lesser General Public License |
2219 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2220 | + */ |
2221 | + |
2222 | +import QtQuick 2.0 |
2223 | + |
2224 | +Rectangle { |
2225 | + objectName: "fakeSurfaceQML" |
2226 | + id: root |
2227 | + color: "pink" |
2228 | + |
2229 | + anchors.fill: parent |
2230 | + |
2231 | + implicitWidth: units.gu(40) |
2232 | + implicitHeight: units.gu(70) |
2233 | + |
2234 | + property alias screenshotSource: screenshotImage.source |
2235 | + |
2236 | + property bool wantInputMethod: false |
2237 | + |
2238 | + property int touchPressCount: 0 |
2239 | + property int touchReleaseCount: 0 |
2240 | + |
2241 | + Image { |
2242 | + id: screenshotImage |
2243 | + anchors.fill: parent |
2244 | + fillMode: Image.Stretch |
2245 | + } |
2246 | + |
2247 | + Text { |
2248 | + anchors.fill: parent |
2249 | + text: "SURFACE" |
2250 | + color: "yellow" |
2251 | + font.bold: true |
2252 | + fontSizeMode: Text.Fit |
2253 | + minimumPixelSize: 10; font.pixelSize: 200 |
2254 | + verticalAlignment: Text.AlignVCenter |
2255 | + } |
2256 | + |
2257 | + MultiPointTouchArea { |
2258 | + anchors.fill: parent |
2259 | + onPressed: { root.wantInputMethod = true; root.touchPressCount++; } |
2260 | + onReleased: { root.touchReleaseCount++; } |
2261 | + } |
2262 | +} |
2263 | |
2264 | === removed file 'tests/mocks/Unity/Application/OSKController.qml' |
2265 | --- tests/mocks/Unity/Application/OSKController.qml 2013-09-10 15:06:32 +0000 |
2266 | +++ tests/mocks/Unity/Application/OSKController.qml 1970-01-01 00:00:00 +0000 |
2267 | @@ -1,20 +0,0 @@ |
2268 | -/* |
2269 | - * Copyright (C) 2013 Canonical, Ltd. |
2270 | - * |
2271 | - * This program is free software; you can redistribute it and/or modify |
2272 | - * it under the terms of the GNU General Public License as published by |
2273 | - * the Free Software Foundation; version 3. |
2274 | - * |
2275 | - * This program is distributed in the hope that it will be useful, |
2276 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2277 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2278 | - * GNU General Public License for more details. |
2279 | - * |
2280 | - * You should have received a copy of the GNU General Public License |
2281 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2282 | - */ |
2283 | - |
2284 | -import QtQuick 2.0; |
2285 | - |
2286 | -Item { |
2287 | -} |
2288 | |
2289 | === modified file 'tests/mocks/Unity/Application/SurfaceManager.cpp' |
2290 | --- tests/mocks/Unity/Application/SurfaceManager.cpp 2014-07-24 19:22:20 +0000 |
2291 | +++ tests/mocks/Unity/Application/SurfaceManager.cpp 2014-08-21 13:12:27 +0000 |
2292 | @@ -16,9 +16,8 @@ |
2293 | |
2294 | #include "SurfaceManager.h" |
2295 | |
2296 | +#include <paths.h> |
2297 | #include "MirSurfaceItem.h" |
2298 | -#include "VirtualKeyboard.h" |
2299 | - |
2300 | |
2301 | SurfaceManager *SurfaceManager::the_surface_manager = nullptr; |
2302 | |
2303 | @@ -66,7 +65,19 @@ |
2304 | MirSurfaceItem *SurfaceManager::inputMethodSurface() |
2305 | { |
2306 | if (!m_virtualKeyboard) { |
2307 | - m_virtualKeyboard = new VirtualKeyboard(MirSurfaceItem::Minimized); |
2308 | + |
2309 | + QString screenshotPath = QString("file://%1/Dash/graphics/phone/screenshots/vkb_portrait.png") |
2310 | + .arg(qmlDirectory()); |
2311 | + |
2312 | + QString qmlFilePath = QString("%1/Unity/Application/VirtualKeyboard.qml") |
2313 | + .arg(mockPluginsDir()); |
2314 | + |
2315 | + m_virtualKeyboard = new MirSurfaceItem( |
2316 | + "input-method", |
2317 | + MirSurfaceItem::InputMethod, |
2318 | + MirSurfaceItem::Minimized, |
2319 | + screenshotPath, |
2320 | + qmlFilePath); |
2321 | Q_EMIT surfaceCreated(m_virtualKeyboard); |
2322 | } |
2323 | return m_virtualKeyboard; |
2324 | |
2325 | === modified file 'tests/mocks/Unity/Application/SurfaceManager.h' |
2326 | --- tests/mocks/Unity/Application/SurfaceManager.h 2014-07-24 19:22:20 +0000 |
2327 | +++ tests/mocks/Unity/Application/SurfaceManager.h 2014-08-21 13:12:27 +0000 |
2328 | @@ -20,7 +20,6 @@ |
2329 | #include <QObject> |
2330 | |
2331 | class MirSurfaceItem; |
2332 | -class VirtualKeyboard; |
2333 | |
2334 | class SurfaceManager : public QObject |
2335 | { |
2336 | @@ -48,7 +47,7 @@ |
2337 | |
2338 | private: |
2339 | static SurfaceManager *the_surface_manager; |
2340 | - VirtualKeyboard *m_virtualKeyboard; |
2341 | + MirSurfaceItem *m_virtualKeyboard; |
2342 | }; |
2343 | |
2344 | #endif // SURFACEMANAGER_H |
2345 | |
2346 | === removed file 'tests/mocks/Unity/Application/VirtualKeyboard.cpp' |
2347 | --- tests/mocks/Unity/Application/VirtualKeyboard.cpp 2014-07-22 10:29:25 +0000 |
2348 | +++ tests/mocks/Unity/Application/VirtualKeyboard.cpp 1970-01-01 00:00:00 +0000 |
2349 | @@ -1,55 +0,0 @@ |
2350 | -/* |
2351 | - * Copyright (C) 2014 Canonical, Ltd. |
2352 | - * |
2353 | - * This program is free software; you can redistribute it and/or modify |
2354 | - * it under the terms of the GNU General Public License as published by |
2355 | - * the Free Software Foundation; version 3. |
2356 | - * |
2357 | - * This program is distributed in the hope that it will be useful, |
2358 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2359 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2360 | - * GNU General Public License for more details. |
2361 | - * |
2362 | - * You should have received a copy of the GNU General Public License |
2363 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2364 | - */ |
2365 | - |
2366 | -#include "VirtualKeyboard.h" |
2367 | - |
2368 | -#include <paths.h> |
2369 | - |
2370 | -VirtualKeyboard::VirtualKeyboard(State state, QQuickItem *parent) |
2371 | - : MirSurfaceItem("input-method", |
2372 | - MirSurfaceItem::InputMethod, |
2373 | - state, |
2374 | - QString("file://%1/Dash/graphics/phone/screenshots/vkb_portrait.png").arg(qmlDirectory()), |
2375 | - parent) |
2376 | -{ |
2377 | -} |
2378 | - |
2379 | -void VirtualKeyboard::touchEvent(QTouchEvent *event) |
2380 | -{ |
2381 | - if (event->type() == QEvent::TouchBegin && !hasTouchInsideKeyboard(event)) { |
2382 | - event->ignore(); |
2383 | - } |
2384 | -} |
2385 | - |
2386 | -bool VirtualKeyboard::hasTouchInsideKeyboard(QTouchEvent *event) |
2387 | -{ |
2388 | - const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); |
2389 | - for (int i = 0; i < touchPoints.count(); ++i) { |
2390 | - QPoint pos = touchPoints.at(i).pos().toPoint(); |
2391 | - |
2392 | - // Map to image coords |
2393 | - int imageX = (int)( ( ((qreal)pos.x()) / width() ) * ((qreal)screenshotImage().size().width()) ); |
2394 | - int imageY = (int)( ( ((qreal)pos.y()) / height() ) * ((qreal)screenshotImage().size().height()) ); |
2395 | - |
2396 | - QRgb pixelHit = screenshotImage().pixel(imageX, imageY); |
2397 | - |
2398 | - // The keyboard depicted in the image is in its opaque part. |
2399 | - if (qAlpha(pixelHit) != 0) { |
2400 | - return true; |
2401 | - } |
2402 | - } |
2403 | - return false; |
2404 | -} |
2405 | |
2406 | === removed file 'tests/mocks/Unity/Application/VirtualKeyboard.h' |
2407 | --- tests/mocks/Unity/Application/VirtualKeyboard.h 2014-07-22 10:29:25 +0000 |
2408 | +++ tests/mocks/Unity/Application/VirtualKeyboard.h 1970-01-01 00:00:00 +0000 |
2409 | @@ -1,35 +0,0 @@ |
2410 | -/* |
2411 | - * Copyright (C) 2014 Canonical, Ltd. |
2412 | - * |
2413 | - * This program is free software; you can redistribute it and/or modify |
2414 | - * it under the terms of the GNU General Public License as published by |
2415 | - * the Free Software Foundation; version 3. |
2416 | - * |
2417 | - * This program is distributed in the hope that it will be useful, |
2418 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2419 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2420 | - * GNU General Public License for more details. |
2421 | - * |
2422 | - * You should have received a copy of the GNU General Public License |
2423 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2424 | - */ |
2425 | - |
2426 | -#ifndef VIRTUALKEYBOARD_H |
2427 | -#define VIRTUALKEYBOARD_H |
2428 | - |
2429 | -#include "MirSurfaceItem.h" |
2430 | - |
2431 | -class VirtualKeyboard : public MirSurfaceItem |
2432 | -{ |
2433 | - Q_OBJECT |
2434 | -public: |
2435 | - VirtualKeyboard(State state, |
2436 | - QQuickItem *parent = 0); |
2437 | - |
2438 | - void touchEvent(QTouchEvent * event) override; |
2439 | - |
2440 | -private: |
2441 | - bool hasTouchInsideKeyboard(QTouchEvent *event); |
2442 | -}; |
2443 | - |
2444 | -#endif // VIRTUALKEYBOARD_H |
2445 | |
2446 | === added file 'tests/mocks/Unity/Application/VirtualKeyboard.qml' |
2447 | --- tests/mocks/Unity/Application/VirtualKeyboard.qml 1970-01-01 00:00:00 +0000 |
2448 | +++ tests/mocks/Unity/Application/VirtualKeyboard.qml 2014-08-21 13:12:27 +0000 |
2449 | @@ -0,0 +1,40 @@ |
2450 | +/* |
2451 | + * Copyright 2014 Canonical Ltd. |
2452 | + * |
2453 | + * This program is free software; you can redistribute it and/or modify |
2454 | + * it under the terms of the GNU Lesser General Public License as published by |
2455 | + * the Free Software Foundation; version 3. |
2456 | + * |
2457 | + * This program is distributed in the hope that it will be useful, |
2458 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2459 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2460 | + * GNU Lesser General Public License for more details. |
2461 | + * |
2462 | + * You should have received a copy of the GNU Lesser General Public License |
2463 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2464 | + */ |
2465 | + |
2466 | +import QtQuick 2.0 |
2467 | + |
2468 | +Item { |
2469 | + implicitWidth: units.gu(40) |
2470 | + implicitHeight: units.gu(70) |
2471 | + |
2472 | + anchors.fill: parent |
2473 | + |
2474 | + property alias screenshotSource: screenshotImage.source |
2475 | + |
2476 | + property bool landscape: width > height |
2477 | + |
2478 | + Image { |
2479 | + id: screenshotImage |
2480 | + height: landscape ? parent.height * 0.4 : width * 0.6 |
2481 | + anchors.bottom: parent.bottom |
2482 | + anchors.left: parent.left |
2483 | + anchors.right: parent.right |
2484 | + |
2485 | + MultiPointTouchArea { |
2486 | + anchors.fill: parent |
2487 | + } |
2488 | + } |
2489 | +} |
2490 | |
2491 | === modified file 'tests/mocks/Unity/Application/plugin.cpp' |
2492 | --- tests/mocks/Unity/Application/plugin.cpp 2014-07-19 11:52:38 +0000 |
2493 | +++ tests/mocks/Unity/Application/plugin.cpp 2014-08-21 13:12:27 +0000 |
2494 | @@ -16,7 +16,6 @@ |
2495 | |
2496 | #include "plugin.h" |
2497 | #include "ApplicationInfo.h" |
2498 | -#include "ApplicationImage.h" |
2499 | #include "ApplicationManager.h" |
2500 | #include "ApplicationScreenshotProvider.h" |
2501 | #include "MirSurfaceItem.h" |
2502 | @@ -49,8 +48,6 @@ |
2503 | qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo"); |
2504 | |
2505 | qmlRegisterUncreatableType<MirSurfaceItem>(uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML"); |
2506 | - |
2507 | - qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage"); |
2508 | } |
2509 | |
2510 | void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
2511 | |
2512 | === modified file 'tests/mocks/Unity/Application/qmldir' |
2513 | --- tests/mocks/Unity/Application/qmldir 2014-05-02 22:57:21 +0000 |
2514 | +++ tests/mocks/Unity/Application/qmldir 2014-08-21 13:12:27 +0000 |
2515 | @@ -1,6 +1,3 @@ |
2516 | module Unity.Application |
2517 | plugin FakeUnityApplicationQml |
2518 | typeinfo Application.qmltypes |
2519 | - |
2520 | -InputFilterArea 0.1 InputFilterArea.qml |
2521 | -OSKController 0.1 OSKController.qml |
2522 | |
2523 | === modified file 'tests/plugins/Unity/Launcher/CMakeLists.txt' |
2524 | --- tests/plugins/Unity/Launcher/CMakeLists.txt 2014-05-30 09:22:58 +0000 |
2525 | +++ tests/plugins/Unity/Launcher/CMakeLists.txt 2014-08-21 13:12:27 +0000 |
2526 | @@ -1,6 +1,6 @@ |
2527 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
2528 | pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3) |
2529 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=1) |
2530 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3) |
2531 | |
2532 | include_directories( |
2533 | ${CMAKE_CURRENT_BINARY_DIR} |
2534 | @@ -50,7 +50,7 @@ |
2535 | ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h |
2536 | ) |
2537 | target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS}) |
2538 | -qt5_use_modules(launchermodeltestExec Test Core DBus) |
2539 | +qt5_use_modules(launchermodeltestExec Test Core DBus Qml) |
2540 | |
2541 | # copy .desktop files into build directory for shadow builds |
2542 | file(GLOB DESKTOP_FILES *.desktop) |
2543 | |
2544 | === modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp' |
2545 | --- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-07-03 12:03:57 +0000 |
2546 | +++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-08-21 13:12:27 +0000 |
2547 | @@ -93,10 +93,11 @@ |
2548 | m_list.takeAt(index)->deleteLater(); |
2549 | endRemoveRows(); |
2550 | } |
2551 | - bool updateScreenshot(const QString &appId) { Q_UNUSED(appId); return true; } |
2552 | bool requestFocusApplication(const QString &appId) { Q_UNUSED(appId); return true; } |
2553 | bool suspended() const { return false; } |
2554 | void setSuspended(bool) {} |
2555 | + QJSValue surfaceAboutToBeCreatedCallback() const override { return QJSValue(false); } |
2556 | + void setSurfaceAboutToBeCreatedCallback(const QJSValue &callback) override { Q_UNUSED(callback); } |
2557 | |
2558 | private: |
2559 | QList<MockApp*> m_list; |
2560 | |
2561 | === modified file 'tests/qmltests/CMakeLists.txt' |
2562 | --- tests/qmltests/CMakeLists.txt 2014-08-20 08:39:09 +0000 |
2563 | +++ tests/qmltests/CMakeLists.txt 2014-08-21 13:12:27 +0000 |
2564 | @@ -76,4 +76,6 @@ |
2565 | # These MenuItemFactory tests need the test/mocks/ to come before plugins/ |
2566 | add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS}) |
2567 | add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS}) |
2568 | +add_qml_test(Stages ApplicationWindow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single") |
2569 | add_qml_test(Stages PhoneStage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single") |
2570 | +add_qml_test(Stages SpreadDelegate ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single") |
2571 | |
2572 | === added file 'tests/qmltests/Stages/tst_ApplicationWindow.qml' |
2573 | --- tests/qmltests/Stages/tst_ApplicationWindow.qml 1970-01-01 00:00:00 +0000 |
2574 | +++ tests/qmltests/Stages/tst_ApplicationWindow.qml 2014-08-21 13:12:27 +0000 |
2575 | @@ -0,0 +1,346 @@ |
2576 | +/* |
2577 | + * Copyright 2014 Canonical Ltd. |
2578 | + * |
2579 | + * This program is free software; you can redistribute it and/or modify |
2580 | + * it under the terms of the GNU General Public License as published by |
2581 | + * the Free Software Foundation; version 3. |
2582 | + * |
2583 | + * This program is distributed in the hope that it will be useful, |
2584 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2585 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2586 | + * GNU General Public License for more details. |
2587 | + * |
2588 | + * You should have received a copy of the GNU General Public License |
2589 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2590 | + */ |
2591 | + |
2592 | +import QtQuick 2.0 |
2593 | +import QtTest 1.0 |
2594 | +import Unity.Test 0.1 as UT |
2595 | +import ".." |
2596 | +import "../../../qml/Stages" |
2597 | +import Ubuntu.Components 0.1 |
2598 | +import Ubuntu.Components.ListItems 1.0 as ListItem |
2599 | +import Unity.Application 0.1 |
2600 | + |
2601 | +Rectangle { |
2602 | + color: "red" |
2603 | + id: root |
2604 | + width: units.gu(70) |
2605 | + height: units.gu(70) |
2606 | + |
2607 | + Component.onCompleted: { |
2608 | + root.fakeApplication = ApplicationManager.add("gallery-app"); |
2609 | + root.fakeApplication.manualSurfaceCreation = true; |
2610 | + root.fakeApplication.setState(ApplicationInfo.Starting); |
2611 | + } |
2612 | + property QtObject fakeApplication: null |
2613 | + |
2614 | + Connections { |
2615 | + target: fakeApplication |
2616 | + onSurfaceChanged: { |
2617 | + surfaceCheckbox.checked = fakeApplication.surface !== null; |
2618 | + } |
2619 | + } |
2620 | + |
2621 | + Component { |
2622 | + id: applicationWindowComponent |
2623 | + ApplicationWindow { |
2624 | + anchors.fill: parent |
2625 | + application: fakeApplication |
2626 | + } |
2627 | + } |
2628 | + Loader { |
2629 | + id: applicationWindowLoader |
2630 | + anchors { |
2631 | + top: parent.top |
2632 | + bottom: parent.bottom |
2633 | + left: parent.left |
2634 | + } |
2635 | + width: units.gu(40) |
2636 | + sourceComponent: applicationWindowComponent |
2637 | + } |
2638 | + |
2639 | + Rectangle { |
2640 | + color: "white" |
2641 | + anchors { |
2642 | + top: parent.top |
2643 | + bottom: parent.bottom |
2644 | + left: applicationWindowLoader.right |
2645 | + right: parent.right |
2646 | + } |
2647 | + |
2648 | + Column { |
2649 | + anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
2650 | + spacing: units.gu(1) |
2651 | + Row { |
2652 | + anchors { left: parent.left; right: parent.right } |
2653 | + CheckBox { |
2654 | + id: surfaceCheckbox; checked: false |
2655 | + onCheckedChanged: { |
2656 | + if (applicationWindowLoader.status !== Loader.Ready) |
2657 | + return; |
2658 | + |
2659 | + if (checked && !fakeApplication.surface) { |
2660 | + fakeApplication.createSurface(); |
2661 | + } else if (!checked && fakeApplication.surface) { |
2662 | + fakeApplication.surface.release(); |
2663 | + } |
2664 | + } |
2665 | + } |
2666 | + Label { text: "Surface" } |
2667 | + } |
2668 | + ListItem.ItemSelector { |
2669 | + id: appStateSelector |
2670 | + anchors { left: parent.left; right: parent.right } |
2671 | + text: "Application state" |
2672 | + model: ["Starting", |
2673 | + "Running", |
2674 | + "Suspended", |
2675 | + "Stopped"] |
2676 | + property int selectedApplicationState: { |
2677 | + if (model[selectedIndex] === "Starting") { |
2678 | + return ApplicationInfo.Starting; |
2679 | + } else if (model[selectedIndex] === "Running") { |
2680 | + return ApplicationInfo.Running; |
2681 | + } else if (model[selectedIndex] === "Suspended") { |
2682 | + return ApplicationInfo.Suspended; |
2683 | + } else { |
2684 | + return ApplicationInfo.Stopped; |
2685 | + } |
2686 | + } |
2687 | + onSelectedApplicationStateChanged: { |
2688 | + // state is a read-only property, thus we have to call the setter function |
2689 | + fakeApplication.setState(selectedApplicationState); |
2690 | + } |
2691 | + } |
2692 | + } |
2693 | + } |
2694 | + |
2695 | + UT.UnityTestCase { |
2696 | + id: testCase |
2697 | + name: "ApplicationWindow" |
2698 | + when: windowShown |
2699 | + |
2700 | + // just to make them shorter |
2701 | + property int appStarting: ApplicationInfo.Starting |
2702 | + property int appRunning: ApplicationInfo.Running |
2703 | + property int appSuspended: ApplicationInfo.Suspended |
2704 | + property int appStopped: ApplicationInfo.Stopped |
2705 | + |
2706 | + function setApplicationState(appState) { |
2707 | + switch (appState) { |
2708 | + case appStarting: |
2709 | + appStateSelector.selectedIndex = 0; |
2710 | + break; |
2711 | + case appRunning: |
2712 | + appStateSelector.selectedIndex = 1; |
2713 | + break; |
2714 | + case appSuspended: |
2715 | + appStateSelector.selectedIndex = 2; |
2716 | + break; |
2717 | + case appStopped: |
2718 | + appStateSelector.selectedIndex = 3; |
2719 | + break; |
2720 | + } |
2721 | + } |
2722 | + |
2723 | + // holds some of the internal ApplicationWindow objects we probe during the tests |
2724 | + property var stateGroup: null |
2725 | + |
2726 | + function findInterestingApplicationWindowChildren() { |
2727 | + stateGroup = findInvisibleChild(applicationWindowLoader.item, "applicationWindowStateGroup"); |
2728 | + verify(stateGroup); |
2729 | + } |
2730 | + |
2731 | + function forgetApplicationWindowChildren() { |
2732 | + stateGroup = null; |
2733 | + } |
2734 | + |
2735 | + // wait until any transition animation has finished |
2736 | + function waitUntilTransitionsEnd() { |
2737 | + var transitions = stateGroup.transitions; |
2738 | + for (var i = 0; i < transitions.length; ++i) { |
2739 | + var transition = transitions[i]; |
2740 | + tryCompare(transition, "running", false, 2000); |
2741 | + } |
2742 | + } |
2743 | + |
2744 | + function init() { |
2745 | + findInterestingApplicationWindowChildren(); |
2746 | + } |
2747 | + |
2748 | + function cleanup() { |
2749 | + forgetApplicationWindowChildren(); |
2750 | + |
2751 | + // reload our test subject to get it in a fresh state once again |
2752 | + applicationWindowLoader.active = false; |
2753 | + |
2754 | + appStateSelector.selectedIndex = 0; |
2755 | + surfaceCheckbox.checked = false; |
2756 | + |
2757 | + if (fakeApplication.surface) |
2758 | + fakeApplication.surface.release(); |
2759 | + |
2760 | + applicationWindowLoader.active = true; |
2761 | + } |
2762 | + |
2763 | + function test_showSplashUntilAppFullyInit_data() { |
2764 | + return [ |
2765 | + {tag: "state=Running then create surface", swapInitOrder: false}, |
2766 | + |
2767 | + {tag: "create surface then state=Running", swapInitOrder: true}, |
2768 | + ] |
2769 | + } |
2770 | + |
2771 | + function test_showSplashUntilAppFullyInit() { |
2772 | + verify(stateGroup.state === "splashScreen"); |
2773 | + |
2774 | + if (data.swapInitOrder) { |
2775 | + surfaceCheckbox.checked = true; |
2776 | + } else { |
2777 | + setApplicationState(appRunning); |
2778 | + } |
2779 | + |
2780 | + verify(stateGroup.state === "splashScreen"); |
2781 | + |
2782 | + if (data.swapInitOrder) { |
2783 | + setApplicationState(appRunning); |
2784 | + } else { |
2785 | + surfaceCheckbox.checked = true; |
2786 | + } |
2787 | + |
2788 | + tryCompare(stateGroup, "state", "surface"); |
2789 | + } |
2790 | + |
2791 | + function test_suspendedAppShowsSurface() { |
2792 | + surfaceCheckbox.checked = true; |
2793 | + setApplicationState(appRunning); |
2794 | + |
2795 | + tryCompare(stateGroup, "state", "surface"); |
2796 | + |
2797 | + waitUntilTransitionsEnd(); |
2798 | + |
2799 | + setApplicationState(appSuspended); |
2800 | + |
2801 | + verify(stateGroup.state === "surface"); |
2802 | + waitUntilTransitionsEnd(); |
2803 | + } |
2804 | + |
2805 | + function test_killedAppShowsScreenshot() { |
2806 | + surfaceCheckbox.checked = true; |
2807 | + setApplicationState(appRunning); |
2808 | + tryCompare(stateGroup, "state", "surface"); |
2809 | + |
2810 | + setApplicationState(appSuspended); |
2811 | + |
2812 | + verify(stateGroup.state === "surface"); |
2813 | + verify(fakeApplication.surface !== null); |
2814 | + |
2815 | + // kill it! |
2816 | + setApplicationState(appStopped); |
2817 | + |
2818 | + tryCompare(stateGroup, "state", "screenshot"); |
2819 | + tryCompare(fakeApplication, "surface", null); |
2820 | + } |
2821 | + |
2822 | + function test_restartApp() { |
2823 | + var screenshotImage = findChild(applicationWindowLoader.item, "screenshotImage"); |
2824 | + |
2825 | + surfaceCheckbox.checked = true; |
2826 | + setApplicationState(appRunning); |
2827 | + tryCompare(stateGroup, "state", "surface"); |
2828 | + waitUntilTransitionsEnd(); |
2829 | + |
2830 | + setApplicationState(appSuspended); |
2831 | + |
2832 | + // kill it |
2833 | + setApplicationState(appStopped); |
2834 | + |
2835 | + tryCompare(stateGroup, "state", "screenshot"); |
2836 | + waitUntilTransitionsEnd(); |
2837 | + tryCompare(fakeApplication, "surface", null); |
2838 | + |
2839 | + // and restart it |
2840 | + setApplicationState(appStarting); |
2841 | + |
2842 | + waitUntilTransitionsEnd(); |
2843 | + verify(stateGroup.state === "screenshot"); |
2844 | + verify(fakeApplication.surface === null); |
2845 | + |
2846 | + setApplicationState(appRunning); |
2847 | + |
2848 | + waitUntilTransitionsEnd(); |
2849 | + verify(stateGroup.state === "screenshot"); |
2850 | + |
2851 | + surfaceCheckbox.checked = true; |
2852 | + |
2853 | + tryCompare(stateGroup, "state", "surface"); |
2854 | + tryCompare(screenshotImage, "status", Image.Null); |
2855 | + } |
2856 | + |
2857 | + function test_appCrashed() { |
2858 | + surfaceCheckbox.checked = true; |
2859 | + setApplicationState(appRunning); |
2860 | + tryCompare(stateGroup, "state", "surface"); |
2861 | + waitUntilTransitionsEnd(); |
2862 | + |
2863 | + // oh, it crashed... |
2864 | + setApplicationState(appStopped); |
2865 | + |
2866 | + tryCompare(stateGroup, "state", "screenshot"); |
2867 | + tryCompare(fakeApplication, "surface", null); |
2868 | + } |
2869 | + |
2870 | + function test_keepSurfaceWhileInvisible() { |
2871 | + surfaceCheckbox.checked = true; |
2872 | + setApplicationState(appRunning); |
2873 | + tryCompare(stateGroup, "state", "surface"); |
2874 | + waitUntilTransitionsEnd(); |
2875 | + verify(fakeApplication.surface !== null); |
2876 | + |
2877 | + applicationWindowLoader.item.visible = false; |
2878 | + |
2879 | + waitUntilTransitionsEnd(); |
2880 | + verify(stateGroup.state === "surface"); |
2881 | + verify(fakeApplication.surface !== null); |
2882 | + |
2883 | + applicationWindowLoader.item.visible = true; |
2884 | + |
2885 | + waitUntilTransitionsEnd(); |
2886 | + verify(stateGroup.state === "surface"); |
2887 | + verify(fakeApplication.surface !== null); |
2888 | + } |
2889 | + |
2890 | + function test_touchesReachSurfaceWhenItsShown() { |
2891 | + setApplicationState(appRunning); |
2892 | + surfaceCheckbox.checked = true; |
2893 | + |
2894 | + tryCompare(stateGroup, "state", "surface"); |
2895 | + |
2896 | + waitUntilTransitionsEnd(); |
2897 | + |
2898 | + // Because doing stuff in C++ is a PITA we keep the counter in the interal qml impl. |
2899 | + var fakeSurface = findChild(fakeApplication.surface, "fakeSurfaceQML"); |
2900 | + fakeSurface.touchPressCount = 0; |
2901 | + fakeSurface.touchReleaseCount = 0; |
2902 | + |
2903 | + tap(applicationWindowLoader.item, |
2904 | + applicationWindowLoader.item.width / 2, applicationWindowLoader.item.height / 2); |
2905 | + |
2906 | + verify(fakeSurface.touchPressCount === 1); |
2907 | + verify(fakeSurface.touchReleaseCount === 1); |
2908 | + } |
2909 | + |
2910 | + function test_showNothingOnSuddenSurfaceLoss() { |
2911 | + surfaceCheckbox.checked = true; |
2912 | + setApplicationState(appRunning); |
2913 | + tryCompare(stateGroup, "state", "surface"); |
2914 | + waitUntilTransitionsEnd(); |
2915 | + |
2916 | + surfaceCheckbox.checked = false; |
2917 | + |
2918 | + verify(stateGroup.state === "void"); |
2919 | + } |
2920 | + } |
2921 | +} |
2922 | |
2923 | === modified file 'tests/qmltests/Stages/tst_PhoneStage.qml' |
2924 | --- tests/qmltests/Stages/tst_PhoneStage.qml 2014-07-25 00:01:00 +0000 |
2925 | +++ tests/qmltests/Stages/tst_PhoneStage.qml 2014-08-21 13:12:27 +0000 |
2926 | @@ -26,14 +26,11 @@ |
2927 | width: units.gu(70) |
2928 | height: units.gu(70) |
2929 | |
2930 | - Rectangle { |
2931 | - |
2932 | - } |
2933 | - |
2934 | PhoneStage { |
2935 | id: phoneStage |
2936 | anchors { fill: parent; rightMargin: units.gu(30) } |
2937 | dragAreaWidth: units.gu(2) |
2938 | + maximizedAppTopMargin: units.gu(3) + units.dp(2) |
2939 | } |
2940 | |
2941 | Binding { |
2942 | @@ -46,6 +43,7 @@ |
2943 | anchors { fill: parent; leftMargin: phoneStage.width } |
2944 | |
2945 | Column { |
2946 | + id: buttons |
2947 | anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
2948 | spacing: units.gu(1) |
2949 | Button { |
2950 | @@ -57,9 +55,33 @@ |
2951 | } |
2952 | Button { |
2953 | anchors { left: parent.left; right: parent.right } |
2954 | - text: "Remove App" |
2955 | - onClicked: { |
2956 | - ApplicationManager.stopApplication(ApplicationManager.get(0).appId) |
2957 | + text: "Remove Selected" |
2958 | + onClicked: { |
2959 | + ApplicationManager.stopApplication(ApplicationManager.get(appList.selectedAppIndex).appId); |
2960 | + } |
2961 | + } |
2962 | + Button { |
2963 | + anchors { left: parent.left; right: parent.right } |
2964 | + text: "Stop Selected" |
2965 | + onClicked: { |
2966 | + ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfo.Stopped); |
2967 | + } |
2968 | + } |
2969 | + } |
2970 | + ListView { |
2971 | + id: appList |
2972 | + property int selectedAppIndex |
2973 | + anchors { left: parent.left; right: parent.right; top: buttons.bottom; bottom: parent.bottom } |
2974 | + boundsBehavior: Flickable.StopAtBounds |
2975 | + model: ApplicationManager |
2976 | + delegate: Rectangle { |
2977 | + anchors { left: parent.left; right: parent.right } |
2978 | + height: units.gu(2) |
2979 | + color: appList.selectedAppIndex === model.index ? "red" : "white" |
2980 | + Text { anchors.fill: parent; text: model.appId } |
2981 | + MouseArea { |
2982 | + anchors.fill: parent |
2983 | + onPressed: { appList.selectedAppIndex = model.index; } |
2984 | } |
2985 | } |
2986 | } |
2987 | @@ -84,7 +106,9 @@ |
2988 | function goToSpread() { |
2989 | var spreadView = findChild(phoneStage, "spreadView"); |
2990 | |
2991 | - var startX = phoneStage.width; |
2992 | + // Keep it inside the PhoneStage otherwise the controls on the right side will |
2993 | + // capture the press thus the "- 2" on startX. |
2994 | + var startX = phoneStage.width - 2; |
2995 | var startY = phoneStage.height / 2; |
2996 | var endY = startY; |
2997 | var endX = units.gu(2); |
2998 | @@ -132,7 +156,9 @@ |
2999 | |
3000 | var spreadView = findChild(phoneStage, "spreadView"); |
3001 | |
3002 | - var startX = phoneStage.width; |
3003 | + // Keep it inside the PhoneStage otherwise the controls on the right side will |
3004 | + // capture the press thus the "- 2" on startX. |
3005 | + var startX = phoneStage.width - 2; |
3006 | var startY = phoneStage.height / 2; |
3007 | var endY = startY; |
3008 | var endX = spreadView.width - (spreadView.width * spreadView[data.positionMarker]) - data.offset; |
3009 | @@ -230,6 +256,15 @@ |
3010 | compare(ApplicationManager.focusedApplicationId, selectedApp.appId); |
3011 | } |
3012 | |
3013 | + function test_surfaceSizer() { |
3014 | + var surface = { width: 100, height: 200 }; |
3015 | + var phoneStagePriv = findInvisibleChild(phoneStage, "priv"); |
3016 | + |
3017 | + surface = phoneStagePriv.surfaceSizer(surface); |
3018 | + compare(surface.width, phoneStage.width); |
3019 | + compare(surface.height, phoneStage.height - phoneStage.maximizedAppTopMargin); |
3020 | + } |
3021 | + |
3022 | function cleanup() { |
3023 | while (ApplicationManager.count > 1) { |
3024 | var oldCount = ApplicationManager.count; |
3025 | |
3026 | === added file 'tests/qmltests/Stages/tst_SpreadDelegate.qml' |
3027 | --- tests/qmltests/Stages/tst_SpreadDelegate.qml 1970-01-01 00:00:00 +0000 |
3028 | +++ tests/qmltests/Stages/tst_SpreadDelegate.qml 2014-08-21 13:12:27 +0000 |
3029 | @@ -0,0 +1,167 @@ |
3030 | +/* |
3031 | + * Copyright 2014 Canonical Ltd. |
3032 | + * |
3033 | + * This program is free software; you can redistribute it and/or modify |
3034 | + * it under the terms of the GNU General Public License as published by |
3035 | + * the Free Software Foundation; version 3. |
3036 | + * |
3037 | + * This program is distributed in the hope that it will be useful, |
3038 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3039 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3040 | + * GNU General Public License for more details. |
3041 | + * |
3042 | + * You should have received a copy of the GNU General Public License |
3043 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3044 | + */ |
3045 | + |
3046 | +import QtQuick 2.0 |
3047 | +import QtTest 1.0 |
3048 | +import Unity.Test 0.1 as UT |
3049 | +import ".." |
3050 | +import "../../../qml/Stages" |
3051 | +import Ubuntu.Components 0.1 |
3052 | +import Ubuntu.Components.ListItems 1.0 as ListItem |
3053 | +import Unity.Application 0.1 |
3054 | + |
3055 | +Rectangle { |
3056 | + color: "red" |
3057 | + id: root |
3058 | + width: units.gu(70) |
3059 | + height: units.gu(70) |
3060 | + |
3061 | + Component.onCompleted: { |
3062 | + root.fakeApplication = ApplicationManager.startApplication("gallery-app"); |
3063 | + } |
3064 | + property QtObject fakeApplication: null |
3065 | + |
3066 | + Component { |
3067 | + id: spreadDelegateComponent |
3068 | + SpreadDelegate { |
3069 | + anchors.fill: parent |
3070 | + swipeToCloseEnabled: swipeToCloseCheckbox.checked |
3071 | + closeable: closeableCheckbox.checked |
3072 | + application: fakeApplication |
3073 | + } |
3074 | + } |
3075 | + Loader { |
3076 | + id: spreadDelegateLoader |
3077 | + anchors { |
3078 | + top: parent.top |
3079 | + bottom: parent.bottom |
3080 | + left: parent.left |
3081 | + } |
3082 | + width: units.gu(40) |
3083 | + sourceComponent: spreadDelegateComponent |
3084 | + } |
3085 | + |
3086 | + Rectangle { |
3087 | + color: "white" |
3088 | + anchors { |
3089 | + top: parent.top |
3090 | + bottom: parent.bottom |
3091 | + left: spreadDelegateLoader.right |
3092 | + right: parent.right |
3093 | + } |
3094 | + |
3095 | + Column { |
3096 | + anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
3097 | + spacing: units.gu(1) |
3098 | + Row { |
3099 | + anchors { left: parent.left; right: parent.right } |
3100 | + CheckBox { id: swipeToCloseCheckbox; checked: false; } |
3101 | + Label { text: "swipeToCloseEnabled" } |
3102 | + } |
3103 | + Row { |
3104 | + anchors { left: parent.left; right: parent.right } |
3105 | + CheckBox { id: closeableCheckbox; checked: false } |
3106 | + Label { text: "closeable" } |
3107 | + } |
3108 | + } |
3109 | + } |
3110 | + |
3111 | + UT.UnityTestCase { |
3112 | + id: testCase |
3113 | + name: "SpreadDelegate" |
3114 | + when: windowShown |
3115 | + |
3116 | + SignalSpy { |
3117 | + id: spyClosedSignal |
3118 | + target: spreadDelegateLoader.item |
3119 | + signalName: "closed" |
3120 | + } |
3121 | + |
3122 | + property var dragArea |
3123 | + |
3124 | + function init() { |
3125 | + dragArea = findInvisibleChild(spreadDelegateLoader.item, "dragArea"); |
3126 | + dragArea.__dateTime = fakeDateTime; |
3127 | + } |
3128 | + |
3129 | + function cleanup() { |
3130 | + // reload our test subject to get it in a fresh state once again |
3131 | + spreadDelegateLoader.active = false; |
3132 | + spreadDelegateLoader.active = true; |
3133 | + |
3134 | + spyClosedSignal.clear(); |
3135 | + } |
3136 | + |
3137 | + function test_swipeToClose_data() { |
3138 | + return [ |
3139 | + {tag: "swipeToClose=true closeable=true -> appWindow moves away", |
3140 | + swipeToClose: true, closeable: true }, |
3141 | + |
3142 | + {tag: "swipeToClose=true closeable=alse -> appWindow bounces back", |
3143 | + swipeToClose: true, closeable: false }, |
3144 | + |
3145 | + {tag: "swipeToClose=false -> appWindow stays put", |
3146 | + swipeToClose: false, closeable: true }, |
3147 | + ] |
3148 | + } |
3149 | + |
3150 | + function test_swipeToClose(data) { |
3151 | + var appWindowWithShadow = findChild(spreadDelegateLoader.item, "appWindowWithShadow"); |
3152 | + |
3153 | + verify(appWindowWithShadow.y === 0); |
3154 | + |
3155 | + swipeToCloseCheckbox.checked = data.swipeToClose; |
3156 | + closeableCheckbox.checked = data.closeable; |
3157 | + |
3158 | + var dragDistance = spreadDelegateLoader.item.height / 2; |
3159 | + var touchX = spreadDelegateLoader.item.width / 2; |
3160 | + var fromY = spreadDelegateLoader.item.height / 2; |
3161 | + var toY = fromY - dragDistance; |
3162 | + touchFlick(spreadDelegateLoader.item, |
3163 | + touchX /* fromX */, fromY, touchX /* toX */, toY, |
3164 | + true /* beginTouch */, false /* endTouch */, dragArea.minSpeedToClose * 1.1 /* speed */); |
3165 | + |
3166 | + |
3167 | + if (data.swipeToClose) { |
3168 | + verify(appWindowWithShadow.y < 0); |
3169 | + verify(Math.abs(Math.abs(appWindowWithShadow.y) - dragDistance) < units.gu(1)); |
3170 | + |
3171 | + touchRelease(spreadDelegateLoader.item, touchX, toY - units.gu(1)); |
3172 | + |
3173 | + waitForCloseAnimationToFinish(); |
3174 | + |
3175 | + if (data.closeable) { |
3176 | + verify(spyClosedSignal.count === 1); |
3177 | + } else { |
3178 | + verify(spyClosedSignal.count === 0); |
3179 | + tryCompare(appWindowWithShadow, "y", 0); |
3180 | + } |
3181 | + |
3182 | + } else { |
3183 | + verify(appWindowWithShadow.y === 0); |
3184 | + |
3185 | + touchRelease(spreadDelegateLoader.item, touchX, toY); |
3186 | + } |
3187 | + } |
3188 | + |
3189 | + function waitForCloseAnimationToFinish() { |
3190 | + var closeAnimation = findInvisibleChild(spreadDelegateLoader.item, "closeAnimation"); |
3191 | + wait(closeAnimation.duration * 1.5); |
3192 | + tryCompare(closeAnimation, "running", false); |
3193 | + } |
3194 | + |
3195 | + } |
3196 | +} |
3197 | |
3198 | === modified file 'tests/qmltests/tst_Shell.qml' |
3199 | --- tests/qmltests/tst_Shell.qml 2014-07-29 11:35:10 +0000 |
3200 | +++ tests/qmltests/tst_Shell.qml 2014-08-21 13:12:27 +0000 |
3201 | @@ -403,11 +403,11 @@ |
3202 | compare(panel.fullscreenMode, false); |
3203 | ApplicationManager.startApplication("camera-app"); |
3204 | tryCompare(panel, "fullscreenMode", true); |
3205 | - ApplicationManager.startApplication("gallery-app"); |
3206 | + ApplicationManager.startApplication("dialer-app"); |
3207 | tryCompare(panel, "fullscreenMode", false); |
3208 | ApplicationManager.requestFocusApplication("camera-app"); |
3209 | tryCompare(panel, "fullscreenMode", true); |
3210 | - ApplicationManager.requestFocusApplication("gallery-app"); |
3211 | + ApplicationManager.requestFocusApplication("dialer-app"); |
3212 | tryCompare(panel, "fullscreenMode", false); |
3213 | } |
3214 | |
3215 | |
3216 | === modified file 'tests/utils/modules/Unity/Test/UnityTestCase.qml' |
3217 | --- tests/utils/modules/Unity/Test/UnityTestCase.qml 2014-06-23 16:40:11 +0000 |
3218 | +++ tests/utils/modules/Unity/Test/UnityTestCase.qml 2014-08-21 13:12:27 +0000 |
3219 | @@ -312,12 +312,15 @@ |
3220 | } |
3221 | |
3222 | function tap(item, x, y) { |
3223 | + var root = fetchRootItem(item) |
3224 | + var rootPoint = item.mapToItem(root, x, y) |
3225 | + |
3226 | var event = touchEvent() |
3227 | - event.press(0 /* touchId */, x, y) |
3228 | + event.press(0 /* touchId */, rootPoint.x, rootPoint.y) |
3229 | event.commit() |
3230 | |
3231 | event = touchEvent() |
3232 | - event.release(0 /* touchId */, x, y) |
3233 | + event.release(0 /* touchId */, rootPoint.x, rootPoint.y) |
3234 | event.commit() |
3235 | } |
3236 |
unity8-fake-env should provide unity-applicati ons-4 (or 3?).