@@ -0,0 +1,201 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import Ubuntu.Components 1.1
20+import Ubuntu.Components.ListItems 1.0 as ListItem
21+import Unity.Application 0.1
22+import Unity.Test 0.1
23+
24+import "../../../qml/Stages"
25+
26+Rectangle {
27+ id: root
28+ color: "darkblue"
29+ width: desktopStageLoader.width + controls.width
30+ height: desktopStageLoader.height
31+
32+ QtObject {
33+ id: fakeWindowStateStorage
34+
35+ property var storedGeom: [
36+ ["unity8-dash", Qt.rect(units.gu(2), units.gu(2), units.gu(50), units.gu(50))],
37+ ["webbrowser-app", Qt.rect(units.gu(60), units.gu(2), units.gu(50), units.gu(50))]
38+ ]
39+
40+ function saveGeometry(windowId, geometry) {
41+ for (var i = 0; i < storedGeom.length; ++i) {
42+ if (storedGeom[i][0] === windowId) {
43+ storedGeom[i][1] = geometry;
44+ return;
45+ }
46+ }
47+ // if new
48+ storedGeom[storedGeom.length] = [windowId, geometry];
49+ }
50+ function getGeometry(windowId, defaultGeometry) {
51+ for (var i = 0; i < storedGeom.length; ++i) {
52+ if (storedGeom[i][0] === windowId) {
53+ return storedGeom[i][1];
54+ }
55+ }
56+ return defaultGeometry;
57+ }
58+ }
59+
60+ Loader {
61+ id: desktopStageLoader
62+ x: ((root.width - controls.width) - width) / 2
63+ y: (root.height - height) / 2
64+ width: units.gu(160*0.9)
65+ height: units.gu(100*0.9)
66+
67+ focus: true
68+
69+ property bool itemDestroyed: false
70+ sourceComponent: Component {
71+ DesktopStage {
72+ anchors.fill: parent
73+ windowStateStorage: fakeWindowStateStorage
74+ Component.onDestruction: {
75+ desktopStageLoader.itemDestroyed = true;
76+ }
77+ focus: true
78+ }
79+ }
80+ }
81+
82+ Rectangle {
83+ id: controls
84+ color: "darkgrey"
85+ width: units.gu(30)
86+ anchors {
87+ top: parent.top
88+ bottom: parent.bottom
89+ right: parent.right
90+ }
91+
92+ Column {
93+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
94+ spacing: units.gu(1)
95+ Repeater {
96+ model: ApplicationManager.availableApplications
97+ ApplicationCheckBox {
98+ appId: modelData
99+ }
100+ }
101+ }
102+ }
103+
104+ UnityTestCase {
105+ id: testCase
106+ name: "DesktopStage"
107+ when: windowShown
108+
109+ property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null
110+
111+ function init() {
112+ }
113+
114+ function cleanup() {
115+ desktopStageLoader.itemDestroyed = false;
116+ desktopStageLoader.active = false;
117+
118+ tryCompare(desktopStageLoader, "status", Loader.Null);
119+ tryCompare(desktopStageLoader, "item", null);
120+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
121+ // actually took place. Likely because Loader waits until the next event loop
122+ // iteration to do its work. So to ensure the reload, we will wait until the
123+ // Shell instance gets destroyed.
124+ tryCompare(desktopStageLoader, "itemDestroyed", true);
125+
126+ killAllRunningApps();
127+
128+ desktopStageLoader.active = true;
129+ tryCompare(desktopStageLoader, "status", Loader.Ready);
130+ }
131+
132+ function killAllRunningApps() {
133+ while (ApplicationManager.count > 1) {
134+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
135+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId);
136+ }
137+ compare(ApplicationManager.count, 1)
138+ }
139+
140+ function waitUntilAppSurfaceShowsUp(appId) {
141+ var appWindow = findChild(desktopStage, "appWindow_" + appId);
142+ verify(appWindow);
143+ var appWindowStates = findInvisibleChild(appWindow, "applicationWindowStateGroup");
144+ verify(appWindowStates);
145+ tryCompare(appWindowStates, "state", "surface");
146+ }
147+
148+ function rectsIntersect(aLocal, bLocal) {
149+
150+ var a = aLocal.mapToItem(null, 0, 0, aLocal.width, aLocal.height);
151+ var b = bLocal.mapToItem(null, 0, 0, bLocal.width, bLocal.height);
152+
153+ return !((a.y+a.height) < b.y
154+ || a.y > (b.y+b.height)
155+ || (a.x+a.width) < b.x
156+ || a.x > (b.x+b.width));
157+ }
158+
159+ function test_tappingOnWindowChangesFocusedApp() {
160+ ApplicationManager.startApplication("webbrowser-app");
161+ waitUntilAppSurfaceShowsUp("webbrowser-app");
162+
163+ var webbrowserWindow = findChild(desktopStage, "appWindow_webbrowser-app");
164+ verify(webbrowserWindow);
165+ var dashWindow = findChild(desktopStage, "appWindow_unity8-dash");
166+ verify(dashWindow);
167+
168+ // some sanity check
169+ compare(rectsIntersect(dashWindow, webbrowserWindow), false);
170+
171+ tap(dashWindow);
172+ compare(dashWindow.application.session.surface.activeFocus, true);
173+
174+ tap(webbrowserWindow);
175+ compare(webbrowserWindow.application.session.surface.activeFocus, true);
176+ }
177+
178+ function test_tappingOnWindowTitleChangesFocusedApp() {
179+ ApplicationManager.startApplication("webbrowser-app");
180+ waitUntilAppSurfaceShowsUp("webbrowser-app");
181+
182+ var webbrowserWindow = findChild(desktopStage, "decoratedWindow_webbrowser-app");
183+ verify(webbrowserWindow);
184+ var webbrowserWindowTitle = findChild(webbrowserWindow, "windowDecorationTitle");
185+ verify(webbrowserWindowTitle);
186+ var dashWindow = findChild(desktopStage, "decoratedWindow_unity8-dash");
187+ verify(dashWindow);
188+ var dashWindowTitle = findChild(dashWindow, "windowDecorationTitle");
189+ verify(dashWindowTitle);
190+
191+ // some sanity check
192+ compare(rectsIntersect(dashWindow, webbrowserWindow), false);
193+
194+ tap(dashWindowTitle);
195+ compare(dashWindow.application.session.surface.activeFocus, true);
196+
197+ tap(webbrowserWindowTitle);
198+ compare(webbrowserWindow.application.session.surface.activeFocus, true);
199+ }
200+ }
201+}