1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
|
/*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.0
import QtTest 1.0
import ".."
import "../../../qml/Components"
import Unity.Application 0.1
import Ubuntu.Components 0.1
import Unity.Test 0.1 as UT
import "tst_Stage"
Rectangle {
width: units.gu(70)
height: stageRect.height
// Even though we replace the ApplicationScreenshot instances in Stage
// with our own fake ones, ApplicationScreenshot.qml still gives out a warning
// if shell.importUbuntuApplicationAvailable is missing.
// For we have this here for the sake of keeping a clean log output.
Item {
id: shell
property bool importUbuntuApplicationAvailable: false
}
// A fake ApplicationManager implementation to be passed to Stage
QtObject {
id: fakeAppManager
property ListModel mainStageApplications: ListModel {}
property ListModel sideStageApplications: ListModel {}
property var mainStageFocusedApplication
property Component fakeAppWindowComponent: Component {
Rectangle {
width: stage.width
height: stage.height
property alias text : txt.text
Text {id:txt}
}
}
function activateApplication(desktopFile, argument) {
var appWindow = fakeAppWindowComponent.createObject(fakeWindowContainer)
var application = {
'icon': "foo",
'handle': desktopFile,
'name': "Foo",
'fullscreen': false,
'desktopFile': desktopFile,
'stage': ApplicationInfo.MainStage,
'argument': 0,
'color': desktopFile,
'window': appWindow
};
appWindow.color = application.color
appWindow.text = desktopFile + " actual";
mainStageApplications.append(application)
updateZOrderOfWindows(mainStageApplications)
return application
}
function focusApplication(application) {
mainStageFocusedApplication = application
}
function getApplicationFromDesktopFile(desktopFile, stageType) {
var sideStage = (stage == ApplicationInfo.SideStage);
var applications = sideStage ? sideStageApplications
: mainStageApplications;
for (var i = 0; i < applications.count; i++ ) {
var application = applications.get(i);
if (application.desktopFile === desktopFile) {
return application;
}
}
return null;
}
function moveRunningApplicationStackPosition(from, to, stage) {
var sideStage = (stage == ApplicationInfo.SideStage);
var applications = sideStage ? sideStageApplications
: mainStageApplications;
if (from !== to && applications.count > 0 && from >= 0 && to >= 0) {
applications.move(from, to, 1);
}
updateZOrderOfWindows(applications)
}
function updateZOrderOfWindows(applications) {
var nextZ = 100
for (var i = 0; i < applications.count; i++ ) {
var application = applications.get(i);
application.window.z = nextZ--;
}
}
function deacticateApplication(desktopFile) {
for (var i = 0; i < mainStageApplications.count; i++ ) {
var application = mainStageApplications.get(i)
if (application.desktopFile === desktopFile) {
focusApplication(null)
application.window.destroy();
mainStageApplications.remove(i)
updateZOrderOfWindows(mainStageApplications)
return;
}
}
}
}
Rectangle {
id: stageRect
x:0
y:0
width: childrenRect.width
height: childrenRect.height
color: "grey"
// This is where the fake windows are held.
// They stay behind the stage, so that the stage's screenshots are shown
// on top of them
// On a real usage scenario, the current application's surface is composited behind
// the shell's surface (where Stage lives). fakeWindowContainer simulates this stacking
Item {
id: fakeWindowContainer
anchors.fill: parent
}
// A black rectangle behind the stage so that the window switch animations
// look good, just like in Stage's real usage.
Rectangle {
anchors.fill: parent
color: "black"
visible: stage.usingScreenshots
}
Stage {
id: stage
y: 0
shouldUseScreenshots: false
applicationManager: fakeAppManager
rightEdgeDraggingAreaWidth: units.gu(2)
fullyShown: true
fullyHidden: false
newApplicationScreenshot: FakeApplicationScreenshot {
id: newAppScreenshot
parent: stage
width: stage.width
height: stage.height - stage.y}
oldApplicationScreenshot: FakeApplicationScreenshot {
id: oldAppScreenshot
parent: stage
width: stage.width
height: stage.height - stage.y}
}
}
Rectangle {
id: controlsRect
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: stageRect.right
anchors.right: parent.right
color: "lightgrey"
Column {
id: controls
spacing: units.gu(1)
AppControl {id: redControl; desktopFile:"red"}
AppControl {id: greenControl; desktopFile:"green"}
AppControl {id: blueControl; desktopFile:"blue"}
}
}
UT.UnityTestCase {
name: "Stage"
when: windowShown
function isCurrentAppFadingOut() {
// it should get a bit translucent and smaller
return oldAppScreenshot.opacity < 0.99
&& oldAppScreenshot.opacity >= 0.1
&& oldAppScreenshot.scale < 0.99
&& oldAppScreenshot.scale >= 0.1
&& oldAppScreenshot.visible
}
function init() {
redControl.checked = false;
greenControl.checked = false;
blueControl.checked = false;
// give some room for animations to start
wait(50)
// wait until animations end, if any
tryCompare(stage, "usingScreenshots", false)
}
/* If you flick from the right edge of the stage leftwards it should cause an
application switch. */
function test_dragFromRightEdgeToSwitchApplication() {
redControl.checked = true
tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
tryCompare(stage, "usingScreenshots", false) // and then for it to end
compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "red")
compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "red")
greenControl.checked = true
tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
tryCompare(stage, "usingScreenshots", false) // and then for it to end
compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "green")
compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "green")
var touchX = stage.width - (stage.rightEdgeDraggingAreaWidth / 2)
var touchY = stage.height / 2
touchFlick(stage, touchX, touchY, stage.width * 0.25, touchY)
// wait until animations end, if any
tryCompare(stage, "usingScreenshots", false)
// "red" should be the new topmost, focused, application
compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "red")
compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "red")
}
/* When an application is launched, it needs a background before it's drawn on screen
so that the user does not see the previous running app while the new one is launching.
When switching between applications, backgrounds are unnecessary, 'cause the
applications are in front of them. */
function test_background() {
redControl.checked = true
tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
compare(newAppScreenshot.withBackground, true, "starting app screenshot does not have background enabled")
tryCompare(stage, "usingScreenshots", false) // wait for the animation to finish
greenControl.checked = true
tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
tryCompare(stage, "usingScreenshots", false) // and finish
var draggingAreaCenterX = stage.width - (stage.rightEdgeDraggingAreaWidth / 2)
var draggingAreaCenterY = stage.height / 2
var finalTouchX = draggingAreaCenterX - units.gu(5)
touchFlick(stage, draggingAreaCenterX, draggingAreaCenterY,
finalTouchX, draggingAreaCenterY,
true /* beginTouch */, false /* endTouch */)
// wait for the animation to start
tryCompare(stage, "usingScreenshots", true)
compare(newAppScreenshot.withBackground, false, "switched app does have background enabled")
touchRelease(stage, finalTouchX, draggingAreaCenterY)
}
}
}
|