on xenial help sign in
merged with unified stages
d93306eNick Dedekind
debian/changelog+5−3
@@ -1,4 +1,4 @@
1−unity8 (8.14+16.10.20160922-0ubuntu1) yakkety; urgency=medium
1+unity8 (8.14+16.10.20160914-0ubuntu1) yakkety; urgency=medium
2
2
3 [ Albert Astals Cid ]
3 [ Albert Astals Cid ]
4 * LVWPH: update clipItem height when list height changes (LP:
4 * LVWPH: update clipItem height when list height changes (LP:
@@ -46,12 +46,14 @@ unity8 (8.14+16.10.20160922-0ubuntu1) yakkety; urgency=medium
46 the greeter.
46 the greeter.
47
47
48 [ Lukáš Tinkl ]
48 [ Lukáš Tinkl ]
49− * Implement edge maximizing (aka window snapping) (LP: #1602628)
50 * On the PC platform (as opposed to running on $devices), use the
49 * On the PC platform (as opposed to running on $devices), use the
51 "mute" action instead of silent mode
50 "mute" action instead of silent mode
52 * Respect Fitt's law wrt the window control buttons in panel (LP:
51 * Respect Fitt's law wrt the window control buttons in panel (LP:
53 #1611959)
52 #1611959)
54 * Fix 2 failing color-related tests
53 * Fix 2 failing color-related tests
54+ * Implement edge maximizing (aka window snapping) (LP: #1602628,
55+ #1611859)
56+ * Implement moving windows by Alt + left mouse button
55
57
56 [ Marco Trevisan (Treviño) ]
58 [ Marco Trevisan (Treviño) ]
57 * Indicators, mocks: add fake indicators menuitem to populate mocks
59 * Indicators, mocks: add fake indicators menuitem to populate mocks
@@ -73,7 +75,7 @@ unity8 (8.14+16.10.20160922-0ubuntu1) yakkety; urgency=medium
73 * Update look of infographic a bit
75 * Update look of infographic a bit
74 * Make infographic bubbles white even on the default wallpaper.
76 * Make infographic bubbles white even on the default wallpaper.
75
77
76− -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 22 Sep 2016 07:46:57 +0000
78+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 14 Sep 2016 00:46:45 +0000
77
79
78unity8 (8.14+16.10.20160831.3-0ubuntu1) yakkety; urgency=medium
80unity8 (8.14+16.10.20160831.3-0ubuntu1) yakkety; urgency=medium
79
81
debian/unity8.install+1−1
@@ -17,7 +17,7 @@ usr/share/unity8/DeviceConfiguration.qml
17usr/share/unity8/OrientedShell.qml
17usr/share/unity8/OrientedShell.qml
18usr/share/unity8/DisabledScreenNotice.qml
18usr/share/unity8/DisabledScreenNotice.qml
19usr/share/unity8/Shell.qml
19usr/share/unity8/Shell.qml
20−usr/share/unity8/Stages
20+usr/share/unity8/Stage
21usr/share/unity8/Tutorial
21usr/share/unity8/Tutorial
22usr/share/unity8/Wizard
22usr/share/unity8/Wizard
23usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher
23usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher
plugins/Ubuntu/Gestures/TouchGate.cpp+4−1
@@ -61,7 +61,10 @@ void TouchGate::touchEvent(QTouchEvent *event)
61 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
61 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
62
62
63 if (touchPoint.state() == Qt::TouchPointPressed) {
63 if (touchPoint.state() == Qt::TouchPointPressed) {
64+// FIXME: This assert triggers frequently in make trySomething. We have verified
65+// that it's a bug in the mouse to touch conversion of the test environment
66+// and not in the actual product. Still, it probably should be cleaned up eventually.
64− Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
67+// Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
65 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
68 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
66 m_touchInfoMap[touchPoint.id()].ended = false;
69 m_touchInfoMap[touchPoint.id()].ended = false;
67 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
70 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
plugins/Unity/ApplicationMenu/com.ubuntu.MenuRegistrar.xml+13−13
@@ -4,7 +4,7 @@
4 @mainpage
4 @mainpage
5
5
6 An interface to register menus that are associated with a window in an application. The
6 An interface to register menus that are associated with a window in an application. The
7− main interface is docuemented here: @ref com::ubuntu::MenuRegistrar.
7+ main interface is documented here: @ref com::ubuntu::MenuRegistrar.
8
8
9 The actual menus are transported using the gmenumodel protocol
9 The actual menus are transported using the gmenumodel protocol
10 ]]></dox:d>
10 ]]></dox:d>
@@ -16,34 +16,34 @@
16 </dox:d>
16 </dox:d>
17 <method name="RegisterAppMenu">
17 <method name="RegisterAppMenu">
18 <dox:d><![CDATA[
18 <dox:d><![CDATA[
19− Associates a gmenumodel with a application
19+ Associates a gmenumodel with an application
20
20
21 /note this method assumes that the connection from the caller is the DBus connection
21 /note this method assumes that the connection from the caller is the DBus connection
22 to use for the object. Applications that use multiple DBus connections will need to
22 to use for the object. Applications that use multiple DBus connections will need to
23− ensure this method is called with the same connection that implmenets the object.
23+ ensure this method is called with the same connection that implements the object.
24 ]]></dox:d>
24 ]]></dox:d>
25 <arg name="pid" type="u" direction="in">
25 <arg name="pid" type="u" direction="in">
26 <dox:d>The process ID of the application for which the menu is associated</dox:d>
26 <dox:d>The process ID of the application for which the menu is associated</dox:d>
27 </arg>
27 </arg>
28 <arg name="menuObjectPath" type="o" direction="in">
28 <arg name="menuObjectPath" type="o" direction="in">
29− <dox:d>The object on the dbus interface implementing the gmenumodel interface</dox:d>
29+ <dox:d>The dbus path where the gmenumodel interface for the application menu has been exported</dox:d>
30 </arg>
30 </arg>
31 <arg name="actionObjectPath" type="o" direction="in">
31 <arg name="actionObjectPath" type="o" direction="in">
32− <dox:d>The object on the dbus interface implementing the gactiongroup interface</dox:d>
32+ <dox:d>The dbus path where the gactionmenu interface for the application menu actions has been exported</dox:d>
33 </arg>
33 </arg>
34 <arg name="service" type="s" direction="in">
34 <arg name="service" type="s" direction="in">
35− <dox:d>The address of the connection on DBus (e.g. :1.23 or org.example.service)</dox:d>
35+ <dox:d>The dbus conection name of the client application to be registered (e.g. :1.23 or org.example.service)</dox:d>
36 </arg>
36 </arg>
37 </method>
37 </method>
38 <method name="UnregisterAppMenu">
38 <method name="UnregisterAppMenu">
39 <dox:d>
39 <dox:d>
40− A method to allow removing a application menu from the database.
40+ A method to allow removing an application menu from the database.
41 </dox:d>
41 </dox:d>
42 <arg name="pid" type="u" direction="in">
42 <arg name="pid" type="u" direction="in">
43 <dox:d>The process id of the application</dox:d>
43 <dox:d>The process id of the application</dox:d>
44 </arg>
44 </arg>
45 <arg name="menuObjectPath" type="o" direction="in">
45 <arg name="menuObjectPath" type="o" direction="in">
46− <dox:d>The object on the dbus interface implementing the gmenumodel interface</dox:d>
46+ <dox:d>The dbus path for the registered application menu to be unregistered</dox:d>
47 </arg>
47 </arg>
48 </method>
48 </method>
49
49
@@ -53,19 +53,19 @@
53
53
54 /note this method assumes that the connection from the caller is the DBus connection
54 /note this method assumes that the connection from the caller is the DBus connection
55 to use for the object. Applications that use multiple DBus connections will need to
55 to use for the object. Applications that use multiple DBus connections will need to
56− ensure this method is called with the same connection that implmenets the object.
56+ ensure this method is called with the same connection that implements the object.
57 ]]></dox:d>
57 ]]></dox:d>
58 <arg name="surface" type="s" direction="in">
58 <arg name="surface" type="s" direction="in">
59 <dox:d>The surface ID of the surface</dox:d>
59 <dox:d>The surface ID of the surface</dox:d>
60 </arg>
60 </arg>
61 <arg name="menuObjectPath" type="o" direction="in">
61 <arg name="menuObjectPath" type="o" direction="in">
62− <dox:d>The object on the dbus interface implementing the gmenumodel interface</dox:d>
62+ <dox:d>The dbus path where the gmenumodel interface for the surface menu has been exported</dox:d>
63 </arg>
63 </arg>
64 <arg name="actionObjectPath" type="o" direction="in">
64 <arg name="actionObjectPath" type="o" direction="in">
65− <dox:d>The object on the dbus interface implementing the gactiongroup interface</dox:d>
65+ <dox:d>The dbus path where the gactionmenu interface for the surface menu actions has been exported</dox:d>
66 </arg>
66 </arg>
67 <arg name="service" type="s" direction="in">
67 <arg name="service" type="s" direction="in">
68− <dox:d>The address of the connection on DBus (e.g. :1.23 or org.example.service)</dox:d>
68+ <dox:d>The dbus conection name of the client application to be registered (e.g. :1.23 or org.example.service)</dox:d>
69 </arg>
69 </arg>
70 </method>
70 </method>
71 <method name="UnregisterSurfaceMenu">
71 <method name="UnregisterSurfaceMenu">
@@ -76,7 +76,7 @@
76 <dox:d>The surface id of the surface</dox:d>
76 <dox:d>The surface id of the surface</dox:d>
77 </arg>
77 </arg>
78 <arg name="menuObjectPath" type="o" direction="in">
78 <arg name="menuObjectPath" type="o" direction="in">
79− <dox:d>The object on the dbus interface implementing the gmenumodel interface</dox:d>
79+ <dox:d>The dbus path for the registered surface menu to be unregistered</dox:d>
80 </arg>
80 </arg>
81 </method>
81 </method>
82 </interface>
82 </interface>
plugins/WindowManager/TopLevelSurfaceList.cpp−5
@@ -133,11 +133,6 @@ void TopLevelSurfaceList::appendSurfaceHelper(MirSurfaceInterface *surface, Appl
133
133
134void TopLevelSurfaceList::connectSurface(MirSurfaceInterface *surface)
134void TopLevelSurfaceList::connectSurface(MirSurfaceInterface *surface)
135{
135{
136− connect(surface, &MirSurfaceInterface::focusedChanged, this, [this, surface](bool focused){
137− if (focused) {
138− this->raise(surface);
139− }
140− });
141 connect(surface, &MirSurfaceInterface::liveChanged, this, [this, surface](bool live){
136 connect(surface, &MirSurfaceInterface::liveChanged, this, [this, surface](bool live){
142 if (!live) {
137 if (!live) {
143 onSurfaceDied(surface);
138 onSurfaceDied(surface);
qml/ApplicationMenus/MenuBarLoader.qml+1−1
@@ -101,7 +101,7 @@ Item {
101 property bool popupVisible: __popup && __popup.visible
101 property bool popupVisible: __popup && __popup.visible
102
102
103 implicitWidth: column.implicitWidth
103 implicitWidth: column.implicitWidth
104− implicitHeight: parent.height
104+ implicitHeight: row.height
105 enabled: model.sensitive
105 enabled: model.sensitive
106
106
107 Keys.forwardTo: [ root ]
107 Keys.forwardTo: [ root ]
qml/CMakeLists.txt+1−1
@@ -13,7 +13,7 @@ set(QML_DIRS
13 Launcher
13 Launcher
14 Notifications
14 Notifications
15 Panel
15 Panel
16− Stages
16+ Stage
17 Rotation
17 Rotation
18 Tutorial
18 Tutorial
19 Wizard
19 Wizard
qml/Components/EdgeBarrier.qml+2
@@ -29,6 +29,8 @@ Item {
29 // Supported values are: Qt.LeftEdge, Qt.RightEdge
29 // Supported values are: Qt.LeftEdge, Qt.RightEdge
30 property int edge: Qt.LeftEdge
30 property int edge: Qt.LeftEdge
31
31
32+ readonly property alias progress: controller.progress
33+
32 property Item target: parent
34 property Item target: parent
33 function push(amount) { controller.push(amount); }
35 function push(amount) { controller.push(amount); }
34 signal passed()
36 signal passed()
qml/Components/FloatingFlickable.qml+3
@@ -35,6 +35,9 @@ Item {
35 property alias contentX: flickable.contentX
35 property alias contentX: flickable.contentX
36 property alias contentY: flickable.contentY
36 property alias contentY: flickable.contentY
37 property alias direction: swipeArea.direction
37 property alias direction: swipeArea.direction
38+ property alias leftMargin: flickable.leftMargin
39+ property alias rightMargin: flickable.rightMargin
40+ property alias dragging: flickable.dragging
38
41
39 MouseEventGenerator {
42 MouseEventGenerator {
40 id: mouseEventGenerator
43 id: mouseEventGenerator
qml/Greeter/LoginAreaContainer.qml+1−1
@@ -26,7 +26,7 @@ Item {
26 rightMargin: -units.gu(1.5)
26 rightMargin: -units.gu(1.5)
27 bottomMargin: -units.gu(1.5)
27 bottomMargin: -units.gu(1.5)
28 }
28 }
29− source: "../Stages/graphics/dropshadow2gu.sci"
29+ source: "../graphics/dropshadow2gu.sci"
30 opacity: 0.35
30 opacity: 0.35
31 }
31 }
32
32
qml/Notifications/Notification.qml+1−1
@@ -143,7 +143,7 @@ StyledItem {
143 fill: contents
143 fill: contents
144 margins: shapedBack.visible ? -units.gu(1) : -units.gu(1.5)
144 margins: shapedBack.visible ? -units.gu(1) : -units.gu(1.5)
145 }
145 }
146− source: "../Stages/graphics/dropshadow2gu.sci"
146+ source: "../graphics/dropshadow2gu.sci"
147 opacity: notification.opacity * 0.5
147 opacity: notification.opacity * 0.5
148 enabled: !fullscreen
148 enabled: !fullscreen
149 }
149 }
qml/Rotation/RotationStates.qml−6
@@ -121,12 +121,6 @@ StateGroup {
121 }
121 }
122 }
122 }
123
123
124− property var shellBeingResized: Binding {
125− target: root.shell
126− property: "beingResized"
127− value: d.transitioning
128− }
129−
130 readonly property int fullAnimation: 0
124 readonly property int fullAnimation: 0
131 readonly property int indicatorsBarAnimation: 1
125 readonly property int indicatorsBarAnimation: 1
132 readonly property int noAnimation: 2
126 readonly property int noAnimation: 2
qml/Shell.qml+52−165
@@ -35,7 +35,7 @@ import "Launcher"
35import "Panel"
35import "Panel"
36import "Components"
36import "Components"
37import "Notifications"
37import "Notifications"
38−import "Stages"
38+import "Stage"
39import "Tutorial"
39import "Tutorial"
40import "Wizard"
40import "Wizard"
41import Unity.Notifications 1.0 as NotificationBackend
41import Unity.Notifications 1.0 as NotificationBackend
@@ -58,24 +58,22 @@ StyledItem {
58 property real nativeWidth
58 property real nativeWidth
59 property real nativeHeight
59 property real nativeHeight
60 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
60 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
61− property bool beingResized
62 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
61 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
63 property string mode: "full-greeter"
62 property string mode: "full-greeter"
64 property alias oskEnabled: inputMethod.enabled
63 property alias oskEnabled: inputMethod.enabled
65 function updateFocusedAppOrientation() {
64 function updateFocusedAppOrientation() {
66− applicationsDisplayLoader.item.updateFocusedAppOrientation();
65+ stage.updateFocusedAppOrientation();
67 }
66 }
68 function updateFocusedAppOrientationAnimated() {
67 function updateFocusedAppOrientationAnimated() {
69− applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
68+ stage.updateFocusedAppOrientationAnimated();
70 }
69 }
71 property bool hasMouse: false
70 property bool hasMouse: false
72
71
73 // to be read from outside
72 // to be read from outside
74− readonly property int mainAppWindowOrientationAngle:
73+ readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
75− applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
76
74
77 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
75 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
78− && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
76+ && stage.orientationChangesEnabled
79 && (!greeter || !greeter.animating)
77 && (!greeter || !greeter.animating)
80
78
81 readonly property bool showingGreeter: greeter && greeter.shown
79 readonly property bool showingGreeter: greeter && greeter.shown
@@ -89,19 +87,13 @@ StyledItem {
89 return Qt.PrimaryOrientation;
87 return Qt.PrimaryOrientation;
90 } else if (showingGreeter || notifications.topmostIsFullscreen) {
88 } else if (showingGreeter || notifications.topmostIsFullscreen) {
91 return Qt.PrimaryOrientation;
89 return Qt.PrimaryOrientation;
92− } else if (applicationsDisplayLoader.item) {
93− return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
94 } else {
90 } else {
95− // we just don't care
91+ return shell.orientations.map(stage.supportedOrientations);
96− return Qt.PortraitOrientation
97− | Qt.LandscapeOrientation
98− | Qt.InvertedPortraitOrientation
99− | Qt.InvertedLandscapeOrientation;
100 }
92 }
101 }
93 }
102
94
103− readonly property var mainApp:
95+ readonly property var mainApp: stage.mainApp
104− applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
96+
105 onMainAppChanged: {
97 onMainAppChanged: {
106 if (mainApp) {
98 if (mainApp) {
107 _onMainAppChanged(mainApp.appId);
99 _onMainAppChanged(mainApp.appId);
@@ -278,154 +270,50 @@ StyledItem {
278 applicationsModel: ApplicationManager
270 applicationsModel: ApplicationManager
279 }
271 }
280
272
281− Loader {
273+ Stage {
282− id: applicationsDisplayLoader
274+ id: stage
283− objectName: "applicationsDisplayLoader"
275+ objectName: "stage"
284 anchors.fill: parent
276 anchors.fill: parent
277+ focus: true
278+
279+ dragAreaWidth: shell.edgeSize
280+ background: wallpaperResolver.background
281+ leftEdgeDragProgress: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 :
282+ Math.max(0, (launcher.dragDistance * (stage.width - launcher.panelWidth) / stage.width) - launcher.panelWidth)
285
283
286− // When we have a locked app, we only want to show that one app.
284+ applicationManager: ApplicationManager
287− // FIXME: do this in a less traumatic way. We currently only allow
285+ topLevelSurfaceList: topLevelSurfaceList
288− // locked apps in phone mode (see FIXME in Lockscreen component in
286+ inputMethodRect: inputMethod.visibleRect
289− // this same file). When that changes, we need to do something
290− // nicer here. But this code is currently just to prevent a
291− // theoretical attack where user enters lockedApp mode, then makes
292− // the screen larger (maybe connects to monitor) and tries to enter
293− // tablet mode.
294
287
295 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
288 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
296− ? "phone"
289+ ? "phone"
297− : shell.usageScenario
290+ : shell.usageScenario
298− readonly property string qmlComponent: {
291+
299− if (applicationsDisplayLoader.usageScenario === "phone") {
292+ mode: usageScenario == "phone" ? "staged"
300− return "Stages/PhoneStage.qml";
301− } else if (applicationsDisplayLoader.usageScenario === "tablet") {
293+ : usageScenario == "tablet" ? "stagedWithSideStage"
302− return "Stages/TabletStage.qml";
294+ : "windowed"
303− } else {
295+
304− return "Stages/DesktopStage.qml";
296+ shellOrientation: shell.orientation
305− }
297+ shellOrientationAngle: shell.orientationAngle
306− }
298+ orientations: shell.orientations
307− // TODO: Ensure the current stage is destroyed before the new one gets loaded.
299+ nativeWidth: shell.nativeWidth
308− // Currently the new one will get loaded while the old is still hanging
300+ nativeHeight: shell.nativeHeight
309− // around for a bit, which might lead to conflicts where both stages
310− // change the model simultaneously.
311− onQmlComponentChanged: {
312− if (item) item.stageAboutToBeUnloaded();
313− source = qmlComponent;
314− }
315
301
316− property bool interactive: (!greeter || !greeter.shown)
302+ interactive: (!greeter || !greeter.shown)
317 && panel.indicators.fullyClosed
303 && panel.indicators.fullyClosed
318 && launcher.progress == 0
304 && launcher.progress == 0
319 && !notifications.useModal
305 && !notifications.useModal
320
306
321 onInteractiveChanged: { if (interactive) { focus = true; } }
307 onInteractiveChanged: { if (interactive) { focus = true; } }
322
308
323− Binding {
324− target: applicationsDisplayLoader.item
325− property: "focus"
326− value: true
327− }
328− Binding {
329− target: applicationsDisplayLoader.item
330− property: "objectName"
331− value: "stage"
332− }
333− Binding {
334− target: applicationsDisplayLoader.item
335− property: "dragAreaWidth"
336− value: shell.edgeSize
337− }
338− Binding {
339− target: applicationsDisplayLoader.item
340− property: "maximizedAppTopMargin"
341− // Not just using panel.panelHeight as that changes depending on the focused app.
342− value: panel.indicators.minimizedPanelHeight
343− }
344− Binding {
345− target: applicationsDisplayLoader.item
346− property: "interactive"
347− value: applicationsDisplayLoader.interactive
348− }
349− Binding {
350− target: applicationsDisplayLoader.item
351− property: "spreadEnabled"
352− value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
353− }
354− Binding {
355− target: applicationsDisplayLoader.item
356− property: "inverseProgress"
357− value: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 : launcher.progress
358− }
359− Binding {
360− target: applicationsDisplayLoader.item
361− property: "shellOrientationAngle"
362− value: shell.orientationAngle
363− }
364− Binding {
365− target: applicationsDisplayLoader.item
366− property: "shellOrientation"
367− value: shell.orientation
368− }
369− Binding {
370− target: applicationsDisplayLoader.item
371− property: "orientations"
372− value: shell.orientations
373− }
374− Binding {
375− target: applicationsDisplayLoader.item
376− property: "background"
377− value: wallpaperResolver.cachedBackground
378− }
379− Binding {
380− target: applicationsDisplayLoader.item
381− property: "nativeWidth"
382− value: shell.nativeWidth
383− }
384− Binding {
385− target: applicationsDisplayLoader.item
386− property: "nativeHeight"
387− value: shell.nativeHeight
388− }
389− Binding {
390− target: applicationsDisplayLoader.item
391− property: "beingResized"
392− value: shell.beingResized
393− }
394− Binding {
395− target: applicationsDisplayLoader.item
396− property: "keepDashRunning"
397− value: launcher.shown || launcher.dashSwipe
398− }
399− Binding {
400− target: applicationsDisplayLoader.item
401− property: "suspended"
402− value: greeter.shown
403− }
404− Binding {
405− target: applicationsDisplayLoader.item
406− property: "altTabPressed"
407− value: physicalKeysMapper.altTabPressed
408− }
409− Binding {
410− target: applicationsDisplayLoader.item
411− property: "leftMargin"
412− value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
309+ leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
413− }
310+ suspended: greeter.shown
414− Binding {
311+ keepDashRunning: launcher.shown || launcher.dashSwipe
415− target: applicationsDisplayLoader.item
312+ altTabPressed: physicalKeysMapper.altTabPressed
416− property: "applicationManager"
313+ oskEnabled: shell.oskEnabled
417− value: ApplicationManager
314+
418− }
315+ // TODO: This is not implemented yet in the new stage...
419− Binding {
316+ spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
420− target: applicationsDisplayLoader.item
421− property: "topLevelSurfaceList"
422− value: topLevelSurfaceList
423− }
424− Binding {
425− target: applicationsDisplayLoader.item
426− property: "oskEnabled"
427− value: shell.oskEnabled
428− }
429 }
317 }
430 }
318 }
431
319
@@ -442,6 +330,7 @@ StyledItem {
442
330
443 Loader {
331 Loader {
444 id: greeterLoader
332 id: greeterLoader
333+ objectName: "greeterLoader"
445 anchors.fill: parent
334 anchors.fill: parent
446 anchors.topMargin: panel.panelHeight
335 anchors.topMargin: panel.panelHeight
447 sourceComponent: shell.mode != "shell" ? integratedGreeter :
336 sourceComponent: shell.mode != "shell" ? integratedGreeter :
@@ -654,7 +543,7 @@ StyledItem {
654 }
543 }
655 onFocusChanged: {
544 onFocusChanged: {
656 if (!focus) {
545 if (!focus) {
657− applicationsDisplayLoader.focus = true;
546+ stage.focus = true;
658 }
547 }
659 }
548 }
660
549
@@ -710,12 +599,12 @@ StyledItem {
710 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
599 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
711 inputMethod.visible ||
600 inputMethod.visible ||
712 (launcher.shown && !launcher.lockedVisible) ||
601 (launcher.shown && !launcher.lockedVisible) ||
713− panel.indicators.shown || stage.dragProgress > 0
602+ panel.indicators.shown || stage.rightEdgeDragProgress > 0
714 usageScenario: shell.usageScenario
603 usageScenario: shell.usageScenario
715 lastInputTimestamp: inputFilter.lastInputTimestamp
604 lastInputTimestamp: inputFilter.lastInputTimestamp
716 launcher: launcher
605 launcher: launcher
717 panel: panel
606 panel: panel
718− stage: applicationsDisplayLoader.item
607+ stage: stage
719 }
608 }
720
609
721 Wizard {
610 Wizard {
@@ -806,7 +695,7 @@ StyledItem {
806 z: dialogs.z + 10
695 z: dialogs.z + 10
807 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
696 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
808 Connections {
697 Connections {
809− target: applicationsDisplayLoader.item
698+ target: stage
810 ignoreUnknownSignals: true
699 ignoreUnknownSignals: true
811 onItemSnapshotRequested: itemGrabber.capture(item)
700 onItemSnapshotRequested: itemGrabber.capture(item)
812 }
701 }
@@ -818,7 +707,7 @@ StyledItem {
818 z: itemGrabber.z + 1
707 z: itemGrabber.z + 1
819 topBoundaryOffset: panel.panelHeight
708 topBoundaryOffset: panel.panelHeight
820
709
821− confiningItem: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.itemConfiningMouseCursor : null
710+ confiningItem: stage.itemConfiningMouseCursor
822
711
823 property bool mouseNeverMoved: true
712 property bool mouseNeverMoved: true
824 Binding {
713 Binding {
@@ -832,10 +721,9 @@ StyledItem {
832
721
833 height: units.gu(3)
722 height: units.gu(3)
834
723
835− readonly property var previewRectangle: applicationsDisplayLoader.item && applicationsDisplayLoader.item.previewRectangle &&
724+ readonly property var previewRectangle: stage.previewRectangle.target &&
836− applicationsDisplayLoader.item.previewRectangle.target &&
837− applicationsDisplayLoader.item.previewRectangle.target.dragging ?
725+ stage.previewRectangle.target.dragging ?
838− applicationsDisplayLoader.item.previewRectangle : null
726+ stage.previewRectangle : null
839
727
840 onPushedLeftBoundary: {
728 onPushedLeftBoundary: {
841 if (buttons === Qt.NoButton) {
729 if (buttons === Qt.NoButton) {
@@ -846,9 +734,8 @@ StyledItem {
846 }
734 }
847
735
848 onPushedRightBoundary: {
736 onPushedRightBoundary: {
849− if (buttons === Qt.NoButton && applicationsDisplayLoader.item
737+ if (buttons === Qt.NoButton) {
850− && applicationsDisplayLoader.item.pushRightEdge) {
851− applicationsDisplayLoader.item.pushRightEdge(amount);
738+ stage.pushRightEdge(amount);
852 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
739 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
853 previewRectangle.maximizeRight(amount);
740 previewRectangle.maximizeRight(amount);
854 }
741 }
qml/Stages/AbstractStage.qml → qml/Stage/AbstractStage.qmlrenamed

The content is the same.

qml/Stages/ApplicationWindow.qml → qml/Stage/ApplicationWindow.qmlrenamed+13−37
@@ -20,8 +20,8 @@ import Unity.Application 0.1
20
20
21FocusScope {
21FocusScope {
22 id: root
22 id: root
23− implicitWidth: surfaceContainer.implicitWidth
23+ implicitWidth: requestedWidth
24− implicitHeight: surfaceContainer.implicitHeight
24+ implicitHeight: requestedHeight
25
25
26 // to be read from outside
26 // to be read from outside
27 property alias interactive: surfaceContainer.interactive
27 property alias interactive: surfaceContainer.interactive
@@ -29,22 +29,10 @@ FocusScope {
29 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
29 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
30 readonly property QtObject focusedSurface: d.focusedSurface.surface
30 readonly property QtObject focusedSurface: d.focusedSurface.surface
31
31
32− // overridable from outside
33− property bool fullscreen: {
34− if (surface) {
35− return surface.state === Mir.FullscreenState;
36− } else if (application) {
37− return application.fullscreen;
38− } else {
39− return false;
40− }
41− }
42−
43 // to be set from outside
32 // to be set from outside
44 property QtObject surface
33 property QtObject surface
45 property QtObject application
34 property QtObject application
46 property int surfaceOrientationAngle
35 property int surfaceOrientationAngle
47− property alias resizeSurface: surfaceContainer.resizeSurface
48 property int requestedWidth: -1
36 property int requestedWidth: -1
49 property int requestedHeight: -1
37 property int requestedHeight: -1
50 property real splashRotation: 0
38 property real splashRotation: 0
@@ -156,6 +144,9 @@ FocusScope {
156 id: screenshotImage
144 id: screenshotImage
157 objectName: "screenshotImage"
145 objectName: "screenshotImage"
158 anchors.fill: parent
146 anchors.fill: parent
147+ fillMode: Image.PreserveAspectCrop
148+ horizontalAlignment: Image.AlignLeft
149+ verticalAlignment: Image.AlignTop
159 antialiasing: !root.interactive
150 antialiasing: !root.interactive
160 z: 1
151 z: 1
161
152
@@ -197,6 +188,7 @@ FocusScope {
197
188
198 SurfaceContainer {
189 SurfaceContainer {
199 id: surfaceContainer
190 id: surfaceContainer
191+ anchors.fill: parent
200 z: splashLoader.z + 1
192 z: splashLoader.z + 1
201 requestedWidth: root.requestedWidth
193 requestedWidth: root.requestedWidth
202 requestedHeight: root.requestedHeight
194 requestedHeight: root.requestedHeight
@@ -220,6 +212,8 @@ FocusScope {
220 surface: model.surface
212 surface: model.surface
221 width: root.width
213 width: root.width
222 height: root.height
214 height: root.height
215+ requestedWidth: root.requestedWidth
216+ requestedHeight: root.requestedHeight
223 isPromptSurface: true
217 isPromptSurface: true
224 z: surfaceContainer.z + (promptSurfacesRepeater.count - index)
218 z: surfaceContainer.z + (promptSurfacesRepeater.count - index)
225 property int index: model.index
219 property int index: model.index
@@ -239,28 +233,6 @@ FocusScope {
239 property Item first: null
233 property Item first: null
240 }
234 }
241
235
242− // SurfaceContainer size drives ApplicationWindow size
243− Binding {
244− target: root; property: "width"
245− value: stateGroup.state === "surface" ? surfaceContainer.width : root.requestedWidth
246− when: root.requestedWidth >= 0
247− }
248− Binding {
249− target: root; property: "height"
250− value: stateGroup.state === "surface" ? surfaceContainer.height : root.requestedHeight
251− when: root.requestedHeight >= 0
252− }
253−
254− // ApplicationWindow size drives SurfaceContainer size
255− Binding {
256− target: surfaceContainer; property: "width"; value: root.width
257− when: root.requestedWidth < 0
258− }
259− Binding {
260− target: surfaceContainer; property: "height"; value: root.height
261− when: root.requestedHeight < 0
262− }
263−
264 StateGroup {
236 StateGroup {
265 id: stateGroup
237 id: stateGroup
266 objectName: "applicationWindowStateGroup"
238 objectName: "applicationWindowStateGroup"
@@ -287,6 +259,11 @@ FocusScope {
287 (d.liveSurface ||
259 (d.liveSurface ||
288 (d.applicationState !== ApplicationInfoInterface.Running
260 (d.applicationState !== ApplicationInfoInterface.Running
289 && screenshotImage.status !== Image.Ready))
261 && screenshotImage.status !== Image.Ready))
262+ PropertyChanges {
263+ target: root
264+ implicitWidth: surfaceContainer.implicitWidth
265+ implicitHeight: surfaceContainer.implicitHeight
266+ }
290 },
267 },
291 State {
268 State {
292 name: "screenshot"
269 name: "screenshot"
@@ -424,5 +401,4 @@ FocusScope {
424 }
401 }
425 ]
402 ]
426 }
403 }
427−
428}
404}
qml/Stage/DecoratedWindow.qmlnew file+293
@@ -0,0 +1,293 @@
1+/*
2+ * Copyright (C) 2014-2016 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.4
18+import Ubuntu.Components 1.3
19+import Unity.Application 0.1
20+import "Spread/MathUtils.js" as MathUtils
21+import Unity.ApplicationMenu 0.1
22+import Unity.Indicators 0.1 as Indicators
23+import "../Components/PanelState"
24+
25+FocusScope {
26+ id: root
27+
28+ // The DecoratedWindow takes requestedWidth/requestedHeight and asks its surface to be resized to that
29+ // (minus the window decoration size in case hasDecoration and showDecoration are true)
30+ // The surface might not be able to resize to the requested values. It will return its actual size
31+ // in implicitWidth/implicitHeight.
32+
33+ property alias application: applicationWindow.application
34+ property alias surface: applicationWindow.surface
35+ readonly property alias focusedSurface: applicationWindow.focusedSurface
36+ property alias active: decoration.active
37+ readonly property alias title: applicationWindow.title
38+ property alias maximizeButtonShown: decoration.maximizeButtonShown
39+ property alias interactive: applicationWindow.interactive
40+ readonly property alias orientationChangesEnabled: applicationWindow.orientationChangesEnabled
41+
42+ // Changing this will actually add/remove a decoration, meaning, requestedHeight will take the decoration into account.
43+ property bool hasDecoration: true
44+ // This will temporarily show/hide the decoration without actually changing the surface's dimensions
45+ property real showDecoration: 1
46+ property bool animateDecoration: false
47+ property bool showHighlight: false
48+ property int highlightSize: units.gu(1)
49+ property real shadowOpacity: 0
50+ property bool darkening: false
51+
52+ property real requestedWidth
53+ property real requestedHeight
54+ property real scaleToPreviewProgress: 0
55+ property int scaleToPreviewSize: units.gu(30)
56+
57+ property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
58+ readonly property real decorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
59+ readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
60+
61+ readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
62+ readonly property int minimumHeight: decorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
63+ readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
64+ readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
65+ + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
66+ readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
67+ readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
68+
69+ property alias overlayShown: decoration.overlayShown
70+ property alias stageWidth: moveHandler.stageWidth
71+ property alias stageHeight: moveHandler.stageHeight
72+ readonly property alias dragging: moveHandler.dragging
73+
74+ readonly property Item clientAreaItem: applicationWindow
75+
76+ signal closeClicked()
77+ signal maximizeClicked()
78+ signal maximizeHorizontallyClicked()
79+ signal maximizeVerticallyClicked()
80+ signal minimizeClicked()
81+ signal decorationPressed()
82+ signal decorationReleased()
83+
84+ QtObject {
85+ id: d
86+ property int requestedDecorationHeight: root.hasDecoration ? decoration.height : 0
87+ Behavior on requestedDecorationHeight { enabled: root.animateDecoration; UbuntuNumberAnimation { } }
88+
89+ property int visibleDecorationHeight: root.hasDecoration ? root.showDecoration * decoration.height : 0
90+ Behavior on visibleDecorationHeight { enabled: root.animateDecoration; UbuntuNumberAnimation { } }
91+ }
92+
93+ StateGroup {
94+ states: [
95+ State {
96+ name: "normal"; when: root.scaleToPreviewProgress <= 0 && root.application.state === ApplicationInfoInterface.Running
97+ PropertyChanges {
98+ target: root
99+ implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
100+ implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
101+ }
102+ },
103+ State {
104+ name: "normalSuspended"; when: root.scaleToPreviewProgress <= 0 && root.application.state !== ApplicationInfoInterface.Running
105+ PropertyChanges {
106+ target: root
107+ implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
108+ implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
109+ }
110+// PropertyChanges { target: applicationWindow; anchors.topMargin: (root.height - applicationWindow.implicitHeight) / 2 }
111+// PropertyChanges { target: dropShadow; anchors.topMargin: (root.height - applicationWindow.implicitHeight) / 2 }
112+ },
113+ State {
114+ name: "preview"; when: root.scaleToPreviewProgress > 0 && root.application.state === ApplicationInfoInterface.Running
115+ PropertyChanges {
116+ target: root
117+ implicitWidth: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, root.scaleToPreviewSize, root.scaleToPreviewProgress)
118+ implicitHeight: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, root.scaleToPreviewSize, root.scaleToPreviewProgress)
119+ }
120+ PropertyChanges {
121+ target: applicationWindow;
122+ requestedWidth: applicationWindow.oldRequestedWidth
123+ requestedHeight: applicationWindow.oldRequestedHeight
124+ width: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, applicationWindow.minSize, root.scaleToPreviewProgress)
125+ height: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, applicationWindow.minSize, root.scaleToPreviewProgress)
126+ itemScale: root.implicitWidth / width
127+ }
128+ },
129+ State {
130+ name: "previewSuspended"; when: root.scaleToPreviewProgress > 0 && root.application.state !== ApplicationInfoInterface.Running
131+ extend: "preview"
132+ PropertyChanges { target: applicationWindow;
133+ anchors.verticalCenterOffset: applicationWindow.implicitHeight < applicationWindow.height ?
134+ (root.height / applicationWindow.itemScale - applicationWindow.implicitHeight) / 2
135+ : (root.height / applicationWindow.itemScale - applicationWindow.height) / 2
136+ }
137+// PropertyChanges { target: dropShadow; anchors.topMargin: (root.height - root.implicitHeight) / 2 * (1 - root.scaleToPreviewProgress) }
138+ }
139+ ]
140+ }
141+
142+ Rectangle {
143+ id: selectionHighlight
144+ objectName: "selectionHighlight"
145+ anchors.fill: parent
146+ anchors.margins: -root.highlightSize
147+ color: "white"
148+ opacity: showHighlight ? 0.55 : 0
149+ visible: opacity > 0
150+ }
151+
152+ BorderImage {
153+ id: dropShadow
154+ anchors {
155+ left: parent.left; top: parent.top; right: parent.right
156+ margins: active ? -units.gu(2) : -units.gu(1.5)
157+ }
158+ height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
159+ + root.decorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
160+ source: "../graphics/dropshadow2gu.sci"
161+ opacity: root.shadowOpacity
162+ }
163+
164+ ApplicationWindow {
165+ id: applicationWindow
166+ objectName: "appWindow"
167+ anchors.verticalCenter: parent.verticalCenter
168+ anchors.verticalCenterOffset: (root.decorationHeight * Math.min(1, root.showDecoration)) / 2
169+ anchors.left: parent.left
170+ width: implicitWidth
171+ height: implicitHeight
172+ requestedHeight: !counterRotate ? root.requestedHeight - d.requestedDecorationHeight : root.requestedWidth
173+ requestedWidth: !counterRotate ? root.requestedWidth : root.requestedHeight - d.requestedDecorationHeight
174+ property int oldRequestedWidth: requestedWidth
175+ property int oldRequestedHeight: requestedHeight
176+ onRequestedWidthChanged: oldRequestedWidth = requestedWidth
177+ onRequestedHeightChanged: oldRequestedHeight = requestedHeight
178+ focus: true
179+
180+ property real itemScale: 1
181+ property real minSize: Math.min(root.scaleToPreviewSize, Math.min(requestedHeight, Math.min(requestedWidth, Math.min(implicitHeight, implicitWidth))))
182+
183+ transform: [
184+ Rotation {
185+ id: rotationTransform
186+ readonly property int rotationAngle: applicationWindow.application &&
187+ applicationWindow.application.rotatesWindowContents
188+ ? ((360 - applicationWindow.surfaceOrientationAngle) % 360) : 0
189+ origin.x: {
190+ if (rotationAngle == 90) return applicationWindow.height / 2;
191+ else if (rotationAngle == 270) return applicationWindow.width / 2;
192+ else if (rotationAngle == 180) return applicationWindow.width / 2;
193+ else return 0;
194+ }
195+ origin.y: {
196+ if (rotationAngle == 90) return applicationWindow.height / 2;
197+ else if (rotationAngle == 270) return applicationWindow.width / 2;
198+ else if (rotationAngle == 180) return applicationWindow.height / 2;
199+ else return 0;
200+ }
201+ angle: rotationAngle
202+ },
203+ Scale {
204+ origin.y: (applicationWindow.implicitHeight < applicationWindow.height ? applicationWindow.implicitHeight : applicationWindow.height) / 2
205+ xScale: applicationWindow.itemScale
206+ yScale: applicationWindow.itemScale
207+ }
208+ ]
209+ }
210+
211+ MouseArea {
212+ anchors { left: parent.left; top: parent.top; right: parent.right }
213+ height: units.gu(3)
214+
215+ opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
216+
217+ Behavior on opacity { UbuntuNumberAnimation { } }
218+
219+ drag.target: Item {}
220+ drag.filterChildren: true
221+ drag.threshold: 0
222+
223+ onPressed: root.decorationPressed();
224+ onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
225+ onPositionChanged: moveHandler.handlePositionChanged(mouse)
226+ onReleased: {
227+ root.decorationReleased();
228+ moveHandler.handleReleased();
229+ }
230+
231+ WindowDecoration {
232+ id: decoration
233+ target: root.parent || null
234+ objectName: "appWindowDecoration"
235+ anchors.fill: parent
236+ title: applicationWindow.title
237+
238+ onCloseClicked: root.closeClicked();
239+ onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
240+ onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
241+ onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
242+ onMinimizeClicked: root.minimizeClicked();
243+
244+ enableMenus: {
245+ return active &&
246+ surface &&
247+ (PanelState.focusedPersistentSurfaceId !== surface.persistentId ||
248+ (PanelState.focusedPersistentSurfaceId === surface.persistentId && !PanelState.focusedSurfaceMaximized))
249+ }
250+ menu: sharedAppModel.model
251+
252+ Indicators.SharedUnityMenuModel {
253+ id: sharedAppModel
254+ property var menus: surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : []
255+ property var menuService: menus.length > 0 ? menus[0] : undefined
256+
257+ onMenuServiceChanged: console.log("MENU!", menuService.service, menuService.menuPath, menuService.actionPath)
258+
259+ busName: menuService ? menuService.service : ""
260+ menuObjectPath: menuService && menuService.menuPath ? menuService.menuPath : ""
261+ actions: menuService && menuService.actionPath ? { "unity": menuService.actionPath } : {}
262+ }
263+
264+ Connections {
265+ target: ApplicationMenuRegistry
266+ onSurfaceMenuRegistered: {
267+ if (surface && surfaceId === surface.persistentId) {
268+ sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
269+ }
270+ }
271+ onSurfaceMenuUnregistered: {
272+ if (surface && surfaceId === surface.persistentId) {
273+ sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
274+ }
275+ }
276+ }
277+ }
278+ }
279+
280+ MoveHandler {
281+ id: moveHandler
282+ objectName: "moveHandler"
283+ target: root.parent
284+ buttonsWidth: decoration.buttonsWidth
285+ }
286+
287+ Rectangle {
288+ anchors.fill: parent
289+ color: "black"
290+ opacity: root.darkening && !root.showHighlight ? 0.05 : 0
291+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
292+ }
293+}
qml/Stages/DesktopSpread.qml → qml/Stage/DesktopSpread.qmlrenamed

The content is the same.

qml/Stages/DesktopSpreadDelegate.qml → qml/Stage/DesktopSpreadDelegate.qmlrenamed

The content is the same.

qml/Stages/FakeMaximizeDelegate.qml → qml/Stage/FakeMaximizeDelegate.qmlrenamed

The content is the same.

qml/Stages/MainViewStyle.qml → qml/Stage/MainViewStyle.qmlrenamed

The content is the same.

qml/Stages/MoveHandler.qml → qml/Stage/MoveHandler.qmlrenamed+2−2
@@ -112,8 +112,8 @@ QtObject {
112 // Use integer coordinate values to ensure that target is left in a pixel-aligned
112 // Use integer coordinate values to ensure that target is left in a pixel-aligned
113 // position. Mouse movement could have subpixel precision, yielding a fractional
113 // position. Mouse movement could have subpixel precision, yielding a fractional
114 // mouse position.
114 // mouse position.
115− target.requestedX = Math.round(pos.x - priv.distanceX);
115+ target.windowedX = Math.round(pos.x - priv.distanceX);
116− target.requestedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
116+ target.windowedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
117
117
118 if (sensingPoints) { // edge/corner detection when dragging via the touch overlay
118 if (sensingPoints) { // edge/corner detection when dragging via the touch overlay
119 if (sensingPoints.topLeft.x < priv.triggerArea && sensingPoints.topLeft.y < PanelState.panelHeight + priv.triggerArea
119 if (sensingPoints.topLeft.x < priv.triggerArea && sensingPoints.topLeft.y < PanelState.panelHeight + priv.triggerArea
qml/Stages/OrientationChangeAnimation.qml → qml/Stage/OrientationChangeAnimation.qmlrenamed

The content is the same.

qml/Stages/PhoneStage.qml → qml/Stage/PhoneStage.qmlrenamed

The content is the same.

qml/Stages/PromptSurfaceAnimations.qml → qml/Stage/PromptSurfaceAnimations.qmlrenamed+2−3
@@ -43,7 +43,7 @@ StateGroup {
43 SequentialAnimation {
43 SequentialAnimation {
44 // clip so we don't go out of parent's bounds during spread
44 // clip so we don't go out of parent's bounds during spread
45 PropertyAction { target: root.container.parent; property: "clip"; value: true }
45 PropertyAction { target: root.container.parent; property: "clip"; value: true }
46− UbuntuNumberAnimation { target: root.surfaceItem; property: "y"; to: root.container.height
46+ UbuntuNumberAnimation { target: root.surfaceItem; property: "anchors.topMargin"; to: root.container.height
47 duration: UbuntuAnimation.BriskDuration }
47 duration: UbuntuAnimation.BriskDuration }
48 PropertyAction { target: root.surfaceItem; property: "visible"; value: false }
48 PropertyAction { target: root.surfaceItem; property: "visible"; value: false }
49 PropertyAction { target: container.parent; property: "clip"; value: false }
49 PropertyAction { target: container.parent; property: "clip"; value: false }
@@ -61,11 +61,10 @@ StateGroup {
61 // clip so we don't go out of parent's bounds during spread
61 // clip so we don't go out of parent's bounds during spread
62 PropertyAction { target: root.container.parent; property: "clip"; value: true }
62 PropertyAction { target: root.container.parent; property: "clip"; value: true }
63 ScriptAction { script: {
63 ScriptAction { script: {
64− root.surfaceItem.y = root.container.height;
65 root.surfaceItem.visible = true;
64 root.surfaceItem.visible = true;
66 } }
65 } }
67 UbuntuNumberAnimation {
66 UbuntuNumberAnimation {
68− target: root.surfaceItem; property: "y"; to: 0
67+ target: root.surfaceItem; property: "anchors.topMargin"; from: root.container.height; to: 0
69 duration: UbuntuAnimation.BriskDuration
68 duration: UbuntuAnimation.BriskDuration
70 }
69 }
71 PropertyAction { target: container.parent; property: "clip"; value: false }
70 PropertyAction { target: container.parent; property: "clip"; value: false }
qml/Stages/ResizeGrip.qml → qml/Stage/ResizeGrip.qmlrenamed

The content is the same.

qml/Stages/SideStage.qml → qml/Stage/SideStage.qmlrenamed

The content is the same.

qml/Stages/Splash.qml → qml/Stage/Splash.qmlrenamed

The content is the same.

qml/Stage/Spread/BezierCurve.qmlnew file+45
@@ -0,0 +1,45 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import QtQuick.Window 2.2
20+import 'cubic-bezier.js' as Bezier
21+import 'KeySpline.js' as KeySpline
22+
23+Item {
24+ id: root
25+
26+ property var controlPoint1: {'x':0, 'y':0}
27+ property var controlPoint2: {'x':0, 'y':0}
28+ property var controlPoint3: {'x':0.58, 'y':1}
29+ property var controlPoint4: {'x':1, 'y':1}
30+
31+ function getValues(t) {
32+ if (t<0) t=0
33+ else if (t>1)t=1
34+
35+ return Bezier.getBezier(t, controlPoint1, controlPoint2, controlPoint3, controlPoint4)
36+ }
37+
38+ function getYFromX(x) {
39+ var spline = new KeySpline.keySpline(controlPoint2.x, controlPoint2.y, controlPoint3.x, controlPoint3.y)
40+ if (x<0) x=0
41+ else if (x>1)x=1
42+
43+ return spline.get(x)
44+ }
45+}
qml/Stage/Spread/KeySpline.jsnew file+66
@@ -0,0 +1,66 @@
1+/** MIT License
2+ *
3+ * KeySpline - use bezier curve for transition easing function
4+ * Copyright (c) 2012 Gaetan Renaudeau <renaudeau.gaetan@gmail.com>
5+ *
6+ * Permission is hereby granted, free of charge, to any person obtaining a
7+ * copy of this software and associated documentation files (the "Software"),
8+ * to deal in the Software without restriction, including without limitation
9+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10+ * and/or sell copies of the Software, and to permit persons to whom the
11+ * Software is furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22+ * DEALINGS IN THE SOFTWARE.
23+ */
24+/**
25+* KeySpline - use bezier curve for transition easing function
26+* is inspired from Firefox's nsSMILKeySpline.cpp
27+* Usage:
28+* var spline = new KeySpline(0.25, 0.1, 0.25, 1.0)
29+* spline.get(x) => returns the easing value | x must be in [0, 1] range
30+*/
31+
32+.pragma library
33+
34+function keySpline (mX1, mY1, mX2, mY2) {
35+
36+ this.get = function(aX) {
37+ if (mX1 == mY1 && mX2 == mY2) return aX; // linear
38+ return CalcBezier(GetTForX(aX), mY1, mY2);
39+ }
40+
41+ function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
42+ function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
43+ function C(aA1) { return 3.0 * aA1; }
44+
45+ // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
46+ function CalcBezier(aT, aA1, aA2) {
47+ return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT;
48+ }
49+
50+ // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
51+ function GetSlope(aT, aA1, aA2) {
52+ return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
53+ }
54+
55+ function GetTForX(aX) {
56+ // Newton raphson iteration
57+ var aGuessT = aX;
58+ for (var i = 0; i < 4; ++i) {
59+ var currentSlope = GetSlope(aGuessT, mX1, mX2);
60+ if (currentSlope == 0.0) return aGuessT;
61+ var currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
62+ aGuessT -= currentX / currentSlope;
63+ }
64+ return aGuessT;
65+ }
66+}
qml/Stage/Spread/MathUtils.jsnew file+95
@@ -0,0 +1,95 @@
1+/*
2+ * Copyright (C) 2016 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+.pragma library
18+
19+/**
20+ * From processing.js: https://raw.githubusercontent.com/processing-js/processing-js/v1.4.8/processing.js
21+ *
22+ * Re-map a number from one range to another. In the example above, the number
23+ * '25' is converted from a value in the range 0..100 into a value that
24+ * ranges from the left edge (0) to the right edge (width) of the screen.
25+ * Numbers outside the range are not clamped to 0 and 1, because out-of-range
26+ * values are often intentional and useful.
27+ *
28+ * @param {Number} value The incoming value to be converted
29+ * @param {Number} istart Lower bound of the value's current range
30+ * @param {Number} istop Upper bound of the value's current range
31+ * @param {Number} ostart Lower bound of the value's target range
32+ * @param {Number} ostop Upper bound of the value's target range
33+ *
34+ * @returns {Number}
35+ */
36+function map(value, istart, istop, ostart, ostop) {
37+ return ostart + (ostop - ostart) * ((value - istart) / (istop - istart))
38+}
39+
40+/**
41+ * Return a value which is always between `min` and `max`
42+ *
43+ * @param {Number} value The current value
44+ * @param {Number} min The minimum value
45+ * @param {Number} max The maximum value
46+ *
47+ * @returns {Number}
48+ */
49+function clamp(value, min, max) {
50+ if (value < min) return min
51+ if (value > max) return max
52+ return value
53+}
54+
55+// calculates the distance from the middle of one rect to middle of other rect
56+function rectDistance(rect1, rect2) {
57+ return pointDistance(Qt.point(rect1.x + rect1.width / 2, rect1.y + rect1.height / 2),
58+ Qt.point(rect2.x + rect2.width / 2, rect2.y + rect2.height / 2))
59+}
60+
61+// calculates the distance between two points
62+function pointDistance(point1, point2) {
63+ return Math.sqrt(Math.pow(point1.x - point2.x, 2) +
64+ Math.pow(point1.y - point2.y, 2)
65+ )
66+}
67+
68+// from http://stackoverflow.com/questions/14616829/java-method-to-find-the-rectangle-that-is-the-intersection-of-two-rectangles-usi
69+function intersectionRect(r1, r2) {
70+ var xmin = Math.max(r1.x, r2.x);
71+ var xmax1 = r1.x + r1.width;
72+ var xmax2 = r2.x + r2.width;
73+ var xmax = Math.min(xmax1, xmax2);
74+ var out = {x:0, y:0, width:0, height:0}
75+ if (xmax > xmin) {
76+ var ymin = Math.max(r1.y, r2.y);
77+ var ymax1 = r1.y + r1.height;
78+ var ymax2 = r2.y + r2.height;
79+ var ymax = Math.min(ymax1, ymax2);
80+ if (ymax > ymin) {
81+ out.x = xmin;
82+ out.y = ymin;
83+ out.width = xmax - xmin;
84+ out.height = ymax - ymin;
85+ }
86+ }
87+ return out;
88+}
89+
90+function easeOutCubic(t) { return (--t)*t*t+1 }
91+
92+function linearAnimation(startProgress, endProgress, startValue, endValue, progress) {
93+ // progress : progressDiff = value : valueDiff => value = progress * valueDiff / progressDiff
94+ return (progress - startProgress) * (endValue - startValue) / (endProgress - startProgress) + startValue;
95+}
qml/Stage/Spread/OpacityMask.qmlnew file+82
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+
19+Item {
20+ id: root
21+ anchors.fill: sourceItem
22+ anchors.margins: -units.gu(2)
23+ visible: sourceItem !== null
24+
25+ property var sourceItem: null
26+ property int maskX: 0
27+ property int maskY: 0
28+ property int maskWidth: 0
29+ property int maskHeight: 0
30+
31+ property real opacityValue: 1
32+
33+ Item {
34+ id: opacityMask
35+ anchors.fill: parent
36+
37+ Rectangle {
38+ id: clipRect
39+ color: "black"
40+ x: root.maskX - root.anchors.margins
41+ y: root.maskY - root.anchors.margins
42+ width: root.maskWidth
43+ height: root.maskHeight
44+ opacity: 1 - root.opacityValue
45+ }
46+ }
47+
48+ ShaderEffect {
49+ id: opacityEffect
50+ anchors.fill: parent
51+
52+ property variant source: ShaderEffectSource {
53+ id: shaderEffectSource
54+ sourceItem: root.sourceItem
55+ sourceRect: root.sourceItem ? Qt.rect(sourceItem.x + root.anchors.margins,
56+ sourceItem.y + root.anchors.margins,
57+ sourceItem.width - root.anchors.margins * 2,
58+ sourceItem.height - root.anchors.margins * 2)
59+ : Qt.rect(0,0,0,0)
60+ hideSource: true
61+ }
62+
63+ property var mask: ShaderEffectSource {
64+ sourceItem: opacityMask
65+ hideSource: true
66+ }
67+
68+ fragmentShader: "
69+ varying highp vec2 qt_TexCoord0;
70+ uniform sampler2D source;
71+ uniform sampler2D mask;
72+ void main(void)
73+ {
74+ highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
75+ highp vec4 maskColor = texture2D(mask, qt_TexCoord0);
76+
77+ sourceColor *= 1.0 - maskColor.a;
78+
79+ gl_FragColor = sourceColor;
80+ }"
81+ }
82+}
qml/Stage/Spread/Spread.qmlnew file+162
@@ -0,0 +1,162 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import "MathUtils.js" as MathUtils
20+
21+Item {
22+ id: root
23+
24+ // Information about the environment
25+ property int highlightedIndex: -1
26+ property var model: null
27+ property int leftMargin: 0
28+ property var spreadFlickable
29+
30+ // some config options
31+ property real contentMargin: 0.16 * root.height
32+ property real contentTopMargin: contentMargin
33+ property real contentBottomMargin: 0.35 * contentMargin
34+ property real windowTitleTopMargin: 3/4 * (contentTopMargin - windowTitle.height)
35+ property int stackItemCount: 3
36+ property real leftRotationAngle: 22
37+ property real rightRotationAngle: 32
38+ property real leftStackScale: .82
39+ property real rightStackScale: 1
40+ property real rightEdgeBreakPoint: Math.min(units.gu(40) / root.width, .35)
41+
42+ signal leaveSpread()
43+
44+ // Calculated stuff
45+ readonly property int totalItemCount: model.count
46+ readonly property real leftStackXPos: 0.03 * root.width + leftMargin
47+ readonly property real rightStackXPos: root.width - 1.5 * leftStackXPos + leftMargin
48+
49+ readonly property real stackHeight: spreadItemHeight - appInfoHeight
50+ readonly property real stackWidth: Math.min(leftStackXPos/3, units.gu(1.5))
51+
52+ readonly property real spreadWidth: rightStackXPos - leftStackXPos
53+ readonly property real spreadHeight: root.height
54+ readonly property real spreadItemHeight: spreadHeight - contentTopMargin - contentBottomMargin
55+ readonly property real spreadItemWidth: stackHeight
56+
57+ readonly property real dynamicLeftRotationAngle: leftRotationAngle * rotationAngleFactor
58+ readonly property real dynamicRightRotationAngle: rightRotationAngle * rotationAngleFactor
59+
60+ readonly property real appInfoHeight: {
61+ var screenHeightReferencePoint = 40 // ref screen height in gu
62+ var valueAtReferencePoint = 0.17 // of screen height at the reference point
63+ var appInfoHeightValueChange = -0.0014 // units / gu
64+ var minAppInfoHeight = 0.08
65+ var maxAppInfoHeight = 0.2
66+ var screenHeightInGU = root.height / units.gu(1) // screenHeight in gu
67+
68+ return MathUtils.clamp(valueAtReferencePoint + appInfoHeightValueChange * (screenHeightInGU - screenHeightReferencePoint), minAppInfoHeight, maxAppInfoHeight) * root.height
69+ }
70+
71+ property real rotationAngleFactor: {
72+ var spreadHeightReferencePoint = 28 // reference spread height in gu
73+ var valueAtReferencePoint = 1.3
74+ var rotationAngleValueChange = -0.008 // units / gu
75+ var minRotationAngleFactor = 0.6
76+ var maxRotationAngleFactor = 1.5
77+ var spreadHeightInGU = spreadHeight / units.gu(1)
78+
79+ return MathUtils.clamp(valueAtReferencePoint + rotationAngleValueChange * (spreadHeightInGU - spreadHeightReferencePoint), minRotationAngleFactor, maxRotationAngleFactor)
80+ }
81+ readonly property real itemOverlap: {
82+ var spreadAspectRatioReferencePoint = 1.0 // ref screen height in gu
83+ var valueAtReferencePoint = 0.74 // of screen height at the reference point
84+ var itemOverlapValueChange = -0.068
85+ var minOverlap = 0.55
86+ var maxOverlap = 0.82
87+ var spreadAspectRatio = spreadWidth / stackHeight // spread stack aspect ratio (app info not included)
88+
89+ return MathUtils.clamp(valueAtReferencePoint + itemOverlapValueChange * (spreadAspectRatio - spreadAspectRatioReferencePoint), minOverlap, maxOverlap)
90+ }
91+
92+ readonly property real visibleItemCount: (spreadWidth / spreadItemWidth) / (1 - itemOverlap)
93+
94+ readonly property real spreadTotalWidth: totalItemCount * spreadWidth / visibleItemCount
95+
96+ readonly property real centeringOffset: Math.max(spreadWidth - spreadTotalWidth ,0) / (2 * spreadWidth)
97+
98+
99+ readonly property var curve: BezierCurve {
100+ controlPoint2: {'x': 0.19, 'y': 0.00}
101+ controlPoint3: {'x': 0.91, 'y': 1.00}
102+ }
103+
104+ Label {
105+ id: windowTitle
106+
107+ width: Math.min(implicitWidth, 0.5*root.width)
108+ elide: Qt.ElideMiddle
109+ anchors.horizontalCenter: parent.horizontalCenter
110+ y: windowTitleTopMargin
111+ readonly property var highlightedSurface: root.model ? root.model.surfaceAt(root.highlightedIndex) : null
112+ readonly property var highlightedApp: root.model ? root.model.applicationAt(root.highlightedIndex) : null
113+ text: root.highlightedIndex >= 0 && highlightedSurface && highlightedSurface.name != "" ? highlightedSurface.name :
114+ highlightedApp ? highlightedApp.name : ""
115+ fontSize: root.height < units.gu(85) ? 'medium' : 'large'
116+ color: "white"
117+ opacity: root.highlightedIndex >= 0 ? 1 : 0
118+ Behavior on opacity { UbuntuNumberAnimation { } }
119+ }
120+
121+ Keys.onPressed: {
122+ switch (event.key) {
123+ case Qt.Key_Left:
124+ case Qt.Key_Backtab:
125+ selectPrevious(event.isAutoRepeat)
126+ event.accepted = true;
127+ break;
128+ case Qt.Key_Right:
129+ case Qt.Key_Tab:
130+ selectNext(event.isAutoRepeat)
131+ event.accepted = true;
132+ break;
133+ case Qt.Key_Escape:
134+ highlightedIndex = -1
135+ // Falling through intentionally
136+ case Qt.Key_Enter:
137+ case Qt.Key_Return:
138+ case Qt.Key_Space:
139+ root.leaveSpread();
140+ event.accepted = true;
141+ }
142+ }
143+
144+
145+ function selectNext(isAutoRepeat) {
146+ if (isAutoRepeat && highlightedIndex >= totalItemCount -1) {
147+ return; // AutoRepeat is not allowed to wrap around
148+ }
149+
150+ highlightedIndex = (highlightedIndex + 1) % totalItemCount;
151+ spreadFlickable.snap(highlightedIndex)
152+ }
153+
154+ function selectPrevious(isAutoRepeat) {
155+ if (isAutoRepeat && highlightedIndex == 0) {
156+ return; // AutoRepeat is not allowed to wrap around
157+ }
158+
159+ highlightedIndex = highlightedIndex - 1 >= 0 ? highlightedIndex - 1 : totalItemCount - 1;
160+ spreadFlickable.snap(highlightedIndex)
161+ }
162+}
qml/Stage/Spread/SpreadDelegateInputArea.qmlnew file+183
@@ -0,0 +1,183 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import Ubuntu.Gestures 0.1
20+import "../../Components"
21+
22+Item {
23+ id: root
24+
25+ property bool closeable: true
26+ readonly property real minSpeedToClose: units.gu(40)
27+ property bool zeroVelocityCounts: false
28+
29+ readonly property alias distance: d.distance
30+
31+ signal clicked()
32+ signal close()
33+
34+ QtObject {
35+ id: d
36+ property real distance: 0
37+ property bool moving: false
38+ property var dragEvents: []
39+ property real dragVelocity: 0
40+ property int threshold: units.gu(2)
41+
42+ // Can be replaced with a fake implementation during tests
43+ // property var __getCurrentTimeMs: function () { return new Date().getTime() }
44+ property var __dateTime: new function() {
45+ this.getCurrentTimeMs = function() {return new Date().getTime()}
46+ }
47+
48+ function pushDragEvent(event) {
49+ var currentTime = __dateTime.getCurrentTimeMs()
50+ dragEvents.push([currentTime, event.x, event.y, getEventSpeed(currentTime, event)])
51+ cullOldDragEvents(currentTime)
52+ updateSpeed()
53+ }
54+
55+ function cullOldDragEvents(currentTime) {
56+ // cull events older than 50 ms but always keep the latest 2 events
57+ for (var numberOfCulledEvents = 0; numberOfCulledEvents < dragEvents.length-2; numberOfCulledEvents++) {
58+ // dragEvents[numberOfCulledEvents][0] is the dragTime
59+ if (currentTime - dragEvents[numberOfCulledEvents][0] <= 50) break
60+ }
61+
62+ dragEvents.splice(0, numberOfCulledEvents)
63+ }
64+
65+ function updateSpeed() {
66+ var totalSpeed = 0
67+ for (var i = 0; i < dragEvents.length; i++) {
68+ totalSpeed += dragEvents[i][3]
69+ }
70+
71+ if (zeroVelocityCounts || Math.abs(totalSpeed) > 0.001) {
72+ dragVelocity = totalSpeed / dragEvents.length * 1000
73+ }
74+ }
75+
76+ function getEventSpeed(currentTime, event) {
77+ if (dragEvents.length != 0) {
78+ var lastDrag = dragEvents[dragEvents.length-1]
79+ var duration = Math.max(1, currentTime - lastDrag[0])
80+ return (event.y - lastDrag[2]) / duration
81+ } else {
82+ return 0
83+ }
84+ }
85+ }
86+
87+ // Event eater
88+ MouseArea {
89+ anchors.fill: parent
90+ onClicked: root.clicked()
91+ onWheel: wheel.accepted = true
92+ }
93+
94+ MultiPointTouchArea {
95+ anchors.fill: parent
96+ mouseEnabled: false
97+ maximumTouchPoints: 1
98+ property int offset: 0
99+
100+ touchPoints: [
101+ TouchPoint {
102+ id: tp
103+ }
104+ ]
105+
106+ onCanceled: {
107+ d.moving = false
108+ animation.animate("center");
109+ }
110+
111+ onTouchUpdated: {
112+ if (!d.moving) {
113+ if (Math.abs(tp.startY - tp.y) > d.threshold) {
114+ d.moving = true;
115+ d.dragEvents = []
116+ offset = tp.y - tp.startY;
117+ } else {
118+ return;
119+ }
120+ }
121+
122+ d.distance = tp.y - tp.startY - offset
123+ d.pushDragEvent(tp);
124+ }
125+
126+ onReleased: {
127+ if (!d.moving) {
128+ root.clicked()
129+ }
130+
131+ if (!root.closeable) {
132+ animation.animate("center")
133+ return;
134+ }
135+
136+ var touchPoint = touchPoints[0];
137+
138+ if ((d.dragVelocity < -root.minSpeedToClose && d.distance < -units.gu(8)) || d.distance < -root.height / 2) {
139+ animation.animate("up")
140+ } else if ((d.dragVelocity > root.minSpeedToClose && d.distance > units.gu(8)) || d.distance > root.height / 2) {
141+ animation.animate("down")
142+ } else {
143+ animation.animate("center")
144+ }
145+ }
146+ }
147+
148+ UbuntuNumberAnimation {
149+ id: animation
150+ objectName: "closeAnimation"
151+ target: d
152+ property: "distance"
153+ property bool requestClose: false
154+
155+ function animate(direction) {
156+ animation.from = dragArea.distance;
157+ switch (direction) {
158+ case "up":
159+ animation.to = -root.height * 1.5;
160+ requestClose = true;
161+ break;
162+ case "down":
163+ animation.to = root.height * 1.5;
164+ requestClose = true;
165+ break;
166+ default:
167+ animation.to = 0
168+ }
169+ animation.start();
170+ }
171+
172+ onRunningChanged: {
173+ if (!running) {
174+ d.moving = false;
175+ if (requestClose) {
176+ root.close();
177+ } else {
178+ d.distance = 0;
179+ }
180+ }
181+ }
182+ }
183+}
qml/Stage/Spread/SpreadMaths.qmlnew file+78
@@ -0,0 +1,78 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import Utils 0.1
20+import "MathUtils.js" as MathUtils
21+
22+Item {
23+ id: root
24+ anchors { left: parent.left; top: parent.top; margins: units.gu(1) }
25+
26+ // Information about the environment
27+ property Item flickable: null
28+ property Spread spread: null
29+ property int itemIndex: 0
30+
31+ // Internal
32+ property real spreadPosition: itemIndex/spread.visibleItemCount - flickable.contentX/spread.spreadWidth // 0 -> left stack, 1 -> right stack
33+ property real leftStackingProgress: MathUtils.clamp(MathUtils.map(spreadPosition, 0, -spread.stackItemCount/spread.visibleItemCount , 0, 1), 0, 1)
34+ property real rightStackingProgress: MathUtils.clamp(MathUtils.map(spreadPosition, 1, 1 + spread.stackItemCount/spread.visibleItemCount , 0, 1), 0, 1)
35+ property real stackingX: (MathUtils.easeOutCubic(rightStackingProgress) - MathUtils.easeOutCubic(leftStackingProgress)) * spread.stackWidth
36+
37+
38+ QtObject {
39+ id: d
40+ property real spreadScale: MathUtils.clamp(
41+ MathUtils.map(spreadPosition, 0, 1, spread.leftStackScale, spread.rightStackScale),
42+ spread.leftStackScale, spread.rightStackScale)
43+
44+ property real selectedScale: (spread.highlightedIndex == itemIndex ? 1.01 : 1)
45+ Behavior on selectedScale { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
46+
47+ }
48+
49+ // Output
50+ readonly property int targetX: spread.leftStackXPos +
51+ spread.spreadWidth * spread.curve.getYFromX(spreadPosition + spread.centeringOffset) +
52+ stackingX
53+
54+ readonly property int targetY: spread.contentTopMargin
55+
56+ readonly property real targetAngle: MathUtils.clamp(
57+ MathUtils.map(targetX, spread.leftStackXPos, spread.rightStackXPos, spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle),
58+ Math.min(spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle), Math.max(spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle))
59+
60+
61+ readonly property real targetScale: d.spreadScale * d.selectedScale
62+
63+ readonly property real shadowOpacity: 0.2 * (1 - rightStackingProgress) * (1 - leftStackingProgress)
64+
65+
66+ readonly property real closeIconOffset: (targetScale - 1) * (-spread.stackHeight / 2)
67+
68+ readonly property real tileInfoOpacity: Math.min(MathUtils.clamp(MathUtils.map(leftStackingProgress, 0 , 1/(spread.stackItemCount*3), 1, 0), 0 , 1),
69+ MathUtils.clamp(MathUtils.map(spreadPosition, 0.9 , 1, 1, 0), 0 , 1)) /** MathUtils.map(curvedSwitcherProgress, 0.7, 0.9, 0, 1)*/
70+
71+ readonly property bool itemVisible: {
72+ var leftStackHidden = spreadPosition < -(spread.stackItemCount + 1)/spread.visibleItemCount
73+ // don't hide the rightmost
74+ var rightStackHidden = (spreadPosition > 1 + (spread.stackItemCount)/spread.visibleItemCount) && itemIndex !== spread.totalItemCount - 1
75+ return !leftStackHidden && !rightStackHidden
76+ }
77+
78+}
qml/Stage/Spread/StagedRightEdgeMaths.qmlnew file+174
@@ -0,0 +1,174 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import Unity.Application 0.1
20+import "MathUtils.js" as MathUtils
21+
22+QtObject {
23+ id: root
24+
25+ // Input
26+ property int itemIndex: 0
27+ property real progress: 0
28+ property int sceneWidth: 0
29+ property int sideStageWidth: 0
30+ property int sceneHeight: 0
31+ property int targetX: 0
32+ property int startY: 0
33+ property int targetY: 0
34+ property real startAngle: 30
35+ property real targetAngle: 0
36+ property int targetHeight: 0
37+ property real startScale: 1.3
38+ property real targetScale: 0
39+ property real breakPoint: units.gu(15) / sceneWidth
40+
41+ property bool isMainStageApp: false
42+ property bool isSideStageApp: false
43+ property bool sideStageOpen: false
44+ property int nextInStack: 0
45+ property int shuffledZ: 0
46+
47+
48+ // Config
49+ property int tileDistance: units.gu(10)
50+
51+ // Output
52+
53+ readonly property real scaleToPreviewProgress: {
54+ return progress < breakPoint ? 0 : MathUtils.clamp(MathUtils.linearAnimation(breakPoint, 1, 0, 1, progress), 0, 1)
55+ }
56+ readonly property int animatedWidth: {
57+ return progress < breakPoint ? root.sceneHeight : MathUtils.linearAnimation(breakPoint, 1, root.sceneWidth, targetHeight, progress)
58+ }
59+
60+ readonly property int animatedHeight: {
61+ return progress < breakPoint ? root.sceneHeight : MathUtils.linearAnimation(breakPoint, 1, root.sceneHeight, targetHeight, progress)
62+ }
63+
64+
65+ readonly property int animatedX: {
66+ var nextStage = appRepeater.itemAt(nextInStack) ? appRepeater.itemAt(nextInStack).stage : ApplicationInfoInterface.MainStage;
67+
68+ var startX = 0;
69+ if (isMainStageApp) {
70+ if (progress < breakPoint) {
71+ if (nextStage == ApplicationInfoInterface.MainStage) {
72+ return MathUtils.linearAnimation(0, breakPoint, 0, -units.gu(4), progress);
73+ } else {
74+ return 0;
75+ }
76+ } else {
77+ if (nextStage == ApplicationInfoInterface.MainStage) {
78+ return MathUtils.linearAnimation(breakPoint, 1, -units.gu(4), targetX, progress);
79+ } else {
80+ return MathUtils.linearAnimation(breakPoint, 1, 0, targetX, progress);
81+ }
82+ }
83+ } else if (isSideStageApp) {
84+ startX = sceneWidth - sideStageWidth;
85+ } else if (itemIndex == nextInStack && itemIndex <= 2 && priv.sideStageDelegate && nextStage == ApplicationInfoInterface.MainStage) {
86+ startX = sceneWidth - sideStageWidth;
87+ } else {
88+ var stageCount = (priv.mainStageDelegate ? 1 : 0) + (priv.sideStageDelegate ? 1 : 0)
89+ startX = sceneWidth + Math.max(0, itemIndex - stageCount - 1) * tileDistance;
90+ }
91+
92+ if (itemIndex == nextInStack) {
93+ if (progress < breakPoint) {
94+ return MathUtils.linearAnimation(0, breakPoint, startX, startX * (1 - breakPoint), progress)
95+ }
96+ return MathUtils.linearAnimation(breakPoint, 1, startX * (1 - breakPoint), targetX, progress)
97+ }
98+
99+ if (progress < breakPoint) {
100+ return startX;
101+ }
102+
103+ return MathUtils.linearAnimation(breakPoint, 1, startX, targetX, progress)
104+
105+ }
106+
107+ readonly property int animatedY: progress < breakPoint ? startY : MathUtils.linearAnimation(breakPoint, 1, startY, targetY, progress)
108+
109+ readonly property int animatedZ: {
110+ if (progress < breakPoint + (1 - breakPoint) / 2) {
111+ return shuffledZ
112+ }
113+ return itemIndex;
114+ }
115+
116+ readonly property real animatedAngle: {
117+ var nextStage = appRepeater.itemAt(nextInStack) ? appRepeater.itemAt(nextInStack).stage : ApplicationInfoInterface.MainStage;
118+
119+ var startAngle = 0;
120+ if (isMainStageApp) {
121+ startAngle = 0;
122+ } else if (isSideStageApp) {
123+ startAngle = 0;
124+ } else {
125+ if (stage == ApplicationInfoInterface.SideStage && itemIndex == nextInStack && !sideStageOpen) {
126+ startAngle = 0;
127+ } else {
128+ startAngle = root.startAngle;
129+ }
130+ }
131+
132+ if ((itemIndex == nextInStack)
133+ || (isMainStageApp && nextStage === ApplicationInfoInterface.MainStage)
134+ || (isSideStageApp && nextStage === ApplicationInfoInterface.SideStage)) {
135+ return MathUtils.linearAnimation(0, 1, startAngle, targetAngle, progress);
136+ }
137+
138+ if (progress < breakPoint) {
139+ return 0;
140+ }
141+ return MathUtils.linearAnimation(breakPoint, 1, startAngle, targetAngle, progress);
142+ }
143+
144+ readonly property real animatedScale: {
145+ var pullingInSideStage = itemIndex == nextInStack && stage == ApplicationInfoInterface.SideStage && !sideStageOpen;
146+
147+ var startScale = 1;
148+ if (isMainStageApp) {
149+ startScale = 1;
150+ } else if (isSideStageApp) {
151+ startScale = 1;
152+ } else {
153+ if (pullingInSideStage) {
154+ startScale = 1
155+ } else {
156+ startScale = root.startScale;
157+ }
158+ }
159+
160+ if (progress < breakPoint) {
161+ if (itemIndex == nextInStack && (sideStageOpen || stage == ApplicationInfoInterface.MainStage)) {
162+ return MathUtils.linearAnimation(0, 1, startScale, targetScale, progress);
163+ }
164+ return startScale;
165+ }
166+ if (itemIndex == nextInStack) {
167+ return MathUtils.linearAnimation(0, 1, startScale, targetScale, progress)
168+ }
169+
170+ return MathUtils.linearAnimation(breakPoint, 1, startScale, targetScale, progress)
171+ }
172+
173+ readonly property bool itemVisible: true //animatedX < sceneWidth
174+}
qml/Stage/Spread/WindowedRightEdgeMaths.qmlnew file+81
@@ -0,0 +1,81 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import Unity.Application 0.1
20+import "MathUtils.js" as MathUtils
21+
22+QtObject {
23+ id: root
24+
25+ // Input
26+ property int itemIndex: 0
27+ property int normalZ: 0
28+ property real progress: 0
29+ property int startWidth: 0
30+ property int startHeight: 0
31+ property int startX: 0
32+ property int targetX: 0
33+ property int startY: 0
34+ property int targetY: 0
35+// property real startAngle: 40
36+ property real targetAngle: 0
37+ property int targetHeight: 0
38+ property real targetScale: 0
39+
40+ // Config
41+ property real breakPoint: 0.4
42+
43+ // Output
44+
45+ readonly property real scaleToPreviewProgress: {
46+ return progress < breakPoint ? 0 : MathUtils.clamp(MathUtils.linearAnimation(breakPoint, 1, 0, 1, progress), 0, 1)
47+ }
48+ readonly property int animatedWidth: {
49+ return progress < breakPoint ? root.startWidth : MathUtils.linearAnimation(breakPoint, 1, root.startWidth, targetHeight, progress)
50+ }
51+
52+ readonly property int animatedHeight: {
53+ return progress < breakPoint ? root.startHeight : MathUtils.linearAnimation(breakPoint, 1, root.startHeight, targetHeight, progress)
54+ }
55+
56+ readonly property int animatedX: {
57+ if (progress < breakPoint) {
58+ return startX;
59+ }
60+ return MathUtils.linearAnimation(breakPoint, 1, startX, targetX, progress)
61+ }
62+
63+ readonly property int animatedY: progress < breakPoint ? startY : MathUtils.linearAnimation(breakPoint, 1, startY, targetY, progress)
64+
65+ readonly property real animatedAngle: progress < breakPoint ? 0 : MathUtils.linearAnimation(breakPoint, 1, 0, targetAngle, progress);
66+
67+ readonly property real decorationHeight: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, 0, progress);
68+
69+ readonly property int animatedZ: {
70+ if (progress < breakPoint + (1 - breakPoint) / 2) {
71+ return itemIndex == 1 ? normalZ + 2 : normalZ
72+ }
73+ return itemIndex
74+ }
75+
76+ readonly property real opacityMask: itemIndex == 1 ? MathUtils.linearAnimation(0, breakPoint, 0, 1, progress) : 1
77+
78+ readonly property real animatedScale: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, targetScale, progress)
79+
80+// readonly property bool itemVisible: true //animatedX < sceneWidth
81+}
qml/Stage/Spread/cubic-bezier.jsnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2016 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+//====================================\\
18+// 13thParallel.org Beziér Curve Code \\
19+// by Dan Pupius (www.pupius.net) \\
20+//====================================\\
21+
22+
23+var coord = function (x,y) {
24+ if(!x) var x=0;
25+ if(!y) var y=0;
26+ return {x: x, y: y};
27+}
28+
29+function B4(t) { return t*t*t }
30+function B3(t) { return 3*t*t*(1-t) }
31+function B2(t) { return 3*t*(1-t)*(1-t) }
32+function B1(t) { return (1-t)*(1-t)*(1-t) }
33+
34+var getBezier = function(percent,C1,C2,C3,C4) {
35+ var pos = new coord();
36+ pos.x = C1.x*B1(percent) + C2.x*B2(percent) + C3.x*B3(percent) + C4.x*B4(percent);
37+ pos.y = C1.y*B1(percent) + C2.y*B2(percent) + C3.y*B3(percent) + C4.y*B4(percent);
38+ return pos;
39+}
qml/Stages/SpreadDelegate.qml → qml/Stage/SpreadDelegate.qmlrenamed

The content is the same.

qml/Stages/SpreadMaths.qml → qml/Stage/SpreadMaths.qmlrenamed

The content is the same.

qml/Stage/Stage.qmlnew file+1888
@@ -0,0 +1,1888 @@
1+/*
2+ * Copyright (C) 2014-2016 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.4
18+import Ubuntu.Components 1.3
19+import Unity.Application 0.1
20+import "../Components/PanelState"
21+import "../Components"
22+import Utils 0.1
23+import Ubuntu.Gestures 0.1
24+import GlobalShortcut 1.0
25+import GSettings 1.0
26+import "Spread"
27+import "Spread/MathUtils.js" as MathUtils
28+
29+FocusScope {
30+ id: root
31+ anchors.fill: parent
32+
33+ property QtObject applicationManager
34+ property QtObject topLevelSurfaceList
35+ property bool altTabPressed
36+ property url background
37+ property int dragAreaWidth
38+ property bool interactive
39+ property bool keepDashRunning: true
40+ property real nativeHeight
41+ property real nativeWidth
42+ property QtObject orientations
43+ property int shellOrientation
44+ property int shellOrientationAngle
45+ property bool spreadEnabled: true // If false, animations and right edge will be disabled
46+ property bool suspended
47+ property int leftMargin: 0
48+ property bool oskEnabled: false
49+ property rect inputMethodRect
50+
51+ // Configuration
52+ property string mode: "staged"
53+ property real leftEdgeDragProgress: 0
54+
55+ // Used by the tutorial code
56+ readonly property bool spreadShown: state == "spread"
57+ readonly property real rightEdgeDragProgress: rightEdgeDragArea.progress // How far left the stage has been dragged
58+
59+ // used by the snap windows (edge maximize) feature
60+ readonly property alias previewRectangle: fakeRectangle
61+
62+ readonly property var mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
63+
64+ // application windows never rotate independently
65+ property int mainAppWindowOrientationAngle: shellOrientationAngle
66+
67+ property bool orientationChangesEnabled: priv.focusedAppDelegate && priv.focusedAppDelegate.orientationChangesEnabled
68+
69+ property int supportedOrientations: {
70+ if (mainApp) {
71+ switch (mode) {
72+ case "staged":
73+ return mainApp.supportedOrientations;
74+ case "stagedWithSideStage":
75+ var orientations = mainApp.supportedOrientations;
76+ orientations |= Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation;
77+ if (priv.sideStageItemId) {
78+ // If we have a sidestage app, support Portrait orientation
79+ // so that it will switch the sidestage app to mainstage on rotate to portrait
80+ orientations |= Qt.PortraitOrientation|Qt.InvertedPortraitOrientation;
81+ }
82+ return orientations;
83+ }
84+ }
85+
86+ return Qt.PortraitOrientation |
87+ Qt.LandscapeOrientation |
88+ Qt.InvertedPortraitOrientation |
89+ Qt.InvertedLandscapeOrientation;
90+ }
91+
92+
93+ onAltTabPressedChanged: priv.goneToSpread = altTabPressed
94+
95+ property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
96+ priv.focusedAppDelegate.surface.confinesMousePointer ?
97+ priv.focusedAppDelegate.clientAreaItem : null;
98+
99+ signal itemSnapshotRequested(Item item)
100+
101+ // functions to be called from outside
102+ function updateFocusedAppOrientation() { /* TODO */ }
103+ function updateFocusedAppOrientationAnimated() { /* TODO */}
104+ function pushRightEdge(amount) {
105+ edgeBarrier.push(amount);
106+ }
107+
108+ onSpreadEnabledChanged: {
109+ if (!spreadEnabled && root.state == "spread") {
110+ priv.goneToSpread = false;
111+ }
112+ }
113+
114+ GSettings {
115+ id: lifecycleExceptions
116+ schema.id: "com.canonical.qtmir"
117+ }
118+
119+ function isExemptFromLifecycle(appId) {
120+ var shortAppId = appId.split('_')[0];
121+ for (var i = 0; i < lifecycleExceptions.lifecycleExemptAppids.length; i++) {
122+ if (shortAppId === lifecycleExceptions.lifecycleExemptAppids[i]) {
123+ return true;
124+ }
125+ }
126+ return false;
127+ }
128+
129+ GlobalShortcut {
130+ id: closeFocusedShortcut
131+ shortcut: Qt.AltModifier|Qt.Key_F4
132+ onTriggered: {
133+ if (priv.focusedAppDelegate && !priv.focusedAppDelegate.isDash) {
134+ priv.focusedAppDelegate.close();
135+ }
136+ }
137+ }
138+
139+ GlobalShortcut {
140+ id: showSpreadShortcut
141+ shortcut: Qt.MetaModifier|Qt.Key_W
142+ onTriggered: priv.goneToSpread = true
143+ }
144+
145+ GlobalShortcut {
146+ id: minimizeAllShortcut
147+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_D
148+ onTriggered: priv.minimizeAllWindows()
149+ active: root.state == "windowed"
150+ }
151+
152+ GlobalShortcut {
153+ id: maximizeWindowShortcut
154+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
155+ onTriggered: priv.focusedAppDelegate.maximize()
156+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximized
157+ }
158+
159+ GlobalShortcut {
160+ id: maximizeWindowLeftShortcut
161+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
162+ onTriggered: priv.focusedAppDelegate.maximizeLeft()
163+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
164+ }
165+
166+ GlobalShortcut {
167+ id: maximizeWindowRightShortcut
168+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
169+ onTriggered: priv.focusedAppDelegate.maximizeRight()
170+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
171+ }
172+
173+ GlobalShortcut {
174+ id: minimizeRestoreShortcut
175+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
176+ onTriggered: priv.focusedAppDelegate.anyMaximized
177+ ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
178+ active: root.state == "windowed" && priv.focusedAppDelegate
179+ }
180+
181+ GlobalShortcut {
182+ shortcut: Qt.AltModifier|Qt.Key_Print
183+ onTriggered: root.itemSnapshotRequested(priv.focusedAppDelegate)
184+ active: priv.focusedAppDelegate !== null
185+ }
186+
187+ QtObject {
188+ id: priv
189+ objectName: "DesktopStagePrivate"
190+
191+ property var focusedAppDelegate: null
192+ property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
193+
194+ property bool goneToSpread: false
195+ property int closingIndex: -1
196+ property int animationDuration: UbuntuAnimation.FastDuration
197+
198+ function updateForegroundMaximizedApp() {
199+ var found = false;
200+ for (var i = 0; i < appRepeater.count && !found; i++) {
201+ var item = appRepeater.itemAt(i);
202+ if (item && item.visuallyMaximized) {
203+ foregroundMaximizedAppDelegate = item;
204+ found = true;
205+ }
206+ }
207+ if (!found) {
208+ foregroundMaximizedAppDelegate = null;
209+ }
210+ }
211+
212+ function minimizeAllWindows() {
213+ for (var i = 0; i < appRepeater.count; i++) {
214+ var appDelegate = appRepeater.itemAt(i);
215+ if (appDelegate && !appDelegate.minimized) {
216+ appDelegate.minimize();
217+ }
218+ }
219+ }
220+
221+ function focusNext() {
222+ for (var i = 0; i < appRepeater.count; i++) {
223+ var appDelegate = appRepeater.itemAt(i);
224+ if (appDelegate && !appDelegate.minimized) {
225+ appDelegate.focus = true;
226+ return;
227+ }
228+ }
229+ }
230+
231+ readonly property bool sideStageEnabled: root.shellOrientation == Qt.LandscapeOrientation ||
232+ root.shellOrientation == Qt.InvertedLandscapeOrientation
233+
234+ property var mainStageDelegate: null
235+ property var sideStageDelegate: null
236+ property int mainStageItemId: 0
237+ property int sideStageItemId: 0
238+ property string mainStageAppId: ""
239+ property string sideStageAppId: ""
240+
241+ onSideStageDelegateChanged: {
242+ if (!sideStageDelegate) {
243+ sideStage.hide();
244+ }
245+ }
246+
247+ function updateMainAndSideStageIndexes() {
248+ if (root.mode != "stagedWithSideStage") {
249+ priv.sideStageDelegate = null;
250+ priv.sideStageItemId = 0;
251+ priv.sideStageAppId = "";
252+ priv.mainStageDelegate = appRepeater.itemAt(0);
253+ priv.mainStageAppId = topLevelSurfaceList.idAt(0);
254+ priv.mainStageAppId = topLevelSurfaceList.applicationAt(0) ? topLevelSurfaceList.applicationAt(0).appId : ""
255+ return;
256+ }
257+
258+ var choseMainStage = false;
259+ var choseSideStage = false;
260+
261+ if (!root.topLevelSurfaceList)
262+ return;
263+
264+ for (var i = 0; i < appRepeater.count && (!choseMainStage || !choseSideStage); ++i) {
265+ var appDelegate = appRepeater.itemAt(i);
266+ if (sideStage.shown && appDelegate.stage == ApplicationInfoInterface.SideStage
267+ && !choseSideStage) {
268+ priv.sideStageDelegate = appDelegate
269+ priv.sideStageItemId = root.topLevelSurfaceList.idAt(i);
270+ priv.sideStageAppId = root.topLevelSurfaceList.applicationAt(i).appId;
271+ choseSideStage = true;
272+ } else if (!choseMainStage && appDelegate.stage == ApplicationInfoInterface.MainStage) {
273+ priv.mainStageDelegate = appDelegate;
274+ priv.mainStageItemId = root.topLevelSurfaceList.idAt(i);
275+ priv.mainStageAppId = root.topLevelSurfaceList.applicationAt(i).appId;
276+ choseMainStage = true;
277+ }
278+ }
279+ if (!choseMainStage && priv.mainStageDelegate) {
280+ priv.mainStageDelegate = null;
281+ priv.mainStageItemId = 0;
282+ priv.mainStageAppId = "";
283+ }
284+ if (!choseSideStage && priv.sideStageDelegate) {
285+ priv.sideStageDelegate = null;
286+ priv.sideStageItemId = 0;
287+ priv.sideStageAppId = "";
288+ }
289+ }
290+
291+ property int nextInStack: {
292+ var mainStageIndex = priv.mainStageDelegate ? priv.mainStageDelegate.itemIndex : -1;
293+ var sideStageIndex = priv.sideStageDelegate ? priv.sideStageDelegate.itemIndex : -1;
294+ if (sideStageIndex == -1) {
295+ return topLevelSurfaceList.count > 1 ? 1 : -1;
296+ }
297+ if (mainStageIndex == 0 || sideStageIndex == 0) {
298+ if (mainStageIndex == 1 || sideStageIndex == 1) {
299+ return topLevelSurfaceList.count > 2 ? 2 : -1;
300+ }
301+ return 1;
302+ }
303+ return -1;
304+ }
305+
306+ readonly property real virtualKeyboardHeight: root.inputMethodRect.height
307+ }
308+
309+ Component.onCompleted: priv.updateMainAndSideStageIndexes();
310+
311+ Connections {
312+ target: PanelState
313+ onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
314+ onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.minimize(); } }
315+ onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.restoreFromMaximized(); } }
316+ }
317+
318+ Binding {
319+ target: PanelState
320+ property: "decorationsVisible"
321+ value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
322+ }
323+
324+ Binding {
325+ target: PanelState
326+ property: "title"
327+ value: {
328+ if (priv.focusedAppDelegate !== null) {
329+ if (priv.focusedAppDelegate.maximized)
330+ return priv.focusedAppDelegate.title
331+ else
332+ return priv.focusedAppDelegate.appName
333+ }
334+ return ""
335+ }
336+ when: priv.focusedAppDelegate
337+ }
338+
339+ Binding {
340+ target: PanelState
341+ property: "focusedPersistentSurfaceId"
342+ value: {
343+ if (priv.focusedAppDelegate !== null) {
344+ if (priv.focusedAppDelegate.surface) {
345+ return priv.focusedAppDelegate.surface.persistentId;
346+ }
347+ }
348+ return "";
349+ }
350+ when: priv.focusedAppDelegate
351+ }
352+
353+ Binding {
354+ target: PanelState
355+ property: "dropShadow"
356+ value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
357+ }
358+
359+ Binding {
360+ target: PanelState
361+ property: "closeButtonShown"
362+ value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
363+ }
364+
365+ Component.onDestruction: {
366+ PanelState.title = "";
367+ PanelState.decorationsVisible = false;
368+ PanelState.dropShadow = false;
369+ }
370+
371+ Instantiator {
372+ model: root.applicationManager
373+ delegate: QtObject {
374+ property var stateBinding: Binding {
375+ readonly property bool isDash: model.application ? model.application.appId == "unity8-dash" : false
376+ target: model.application
377+ property: "requestedState"
378+
379+ // TODO: figure out some lifecycle policy, like suspending minimized apps
380+ // or something if running windowed.
381+ // TODO: If the device has a dozen suspended apps because it was running
382+ // in staged mode, when it switches to Windowed mode it will suddenly
383+ // resume all those apps at once. We might want to avoid that.
384+ value: root.mode === "windowed"
385+ || (isDash && root.keepDashRunning)
386+ || (!root.suspended && model.application && priv.focusedAppDelegate &&
387+ (priv.focusedAppDelegate.appId === model.application.appId ||
388+ priv.mainStageAppId === model.application.appId ||
389+ priv.sideStageAppId === model.application.appId))
390+ ? ApplicationInfoInterface.RequestedRunning
391+ : ApplicationInfoInterface.RequestedSuspended
392+ }
393+
394+ property var lifecycleBinding: Binding {
395+ target: model.application
396+ property: "exemptFromLifecycle"
397+ value: model.application
398+ ? (!model.application.isTouchApp || isExemptFromLifecycle(model.application.appId))
399+ : false
400+ }
401+ }
402+ }
403+
404+ Binding {
405+ target: MirFocusController
406+ property: "focusedSurface"
407+ value: priv.focusedAppDelegate ? priv.focusedAppDelegate.focusedSurface : null
408+ when: !appRepeater.startingUp && root.parent
409+ }
410+
411+ states: [
412+ State {
413+ name: "spread"; when: priv.goneToSpread
414+ PropertyChanges { target: floatingFlickable; enabled: true }
415+ PropertyChanges { target: spreadItem; focus: true }
416+ PropertyChanges { target: hoverMouseArea; enabled: true }
417+ PropertyChanges { target: rightEdgeDragArea; enabled: false }
418+ PropertyChanges { target: cancelSpreadMouseArea; enabled: true }
419+ },
420+ State {
421+ name: "stagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "staged"
422+ },
423+ State {
424+ name: "sideStagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "stagedWithSideStage"
425+ PropertyChanges {
426+ target: sideStage
427+ opacity: priv.sideStageDelegate.x === sideStage.x ? 1 : 0
428+ visible: true
429+ }
430+ },
431+ State {
432+ name: "windowedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "windowed"
433+ },
434+ State {
435+ name: "staged"; when: root.mode === "staged"
436+ },
437+ State {
438+ name: "stagedWithSideStage"; when: root.mode === "stagedWithSideStage"
439+ PropertyChanges { target: triGestureArea; enabled: true }
440+ PropertyChanges { target: sideStage; visible: true }
441+ },
442+ State {
443+ name: "windowed"; when: root.mode === "windowed"
444+ }
445+ ]
446+ transitions: [
447+ Transition {
448+ from: "stagedRightEdge,sideStagedRightEdge,windowedRightEdge"; to: "spread"
449+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
450+ },
451+ Transition {
452+ to: "spread"
453+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: appRepeater.count > 1 ? 1 : 0 }
454+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
455+ },
456+ Transition {
457+ from: "spread"
458+ SequentialAnimation {
459+ ScriptAction {
460+ script: {
461+ var item = appRepeater.itemAt(Math.max(0, spreadItem.highlightedIndex));
462+ if (item.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
463+ sideStage.show();
464+ }
465+ item.playFocusAnimation();
466+ }
467+ }
468+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
469+ }
470+ },
471+ Transition {
472+ to: "stagedRightEdge"
473+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
474+ },
475+ Transition {
476+ to: "stagedWithSideStage"
477+ ScriptAction { script: priv.updateMainAndSideStageIndexes(); }
478+ }
479+
480+ ]
481+
482+ MouseArea {
483+ id: cancelSpreadMouseArea
484+ anchors.fill: parent
485+ enabled: false
486+ onClicked: priv.goneToSpread = false
487+ }
488+
489+ FocusScope {
490+ id: appContainer
491+ objectName: "appContainer"
492+ anchors.fill: parent
493+ focus: true
494+
495+ Wallpaper {
496+ id: wallpaper
497+ anchors.fill: parent
498+ source: root.background
499+ // Make sure it's the lowest item. Due to the left edge drag we sometimes need
500+ // to put the dash at -1 and we don't want it behind the Wallpaper
501+ z: -2
502+ }
503+
504+ Spread {
505+ id: spreadItem
506+ objectName: "spreadItem"
507+ anchors.fill: appContainer
508+ leftMargin: root.leftMargin
509+ model: root.topLevelSurfaceList
510+ spreadFlickable: floatingFlickable
511+ z: 10
512+
513+ onLeaveSpread: {
514+ priv.goneToSpread = false;
515+ }
516+ }
517+
518+ Connections {
519+ target: root.topLevelSurfaceList
520+ onListChanged: priv.updateMainAndSideStageIndexes()
521+ }
522+
523+
524+ DropArea {
525+ objectName: "MainStageDropArea"
526+ anchors {
527+ left: parent.left
528+ top: parent.top
529+ bottom: parent.bottom
530+ }
531+ width: appContainer.width - sideStage.width
532+ enabled: sideStage.enabled
533+
534+ onDropped: {
535+ drop.source.appDelegate.saveStage(ApplicationInfoInterface.MainStage);
536+ drop.source.appDelegate.focus = true;
537+ }
538+ keys: "SideStage"
539+ }
540+
541+ SideStage {
542+ id: sideStage
543+ objectName: "sideStage"
544+ shown: false
545+ height: appContainer.height
546+ x: appContainer.width - width
547+ visible: false
548+ Behavior on opacity { UbuntuNumberAnimation {} }
549+ z: {
550+ if (!priv.mainStageItemId) return 0;
551+
552+ if (priv.sideStageItemId && priv.nextInStack > 0) {
553+
554+ // Due the order in which bindings are evaluated, this might be triggered while shuffling
555+ // the list and index doesn't yet match with itemIndex (even though itemIndex: index)
556+ // Let's walk the list and compare itemIndex to make sure we have the correct one.
557+ var nextDelegateInStack = -1;
558+ for (var i = 0; i < appRepeater.count; i++) {
559+ if (appRepeater.itemAt(i).itemIndex == priv.nextInStack) {
560+ nextDelegateInStack = appRepeater.itemAt(i);
561+ break;
562+ }
563+ }
564+
565+ if (nextDelegateInStack.stage === ApplicationInfoInterface.MainStage) {
566+ // if the next app in stack is a main stage app, put the sidestage on top of it.
567+ return 2;
568+ }
569+ return 1;
570+ }
571+
572+ return 1;
573+ }
574+
575+ onShownChanged: {
576+ if (!shown && priv.mainStageDelegate) {
577+ priv.mainStageDelegate.claimFocus();
578+ }
579+ }
580+
581+ DropArea {
582+ id: sideStageDropArea
583+ objectName: "SideStageDropArea"
584+ anchors.fill: parent
585+
586+ property bool dropAllowed: true
587+
588+ onEntered: {
589+ dropAllowed = drag.keys != "Disabled";
590+ }
591+ onExited: {
592+ dropAllowed = true;
593+ }
594+ onDropped: {
595+ if (drop.keys == "MainStage") {
596+ drop.source.appDelegate.saveStage(ApplicationInfoInterface.SideStage);
597+ drop.source.appDelegate.focus = true;
598+ }
599+ }
600+ drag {
601+ onSourceChanged: {
602+ if (!sideStageDropArea.drag.source) {
603+ dropAllowed = true;
604+ }
605+ }
606+ }
607+ }
608+ }
609+
610+ TopLevelSurfaceRepeater {
611+ id: appRepeater
612+ model: topLevelSurfaceList
613+ objectName: "appRepeater"
614+
615+ delegate: FocusScope {
616+ id: appDelegate
617+ objectName: "appDelegate_" + model.id
618+ property int itemIndex: index // We need this from outside the repeater
619+ // z might be overriden in some cases by effects, but we need z ordering
620+ // to calculate occlusion detection
621+ property int normalZ: topLevelSurfaceList.count - index
622+ onNormalZChanged: {
623+ if (visuallyMaximized) {
624+ priv.updateForegroundMaximizedApp();
625+ }
626+ }
627+ z: normalZ
628+
629+ // Normally we want x/y where we request it to be. Width/height of our delegate will
630+ // match what the actual surface size is.
631+ // Don't write to those, they will be set by states
632+ x: requestedX
633+ y: requestedY
634+ width: decoratedWindow.implicitWidth
635+ height: decoratedWindow.implicitHeight
636+
637+ // requestedX/Y/width/height is what we ask the actual surface to be.
638+ // Do not write to those, they will be set by states
639+ property real requestedX: windowedX
640+ property real requestedY: windowedY
641+ property real requestedWidth: windowedWidth
642+ property real requestedHeight: windowedHeight
643+
644+ // In those are for windowed mode. Those values basically store the window's properties
645+ // when having a floating window. If you want to move/resize a window in normal mode, this is what you want to write to.
646+ property real windowedX
647+ property real windowedY
648+ property real windowedWidth
649+ property real windowedHeight
650+
651+ // unlike windowedX/Y, this is the last known grab position before being pushed against edges/corners
652+ // when restoring, the window should return to these, not to the place where it was dropped near the edge
653+ property real restoredX
654+ property real restoredY
655+
656+ Binding {
657+ target: appDelegate
658+ property: "y"
659+ value: appDelegate.requestedY -
660+ Math.min(appDelegate.requestedY - PanelState.panelHeight,
661+ Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
662+ when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
663+ && root.inputMethodRect.height > 0
664+
665+ }
666+
667+ Behavior on x { id: xBehavior; enabled: priv.closingIndex >= 0; UbuntuNumberAnimation { onRunningChanged: if (!running) priv.closingIndex = -1} }
668+
669+ Connections {
670+ target: root
671+ onShellOrientationAngleChanged: {
672+ // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
673+ if (application && application.rotatesWindowContents) {
674+ if (root.state == "windowed") {
675+ var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
676+ angleDiff = (360 + angleDiff) % 360;
677+ if (angleDiff === 90 || angleDiff === 270) {
678+ var aux = decoratedWindow.requestedHeight;
679+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.decorationHeight;
680+ decoratedWindow.requestedWidth = aux - decoratedWindow.decorationHeight;
681+ }
682+ }
683+ decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
684+ } else {
685+ decoratedWindow.surfaceOrientationAngle = 0;
686+ }
687+ }
688+ }
689+ Connections {
690+ target: priv
691+ onSideStageEnabledChanged: refreshStage()
692+ }
693+
694+ readonly property alias application: decoratedWindow.application
695+ readonly property alias minimumWidth: decoratedWindow.minimumWidth
696+ readonly property alias minimumHeight: decoratedWindow.minimumHeight
697+ readonly property alias maximumWidth: decoratedWindow.maximumWidth
698+ readonly property alias maximumHeight: decoratedWindow.maximumHeight
699+ readonly property alias widthIncrement: decoratedWindow.widthIncrement
700+ readonly property alias heightIncrement: decoratedWindow.heightIncrement
701+
702+ readonly property bool maximized: windowState === WindowStateStorage.WindowStateMaximized
703+ readonly property bool maximizedLeft: windowState === WindowStateStorage.WindowStateMaximizedLeft
704+ readonly property bool maximizedRight: windowState === WindowStateStorage.WindowStateMaximizedRight
705+ readonly property bool maximizedHorizontally: windowState === WindowStateStorage.WindowStateMaximizedHorizontally
706+ readonly property bool maximizedVertically: windowState === WindowStateStorage.WindowStateMaximizedVertically
707+ readonly property bool maximizedTopLeft: windowState === WindowStateStorage.WindowStateMaximizedTopLeft
708+ readonly property bool maximizedTopRight: windowState === WindowStateStorage.WindowStateMaximizedTopRight
709+ readonly property bool maximizedBottomLeft: windowState === WindowStateStorage.WindowStateMaximizedBottomLeft
710+ readonly property bool maximizedBottomRight: windowState === WindowStateStorage.WindowStateMaximizedBottomRight
711+ readonly property bool anyMaximized: maximized || maximizedLeft || maximizedRight || maximizedHorizontally || maximizedVertically ||
712+ maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
713+
714+ readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
715+ readonly property bool fullscreen: surface ? surface.state === Mir.FullscreenState : application.fullscreen
716+
717+ readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
718+ readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
719+ (maximumHeight == 0 || maximumHeight >= appContainer.height)
720+ readonly property bool canBeCornerMaximized: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
721+ (maximumHeight == 0 || maximumHeight >= appContainer.height/2)
722+ readonly property bool canBeMaximizedHorizontally: maximumWidth == 0 || maximumWidth >= appContainer.width
723+ readonly property bool canBeMaximizedVertically: maximumHeight == 0 || maximumHeight >= appContainer.height
724+ readonly property alias orientationChangesEnabled: decoratedWindow.orientationChangesEnabled
725+
726+ property int windowState: WindowStateStorage.WindowStateNormal
727+ property bool animationsEnabled: true
728+ property alias title: decoratedWindow.title
729+ readonly property string appName: model.application ? model.application.name : ""
730+ property bool visuallyMaximized: false
731+ property bool visuallyMinimized: false
732+
733+ property int stage: ApplicationInfoInterface.MainStage
734+ function saveStage(newStage) {
735+ appDelegate.stage = newStage;
736+ WindowStateStorage.saveStage(appId, newStage);
737+ priv.updateMainAndSideStageIndexes()
738+ }
739+
740+ readonly property var surface: model.surface
741+ readonly property alias resizeArea: resizeArea
742+ readonly property alias focusedSurface: decoratedWindow.focusedSurface
743+ readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
744+
745+ readonly property string appId: model.application.appId
746+ readonly property bool isDash: appId == "unity8-dash"
747+ readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
748+
749+ function claimFocus() {
750+ if (root.state == "spread") {
751+ spreadItem.highlightedIndex = index
752+ priv.goneToSpread = false;
753+ }
754+ if (root.mode == "stagedWithSideStage") {
755+ if (appDelegate.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
756+ sideStage.show();
757+ }
758+ priv.updateMainAndSideStageIndexes();
759+ }
760+
761+ if (root.mode == "windowed") {
762+ appDelegate.restore(true /* animated */, appDelegate.windowState);
763+ } else {
764+ appDelegate.focus = true;
765+ }
766+ }
767+ Connections {
768+ target: model.surface
769+ onFocusRequested: {
770+ claimFocus();
771+ }
772+ }
773+ Connections {
774+ target: model.application
775+ onFocusRequested: {
776+ if (!model.surface) {
777+ // when an app has no surfaces, we assume there's only one entry representing it:
778+ // this delegate.
779+ claimFocus();
780+ } else {
781+ // if the application has surfaces, focus request should be at surface-level.
782+ }
783+ }
784+ }
785+
786+ onFocusChanged: {
787+ if (appRepeater.startingUp)
788+ return;
789+
790+ if (focus) {
791+ topLevelSurfaceList.raiseId(model.id);
792+ priv.focusedAppDelegate = appDelegate;
793+ } else if (!focus && priv.focusedAppDelegate === appDelegate && root.state != "spread") {
794+ priv.focusedAppDelegate = null;
795+ // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
796+ MirFocusController.focusedSurface = null;
797+ }
798+ }
799+ Component.onCompleted: {
800+ if (application && application.rotatesWindowContents) {
801+ decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
802+ } else {
803+ decoratedWindow.surfaceOrientationAngle = 0;
804+ }
805+
806+ // First, cascade the newly created window, relative to the currently/old focused window.
807+ windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
808+ windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
809+ // Now load any saved state. This needs to happen *after* the cascading!
810+ resizeArea.loadWindowState();
811+
812+ // NB: We're differentiating if this delegate was created in response to a new entry in the model
813+ // or if the Repeater is just populating itself with delegates to match the model it received.
814+ if (!appRepeater.startingUp) {
815+ // a top level window is always the focused one when it first appears, unfocusing
816+ // any preexisting one
817+ if (root.state == "spread") {
818+ spreadItem.highlightedIndex = index;
819+ }
820+ claimFocus();
821+ }
822+
823+ refreshStage();
824+ _constructing = false;
825+ }
826+ Component.onDestruction: {
827+ if (!root.parent) {
828+ // This stage is about to be destroyed. Don't mess up with the model at this point
829+ return;
830+ }
831+
832+ if (visuallyMaximized) {
833+ priv.updateForegroundMaximizedApp();
834+ }
835+
836+ if (focus) {
837+ // focus some other window
838+ for (var i = 0; i < appRepeater.count; i++) {
839+ var appDelegate = appRepeater.itemAt(i);
840+ if (appDelegate && !appDelegate.minimized && i != index) {
841+ appDelegate.focus = true;
842+ return;
843+ }
844+ }
845+ }
846+ }
847+
848+ onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
849+
850+ property bool _constructing: true;
851+ onStageChanged: {
852+ if (!_constructing) {
853+ priv.updateMainAndSideStageIndexes();
854+ }
855+ }
856+
857+ visible: (
858+ !visuallyMinimized
859+ && !greeter.fullyShown
860+ && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
861+ )
862+ || appDelegate.fullscreen
863+ || focusAnimation.running || rightEdgeFocusAnimation.running || hidingAnimation.running
864+
865+ function close() {
866+ model.surface.close();
867+ }
868+
869+ function maximize(animated) {
870+ animationsEnabled = (animated === undefined) || animated;
871+ windowState = WindowStateStorage.WindowStateMaximized;
872+ }
873+ function maximizeLeft(animated) {
874+ animationsEnabled = (animated === undefined) || animated;
875+ windowState = WindowStateStorage.WindowStateMaximizedLeft;
876+ }
877+ function maximizeRight(animated) {
878+ animationsEnabled = (animated === undefined) || animated;
879+ windowState = WindowStateStorage.WindowStateMaximizedRight;
880+ }
881+ function maximizeHorizontally(animated) {
882+ animationsEnabled = (animated === undefined) || animated;
883+ windowState = WindowStateStorage.WindowStateMaximizedHorizontally;
884+ }
885+ function maximizeVertically(animated) {
886+ animationsEnabled = (animated === undefined) || animated;
887+ windowState = WindowStateStorage.WindowStateMaximizedVertically;
888+ }
889+ function maximizeTopLeft(animated) {
890+ animationsEnabled = (animated === undefined) || animated;
891+ windowState = WindowStateStorage.WindowStateMaximizedTopLeft;
892+ }
893+ function maximizeTopRight(animated) {
894+ animationsEnabled = (animated === undefined) || animated;
895+ windowState = WindowStateStorage.WindowStateMaximizedTopRight;
896+ }
897+ function maximizeBottomLeft(animated) {
898+ animationsEnabled = (animated === undefined) || animated;
899+ windowState = WindowStateStorage.WindowStateMaximizedBottomLeft;
900+ }
901+ function maximizeBottomRight(animated) {
902+ animationsEnabled = (animated === undefined) || animated;
903+ windowState = WindowStateStorage.WindowStateMaximizedBottomRight;
904+ }
905+ function minimize(animated) {
906+ animationsEnabled = (animated === undefined) || animated;
907+ windowState |= WindowStateStorage.WindowStateMinimized; // add the minimized bit
908+ }
909+ function restoreFromMaximized(animated) {
910+ animationsEnabled = (animated === undefined) || animated;
911+ windowState = WindowStateStorage.WindowStateRestored;
912+ }
913+ function restore(animated,state) {
914+ animationsEnabled = (animated === undefined) || animated;
915+ windowState = state || WindowStateStorage.WindowStateRestored;
916+ windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
917+ focus = true;
918+ }
919+
920+ function playFocusAnimation() {
921+ if (state == "stagedRightEdge") {
922+ // TODO: Can we drop this if and find something that always works?
923+ if (root.mode == "staged") {
924+ rightEdgeFocusAnimation.targetX = 0
925+ rightEdgeFocusAnimation.start()
926+ } else if (root.mode == "stagedWithSideStage") {
927+ rightEdgeFocusAnimation.targetX = appDelegate.stage == ApplicationInfoInterface.SideStage ? sideStage.x : 0
928+ rightEdgeFocusAnimation.start()
929+ }
930+ } else if (state == "windowedRightEdge") {
931+ claimFocus();
932+ } else {
933+ focusAnimation.start()
934+ }
935+ }
936+ function playHidingAnimation() {
937+ if (state != "windowedRightEdge") {
938+ hidingAnimation.start()
939+ }
940+ }
941+
942+ function refreshStage() {
943+ var newStage = ApplicationInfoInterface.MainStage;
944+ if (priv.sideStageEnabled) { // we're in lanscape rotation.
945+ if (!isDash && application && application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
946+ var defaultStage = ApplicationInfoInterface.SideStage; // if application supports portrait, it defaults to sidestage.
947+ if (application.supportedOrientations & (Qt.LandscapeOrientation|Qt.InvertedLandscapeOrientation)) {
948+ // if it supports lanscape, it defaults to mainstage.
949+ defaultStage = ApplicationInfoInterface.MainStage;
950+ }
951+ newStage = WindowStateStorage.getStage(application.appId, defaultStage);
952+ }
953+ }
954+
955+ stage = newStage;
956+ if (focus && stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
957+ sideStage.show();
958+ }
959+ }
960+
961+ UbuntuNumberAnimation {
962+ id: focusAnimation
963+ target: appDelegate
964+ property: "scale"
965+ from: 0.98
966+ to: 1
967+ duration: UbuntuAnimation.SnapDuration
968+ onStarted: {
969+ topLevelSurfaceList.raiseId(model.id);
970+ }
971+ onStopped: {
972+ appDelegate.claimFocus();
973+ }
974+ }
975+ ParallelAnimation {
976+ id: rightEdgeFocusAnimation
977+ property int targetX: 0
978+ UbuntuNumberAnimation { target: appDelegate; properties: "x"; to: rightEdgeFocusAnimation.targetX; duration: priv.animationDuration }
979+ UbuntuNumberAnimation { target: decoratedWindow; properties: "angle"; to: 0; duration: priv.animationDuration }
980+ UbuntuNumberAnimation { target: decoratedWindow; properties: "itemScale"; to: 1; duration: priv.animationDuration }
981+ onStopped: {
982+ appDelegate.focus = true
983+ }
984+ }
985+ ParallelAnimation {
986+ id: hidingAnimation
987+ UbuntuNumberAnimation { target: appDelegate; property: "opacity"; to: 0; duration: priv.animationDuration }
988+ onStopped: appDelegate.opacity = 1
989+ }
990+
991+ SpreadMaths {
992+ id: spreadMaths
993+ spread: spreadItem
994+ itemIndex: index
995+ flickable: floatingFlickable
996+ }
997+ StageMaths {
998+ id: stageMaths
999+ sceneWidth: root.width
1000+ stage: appDelegate.stage
1001+ thisDelegate: appDelegate
1002+ mainStageDelegate: priv.mainStageDelegate
1003+ sideStageDelegate: priv.sideStageDelegate
1004+ sideStageWidth: sideStage.panelWidth
1005+ sideStageX: sideStage.x
1006+ itemIndex: appDelegate.itemIndex
1007+ nextInStack: priv.nextInStack
1008+ leftEdgeDragProgress: root.leftEdgeDragProgress
1009+ }
1010+
1011+ StagedRightEdgeMaths {
1012+ id: stagedRightEdgeMaths
1013+ sceneWidth: appContainer.width - root.leftMargin
1014+ sceneHeight: appContainer.height
1015+ isMainStageApp: priv.mainStageDelegate == appDelegate
1016+ isSideStageApp: priv.sideStageDelegate == appDelegate
1017+ sideStageWidth: sideStage.width
1018+ sideStageOpen: sideStage.shown
1019+ itemIndex: index
1020+ nextInStack: priv.nextInStack
1021+ progress: 0
1022+ targetHeight: spreadItem.stackHeight
1023+ targetX: spreadMaths.targetX
1024+ startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1025+ targetY: spreadMaths.targetY
1026+ targetAngle: spreadMaths.targetAngle
1027+ targetScale: spreadMaths.targetScale
1028+ shuffledZ: stageMaths.itemZ
1029+ breakPoint: spreadItem.rightEdgeBreakPoint
1030+ }
1031+
1032+ WindowedRightEdgeMaths {
1033+ id: windowedRightEdgeMaths
1034+ itemIndex: index
1035+ startWidth: appDelegate.requestedWidth
1036+ startHeight: appDelegate.requestedHeight
1037+ targetHeight: spreadItem.stackHeight
1038+ targetX: spreadMaths.targetX
1039+ targetY: spreadMaths.targetY
1040+ normalZ: appDelegate.normalZ
1041+ targetAngle: spreadMaths.targetAngle
1042+ targetScale: spreadMaths.targetScale
1043+ breakPoint: spreadItem.rightEdgeBreakPoint
1044+ }
1045+
1046+ states: [
1047+ State {
1048+ name: "spread"; when: root.state == "spread"
1049+ PropertyChanges {
1050+ target: decoratedWindow;
1051+ showDecoration: false;
1052+ angle: spreadMaths.targetAngle
1053+ itemScale: spreadMaths.targetScale
1054+ scaleToPreviewSize: spreadItem.stackHeight
1055+ scaleToPreviewProgress: 1
1056+ hasDecoration: root.mode === "windowed"
1057+ shadowOpacity: spreadMaths.shadowOpacity
1058+ showHighlight: spreadItem.highlightedIndex === index
1059+ darkening: spreadItem.highlightedIndex >= 0
1060+ anchors.topMargin: dragArea.distance
1061+ }
1062+ PropertyChanges {
1063+ target: appDelegate
1064+ x: spreadMaths.targetX
1065+ y: spreadMaths.targetY
1066+ z: index
1067+ height: spreadItem.spreadItemHeight
1068+ requestedWidth: decoratedWindow.oldRequestedWidth
1069+ requestedHeight: decoratedWindow.oldRequestedHeight
1070+ visible: spreadMaths.itemVisible
1071+ }
1072+ PropertyChanges { target: dragArea; enabled: true }
1073+ PropertyChanges { target: windowInfoItem; opacity: spreadMaths.tileInfoOpacity; visible: spreadMaths.itemVisible }
1074+ },
1075+ State {
1076+ name: "stagedRightEdge"
1077+ when: (root.mode == "staged" || root.mode == "stagedWithSideStage") && (root.state == "sideStagedRightEdge" || root.state == "stagedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running)
1078+ PropertyChanges {
1079+ target: stagedRightEdgeMaths
1080+ progress: Math.max(edgeBarrier.progress, rightEdgeDragArea.draggedProgress)
1081+ }
1082+ PropertyChanges {
1083+ target: appDelegate
1084+ x: stagedRightEdgeMaths.animatedX
1085+ y: stagedRightEdgeMaths.animatedY
1086+ z: stagedRightEdgeMaths.animatedZ
1087+ height: stagedRightEdgeMaths.animatedHeight
1088+ requestedWidth: decoratedWindow.oldRequestedWidth
1089+ requestedHeight: decoratedWindow.oldRequestedHeight
1090+ visible: appDelegate.x < root.width
1091+ }
1092+ PropertyChanges {
1093+ target: decoratedWindow
1094+ hasDecoration: false
1095+ angle: stagedRightEdgeMaths.animatedAngle
1096+ itemScale: stagedRightEdgeMaths.animatedScale
1097+ scaleToPreviewSize: spreadItem.stackHeight
1098+ scaleToPreviewProgress: stagedRightEdgeMaths.scaleToPreviewProgress
1099+ shadowOpacity: .3
1100+ }
1101+ },
1102+ State {
1103+ name: "windowedRightEdge"
1104+ when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || edgeBarrier.progress > 0)
1105+ PropertyChanges {
1106+ target: windowedRightEdgeMaths
1107+ progress: Math.max(rightEdgeDragArea.progress, edgeBarrier.progress)
1108+ }
1109+ PropertyChanges {
1110+ target: appDelegate
1111+ x: windowedRightEdgeMaths.animatedX
1112+ y: windowedRightEdgeMaths.animatedY
1113+ z: windowedRightEdgeMaths.animatedZ
1114+ height: stagedRightEdgeMaths.animatedHeight
1115+ requestedWidth: decoratedWindow.oldRequestedWidth
1116+ requestedHeight: decoratedWindow.oldRequestedHeight
1117+ }
1118+ PropertyChanges {
1119+ target: decoratedWindow
1120+ showDecoration: windowedRightEdgeMaths.decorationHeight
1121+ angle: windowedRightEdgeMaths.animatedAngle
1122+ itemScale: windowedRightEdgeMaths.animatedScale
1123+ scaleToPreviewSize: spreadItem.stackHeight
1124+ scaleToPreviewProgress: windowedRightEdgeMaths.scaleToPreviewProgress
1125+ shadowOpacity: .3
1126+ }
1127+ PropertyChanges {
1128+ target: opacityEffect;
1129+ opacityValue: windowedRightEdgeMaths.opacityMask
1130+ sourceItem: windowedRightEdgeMaths.opacityMask < 1 ? decoratedWindow : null
1131+ }
1132+ },
1133+ State {
1134+ name: "staged"; when: root.state == "staged"
1135+ PropertyChanges {
1136+ target: appDelegate
1137+ x: stageMaths.itemX
1138+ y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1139+ requestedWidth: appContainer.width
1140+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1141+ visuallyMaximized: true
1142+ visible: appDelegate.x < root.width
1143+ }
1144+ PropertyChanges {
1145+ target: decoratedWindow
1146+ hasDecoration: false
1147+ }
1148+ PropertyChanges {
1149+ target: resizeArea
1150+ enabled: false
1151+ }
1152+ PropertyChanges {
1153+ target: stageMaths
1154+ animateX: !focusAnimation.running && itemIndex !== spreadItem.highlightedIndex
1155+ }
1156+ },
1157+ State {
1158+ name: "stagedWithSideStage"; when: root.state == "stagedWithSideStage"
1159+ PropertyChanges {
1160+ target: stageMaths
1161+ itemIndex: index
1162+ }
1163+ PropertyChanges {
1164+ target: appDelegate
1165+ x: stageMaths.itemX
1166+ y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1167+ z: stageMaths.itemZ
1168+ requestedWidth: stageMaths.itemWidth
1169+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1170+ visuallyMaximized: true
1171+ visible: appDelegate.x < root.width
1172+ }
1173+ PropertyChanges {
1174+ target: decoratedWindow
1175+ hasDecoration: false
1176+ }
1177+ PropertyChanges {
1178+ target: resizeArea
1179+ enabled: false
1180+ }
1181+ },
1182+ State {
1183+ name: "maximized"; when: appDelegate.windowState == WindowStateStorage.WindowStateMaximized
1184+ PropertyChanges {
1185+ target: appDelegate;
1186+ requestedX: root.leftMargin;
1187+ requestedY: 0;
1188+ visuallyMinimized: false;
1189+ visuallyMaximized: true
1190+ requestedWidth: appContainer.width - root.leftMargin;
1191+ requestedHeight: appContainer.height;
1192+ }
1193+ PropertyChanges { target: touchControls; enabled: true }
1194+ },
1195+ State {
1196+ name: "fullscreen"; when: appDelegate.fullscreen && !appDelegate.minimized
1197+ PropertyChanges {
1198+ target: appDelegate;
1199+ requestedX: 0
1200+ requestedY: 0
1201+ requestedWidth: appContainer.width;
1202+ requestedHeight: appContainer.height;
1203+ }
1204+ PropertyChanges { target: decoratedWindow; hasDecoration: false }
1205+ },
1206+ State {
1207+ name: "normal";
1208+ when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
1209+ PropertyChanges {
1210+ target: appDelegate
1211+ visuallyMinimized: false
1212+ visuallyMaximized: false
1213+ }
1214+ PropertyChanges { target: touchControls; enabled: true }
1215+ PropertyChanges { target: resizeArea; enabled: true }
1216+ PropertyChanges { target: decoratedWindow; shadowOpacity: .3}
1217+ },
1218+ State {
1219+ name: "restored";
1220+ when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
1221+ extend: "normal"
1222+ PropertyChanges {
1223+ target: appDelegate;
1224+ windowedX: restoredX;
1225+ windowedY: restoredY;
1226+ }
1227+ },
1228+ State {
1229+ name: "semiMaximized"
1230+ PropertyChanges { target: touchControls; enabled: true }
1231+ PropertyChanges { target: resizeArea; enabled: true }
1232+ PropertyChanges { target: decoratedWindow; shadowOpacity: .3 }
1233+ },
1234+ State {
1235+ name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
1236+ extend: "semiMaximized"
1237+ PropertyChanges {
1238+ target: appDelegate
1239+ windowedX: root.leftMargin
1240+ windowedY: PanelState.panelHeight
1241+ windowedWidth: (appContainer.width - root.leftMargin)/2
1242+ windowedHeight: appContainer.height - PanelState.panelHeight
1243+ }
1244+ },
1245+ State {
1246+ name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
1247+ extend: "maximizedLeft"
1248+ PropertyChanges {
1249+ target: appDelegate;
1250+ windowedX: (appContainer.width + root.leftMargin)/2
1251+ }
1252+ },
1253+ State {
1254+ name: "maximizedTopLeft"; when: appDelegate.maximizedTopLeft && !appDelegate.minimized
1255+ extend: "semiMaximized"
1256+ PropertyChanges {
1257+ target: appDelegate
1258+ windowedX: root.leftMargin
1259+ windowedY: PanelState.panelHeight
1260+ windowedWidth: (appContainer.width - root.leftMargin)/2
1261+ windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1262+ }
1263+ },
1264+ State {
1265+ name: "maximizedTopRight"; when: appDelegate.maximizedTopRight && !appDelegate.minimized
1266+ extend: "maximizedTopLeft"
1267+ PropertyChanges {
1268+ target: appDelegate
1269+ windowedX: (appContainer.width + root.leftMargin)/2
1270+ }
1271+ },
1272+ State {
1273+ name: "maximizedBottomLeft"; when: appDelegate.maximizedBottomLeft && !appDelegate.minimized
1274+ extend: "semiMaximized"
1275+ PropertyChanges {
1276+ target: appDelegate
1277+ windowedX: root.leftMargin
1278+ windowedY: (appContainer.height + PanelState.panelHeight)/2
1279+ windowedWidth: (appContainer.width - root.leftMargin)/2
1280+ windowedHeight: appContainer.height/2
1281+ }
1282+ },
1283+ State {
1284+ name: "maximizedBottomRight"; when: appDelegate.maximizedBottomRight && !appDelegate.minimized
1285+ extend: "maximizedBottomLeft"
1286+ PropertyChanges {
1287+ target: appDelegate
1288+ windowedX: (appContainer.width + root.leftMargin)/2
1289+ }
1290+ },
1291+ State {
1292+ name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
1293+ extend: "semiMaximized"
1294+ PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: windowedY;
1295+ requestedWidth: appContainer.width - root.leftMargin; requestedHeight: appDelegate.windowedHeight }
1296+ },
1297+ State {
1298+ name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1299+ extend: "semiMaximized"
1300+ PropertyChanges { target: appDelegate; requestedX: windowedX; requestedY: PanelState.panelHeight;
1301+ requestedWidth: appDelegate.windowedWidth; requestedHeight: appContainer.height - PanelState.panelHeight }
1302+ },
1303+ State {
1304+ name: "minimized"; when: appDelegate.minimized
1305+ PropertyChanges {
1306+ target: appDelegate
1307+ requestedX: -appDelegate.width / 2
1308+ scale: units.gu(5) / appDelegate.width
1309+ opacity: 0;
1310+ visuallyMinimized: true
1311+ visuallyMaximized: false
1312+ }
1313+ }
1314+ ]
1315+ transitions: [
1316+ Transition {
1317+ from: "staged,stagedWithSideStage"; to: "normal"
1318+ enabled: appDelegate.animationsEnabled
1319+ PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1320+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,opacity,requestedWidth,requestedHeight,scale"; duration: priv.animationDuration }
1321+ },
1322+ Transition {
1323+ from: "normal,maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight";
1324+ to: "staged,stagedWithSideStage"
1325+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,requestedWidth,requestedHeight"; duration: priv.animationDuration}
1326+ },
1327+ Transition {
1328+ from: "maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight,minimized";
1329+ to: "normal,restored"
1330+ enabled: appDelegate.animationsEnabled
1331+ PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1332+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,requestedWidth,requestedHeight,windowedWidth,windowedHeight,scale";
1333+ duration: priv.animationDuration }
1334+ },
1335+ Transition {
1336+ to: "minimized"
1337+ enabled: appDelegate.animationsEnabled
1338+ PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1339+ SequentialAnimation {
1340+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
1341+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1342+ ScriptAction {
1343+ script: {
1344+ if (appDelegate.minimized) {
1345+ appDelegate.focus = false;
1346+ priv.focusNext();
1347+ }
1348+ }
1349+ }
1350+ }
1351+ },
1352+ Transition {
1353+ to: "spread"
1354+ // DecoratedWindow wants the scaleToPreviewSize set before enabling scaleToPreview
1355+ PropertyAction { target: appDelegate; properties: "z,visible" }
1356+ PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
1357+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height"; duration: priv.animationDuration }
1358+ UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
1359+ },
1360+ Transition {
1361+ from: "normal,staged"; to: "stagedWithSideStage"
1362+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y"; duration: priv.animationDuration }
1363+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedWidth,requestedHeight"; duration: priv.animationDuration }
1364+ },
1365+ Transition {
1366+ to: "windowedRightEdge"
1367+ ScriptAction {
1368+ script: {
1369+ windowedRightEdgeMaths.startX = appDelegate.requestedX
1370+ windowedRightEdgeMaths.startY = appDelegate.requestedY
1371+
1372+ if (index == 1) {
1373+ var thisRect = { x: appDelegate.windowedX, y: appDelegate.windowedY, width: appDelegate.requestedWidth, height: appDelegate.requestedHeight }
1374+ var otherDelegate = appRepeater.itemAt(0);
1375+ var otherRect = { x: otherDelegate.windowedX, y: otherDelegate.windowedY, width: otherDelegate.requestedWidth, height: otherDelegate.requestedHeight }
1376+ var intersectionRect = MathUtils.intersectionRect(thisRect, otherRect)
1377+ var mappedInterSectionRect = appDelegate.mapFromItem(root, intersectionRect.x, intersectionRect.y)
1378+ opacityEffect.maskX = mappedInterSectionRect.x
1379+ opacityEffect.maskY = mappedInterSectionRect.y
1380+ opacityEffect.maskWidth = intersectionRect.width
1381+ opacityEffect.maskHeight = intersectionRect.height
1382+ }
1383+ }
1384+ }
1385+ },
1386+ Transition {
1387+ from: "stagedRightEdge"; to: "staged"
1388+ enabled: rightEdgeDragArea.cancelled // only transition back to state if the gesture was cancelled, in the other cases we play the focusAnimations.
1389+ SequentialAnimation {
1390+ ParallelAnimation {
1391+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height,width,scale"; duration: priv.animationDuration }
1392+ UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
1393+ }
1394+ // We need to release scaleToPreviewSize at last
1395+ PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
1396+ PropertyAction { target: appDelegate; property: "visible" }
1397+ }
1398+ },
1399+ Transition {
1400+ from: "normal,maximized,maximizedLeft,maximizedRight,maximizedTop,maximizedBottom,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1401+ to: "normal,maximized,maximizedLeft,maximizedRight,maximizedTop,maximizedBottom,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1402+ enabled: appDelegate.animationsEnabled
1403+ SequentialAnimation {
1404+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1405+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,opacity,scale,requestedWidth,requestedHeight,windowedWidth,windowedHeight";
1406+ duration: priv.animationDuration }
1407+ PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1408+ ScriptAction { script: { fakeRectangle.stop(); } }
1409+ }
1410+ }
1411+ ]
1412+
1413+ Binding {
1414+ target: PanelState
1415+ property: "decorationsAlwaysVisible"
1416+ value: appDelegate && appDelegate.maximized && touchControls.overlayShown
1417+ }
1418+
1419+ WindowResizeArea {
1420+ id: resizeArea
1421+ objectName: "windowResizeArea"
1422+
1423+ // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
1424+ anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1425+
1426+ target: appDelegate
1427+ minWidth: units.gu(10)
1428+ minHeight: units.gu(10)
1429+ borderThickness: units.gu(2)
1430+ windowId: model.application.appId // FIXME: Change this to point to windowId once we have such a thing
1431+ screenWidth: appContainer.width
1432+ screenHeight: appContainer.height
1433+ leftMargin: root.leftMargin
1434+ enabled: false
1435+ visible: enabled
1436+
1437+ onPressed: {
1438+ appDelegate.focus = true;
1439+ }
1440+
1441+ Component.onDestruction: {
1442+ saveWindowState();
1443+ }
1444+ }
1445+
1446+ DecoratedWindow {
1447+ id: decoratedWindow
1448+ objectName: "decoratedWindow"
1449+ anchors.left: appDelegate.left
1450+ anchors.top: appDelegate.top
1451+ application: model.application
1452+ surface: model.surface
1453+ active: appDelegate.focus
1454+ focus: true
1455+ interactive: root.interactive
1456+ showDecoration: 1
1457+ maximizeButtonShown: appDelegate.canBeMaximized
1458+ overlayShown: touchControls.overlayShown
1459+ width: implicitWidth
1460+ height: implicitHeight
1461+ highlightSize: windowInfoItem.iconMargin / 2
1462+ stageWidth: appContainer.width
1463+ stageHeight: appContainer.height
1464+
1465+ requestedWidth: appDelegate.requestedWidth
1466+ requestedHeight: appDelegate.requestedHeight
1467+
1468+ property int oldRequestedWidth: -1
1469+ property int oldRequestedHeight: -1
1470+
1471+ onRequestedWidthChanged: oldRequestedWidth = requestedWidth
1472+ onRequestedHeightChanged: oldRequestedHeight = requestedHeight
1473+
1474+ onCloseClicked: { appDelegate.close(); }
1475+ onMaximizeClicked: appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
1476+ onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
1477+ onMaximizeVerticallyClicked: appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
1478+ onMinimizeClicked: appDelegate.minimize()
1479+ onDecorationPressed: { appDelegate.focus = true; }
1480+ onDecorationReleased: fakeRectangle.commit();
1481+
1482+ property real angle: 0
1483+ property real itemScale: 1
1484+ transform: [
1485+ Scale {
1486+ origin.x: 0
1487+ origin.y: decoratedWindow.implicitHeight / 2
1488+ xScale: decoratedWindow.itemScale
1489+ yScale: decoratedWindow.itemScale
1490+ },
1491+ Rotation {
1492+ origin { x: 0; y: (decoratedWindow.height / 2) }
1493+ axis { x: 0; y: 1; z: 0 }
1494+ angle: decoratedWindow.angle
1495+ }
1496+ ]
1497+ }
1498+
1499+ OpacityMask {
1500+ id: opacityEffect
1501+ anchors.fill: decoratedWindow
1502+ }
1503+
1504+ WindowControlsOverlay {
1505+ id: touchControls
1506+ target: appDelegate
1507+ enabled: false
1508+ visible: enabled
1509+ stageWidth: appContainer.width
1510+ stageHeight: appContainer.height
1511+
1512+ onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1513+ onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
1514+ onFakeMaximizeRightAnimationRequested: if (!appDelegate.maximizedRight) fakeRectangle.maximizeRight(amount, true)
1515+ onFakeMaximizeTopLeftAnimationRequested: if (!appDelegate.maximizedTopLeft) fakeRectangle.maximizeTopLeft(amount, true);
1516+ onFakeMaximizeTopRightAnimationRequested: if (!appDelegate.maximizedTopRight) fakeRectangle.maximizeTopRight(amount, true);
1517+ onFakeMaximizeBottomLeftAnimationRequested: if (!appDelegate.maximizedBottomLeft) fakeRectangle.maximizeBottomLeft(amount, true);
1518+ onFakeMaximizeBottomRightAnimationRequested: if (!appDelegate.maximizedBottomRight) fakeRectangle.maximizeBottomRight(amount, true);
1519+ onStopFakeAnimation: fakeRectangle.stop();
1520+ onDragReleased: fakeRectangle.commit();
1521+ }
1522+
1523+ WindowedFullscreenPolicy {
1524+ id: windowedFullscreenPolicy
1525+ active: root.mode == "windowed"
1526+ surface: model.surface
1527+ }
1528+ StagedFullscreenPolicy {
1529+ id: stagedFullscreenPolicy
1530+ active: root.mode == "staged" || root.mode == "stagedWithSideStage"
1531+ surface: model.surface
1532+ }
1533+
1534+ SpreadDelegateInputArea {
1535+ id: dragArea
1536+ objectName: "dragArea"
1537+ anchors.fill: decoratedWindow
1538+ enabled: false
1539+ closeable: !appDelegate.isDash
1540+
1541+ onClicked: {
1542+ spreadItem.highlightedIndex = index;
1543+ if (distance == 0) {
1544+ priv.goneToSpread = false;
1545+ }
1546+ }
1547+ onClose: {
1548+ priv.closingIndex = index
1549+ if (model.surface) { // could be stopped by OOM
1550+ model.surface.close()
1551+ } else if (model.application) {
1552+ root.applicationManager.stopApplication(model.application.appId);
1553+ }
1554+ }
1555+ }
1556+
1557+ WindowInfoItem {
1558+ id: windowInfoItem
1559+ objectName: "windowInfoItem"
1560+ anchors { left: parent.left; top: decoratedWindow.bottom; topMargin: units.gu(1) }
1561+ title: model.application.name
1562+ iconSource: model.application.icon
1563+ height: spreadItem.appInfoHeight
1564+ opacity: 0
1565+ z: 1
1566+ visible: opacity > 0
1567+ maxWidth: {
1568+ var nextApp = appRepeater.itemAt(index + 1);
1569+ if (nextApp) {
1570+ return nextApp.x - appDelegate.x - units.gu(1)
1571+ }
1572+ return appDelegate.width;
1573+ }
1574+
1575+ onClicked: {
1576+ spreadItem.highlightedIndex = index;
1577+ priv.goneToSpread = false;
1578+ }
1579+ }
1580+
1581+ Image {
1582+ id: closeImage
1583+ anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
1584+ source: "graphics/window-close.svg"
1585+ readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1586+ visible: !appDelegate.isDash
1587+ && index == spreadItem.highlightedIndex
1588+ && mousePos.y < (decoratedWindow.height / 3)
1589+ && mousePos.y > -units.gu(4)
1590+ && mousePos.x > -units.gu(4)
1591+ && mousePos.x < (decoratedWindow.width * 2 / 3)
1592+ height: units.gu(2)
1593+ width: height
1594+ sourceSize.width: width
1595+ sourceSize.height: height
1596+
1597+ MouseArea {
1598+ id: closeMouseArea
1599+ objectName: "closeMouseArea"
1600+ anchors.fill: closeImage
1601+ anchors.margins: -units.gu(2)
1602+ onClicked: {
1603+ priv.closingIndex = index;
1604+ appDelegate.close();
1605+ }
1606+ }
1607+ }
1608+ }
1609+ }
1610+ }
1611+
1612+ FakeMaximizeDelegate {
1613+ id: fakeRectangle
1614+ target: priv.focusedAppDelegate
1615+ leftMargin: root.leftMargin
1616+ appContainerWidth: appContainer.width
1617+ appContainerHeight: appContainer.height
1618+ }
1619+
1620+ EdgeBarrier {
1621+ id: edgeBarrier
1622+
1623+ // NB: it does its own positioning according to the specified edge
1624+ edge: Qt.RightEdge
1625+
1626+ onPassed: priv.goneToSpread = true;
1627+
1628+ material: Component {
1629+ Item {
1630+ Rectangle {
1631+ width: parent.height
1632+ height: parent.width
1633+ rotation: 90
1634+ anchors.centerIn: parent
1635+ gradient: Gradient {
1636+ GradientStop { position: 0.0; color: Qt.rgba(0.16,0.16,0.16,0.5)}
1637+ GradientStop { position: 1.0; color: Qt.rgba(0.16,0.16,0.16,0)}
1638+ }
1639+ }
1640+ }
1641+ }
1642+ }
1643+
1644+ MouseArea {
1645+ id: hoverMouseArea
1646+ objectName: "hoverMouseArea"
1647+ anchors.fill: appContainer
1648+ propagateComposedEvents: true
1649+ hoverEnabled: true
1650+ enabled: false
1651+ visible: enabled
1652+
1653+ property int scrollAreaWidth: width / 3
1654+ property bool progressiveScrollingEnabled: false
1655+
1656+ onMouseXChanged: {
1657+ mouse.accepted = false
1658+
1659+ if (hoverMouseArea.pressed) {
1660+ return;
1661+ }
1662+
1663+ // Find the hovered item and mark it active
1664+ var mapped = mapToItem(appContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1665+ var itemUnder = appContainer.childAt(mapped.x, mapped.y)
1666+ if (itemUnder) {
1667+ mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1668+ var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
1669+ if (delegateChild && (delegateChild.objectName === "dragArea" || delegateChild.objectName === "windowInfoItem")) {
1670+ spreadItem.highlightedIndex = appRepeater.indexOf(itemUnder)
1671+ }
1672+ }
1673+
1674+ if (floatingFlickable.contentWidth > floatingFlickable.width) {
1675+ var margins = floatingFlickable.width * 0.05;
1676+
1677+ if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
1678+ progressiveScrollingEnabled = true
1679+ }
1680+
1681+ // do we need to scroll?
1682+ if (mouseX < scrollAreaWidth + margins) {
1683+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
1684+ var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
1685+ floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
1686+ }
1687+ if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
1688+ var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
1689+ var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
1690+ floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
1691+ }
1692+ }
1693+ }
1694+
1695+ onPressed: mouse.accepted = false
1696+ }
1697+
1698+ FloatingFlickable {
1699+ id: floatingFlickable
1700+ objectName: "spreadFlickable"
1701+ anchors.fill: appContainer
1702+ enabled: false
1703+ contentWidth: spreadItem.spreadTotalWidth
1704+
1705+ function snap(toIndex) {
1706+ var delegate = appRepeater.itemAt(toIndex)
1707+ var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
1708+ if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
1709+ var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
1710+ snapAnimation.to = floatingFlickable.contentX - offset;
1711+ snapAnimation.start();
1712+ } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
1713+ var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
1714+ snapAnimation.to = floatingFlickable.contentX - offset;
1715+ snapAnimation.start();
1716+ }
1717+ }
1718+ UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
1719+ }
1720+
1721+ PropertyAnimation {
1722+ id: shortRightEdgeSwipeAnimation
1723+ property: "x"
1724+ to: 0
1725+ duration: priv.animationDuration
1726+ }
1727+
1728+ SwipeArea {
1729+ id: rightEdgeDragArea
1730+ objectName: "rightEdgeDragArea"
1731+ direction: Direction.Leftwards
1732+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
1733+ width: root.dragAreaWidth
1734+
1735+ property var gesturePoints: []
1736+ property bool cancelled: false
1737+
1738+ property real progress: dragging ? -touchPosition.x / root.width : 0
1739+ onProgressChanged: {
1740+ if (dragging) {
1741+ draggedProgress = progress;
1742+ }
1743+ }
1744+
1745+ property real draggedProgress: 0
1746+
1747+ onTouchPositionChanged: {
1748+ gesturePoints.push(touchPosition.x);
1749+ if (gesturePoints.length > 10) {
1750+ gesturePoints.splice(0, gesturePoints.length - 10)
1751+ }
1752+ }
1753+
1754+ onDraggingChanged: {
1755+ if (dragging) {
1756+ // A potential edge-drag gesture has started. Start recording it
1757+ gesturePoints = [];
1758+ cancelled = false;
1759+ draggedProgress = 0;
1760+ } else {
1761+ // Ok. The user released. Did he drag far enough to go to full spread?
1762+ if (gesturePoints[gesturePoints.length - 1] < -spreadItem.rightEdgeBreakPoint * spreadItem.width ) {
1763+
1764+ // He dragged far enough, but if the last movement was a flick to the right again, he wants to cancel the spread again.
1765+ var oneWayFlickToRight = true;
1766+ var smallestX = gesturePoints[0]-1;
1767+ for (var i = 0; i < gesturePoints.length; i++) {
1768+ if (gesturePoints[i] <= smallestX) {
1769+ oneWayFlickToRight = false;
1770+ break;
1771+ }
1772+ smallestX = gesturePoints[i];
1773+ }
1774+
1775+ if (!oneWayFlickToRight) {
1776+ // Ok, the user made it, let's go to spread!
1777+ priv.goneToSpread = true;
1778+ } else {
1779+ cancelled = true;
1780+ }
1781+ } else {
1782+ // Ok, the user didn't drag far enough to cross the breakPoint
1783+ // Find out if it was a one-way movement to the left, in which case we just switch directly to next app.
1784+ var oneWayFlick = true;
1785+ var smallestX = rightEdgeDragArea.width;
1786+ for (var i = 0; i < gesturePoints.length; i++) {
1787+ if (gesturePoints[i] >= smallestX) {
1788+ oneWayFlick = false;
1789+ break;
1790+ }
1791+ smallestX = gesturePoints[i];
1792+ }
1793+
1794+ if (appRepeater.count > 1 &&
1795+ (oneWayFlick && rightEdgeDragArea.distance > units.gu(2) || rightEdgeDragArea.distance > spreadItem.rightEdgeBreakPoint * spreadItem.width)) {
1796+ var nextStage = appRepeater.itemAt(priv.nextInStack).stage
1797+ for (var i = 0; i < appRepeater.count; i++) {
1798+ if (i != priv.nextInStack && appRepeater.itemAt(i).stage == nextStage) {
1799+ appRepeater.itemAt(i).playHidingAnimation()
1800+ break;
1801+ }
1802+ }
1803+ appRepeater.itemAt(priv.nextInStack).playFocusAnimation()
1804+ if (appRepeater.itemAt(priv.nextInStack).stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
1805+ sideStage.show();
1806+ }
1807+
1808+ } else {
1809+ cancelled = true;
1810+ }
1811+
1812+ gesturePoints = [];
1813+ }
1814+ }
1815+ }
1816+ }
1817+
1818+ TabletSideStageTouchGesture {
1819+ id: triGestureArea
1820+ objectName: "triGestureArea"
1821+ anchors.fill: parent
1822+ enabled: false
1823+ property Item appDelegate
1824+
1825+ dragComponent: dragComponent
1826+ dragComponentProperties: { "appDelegate": appDelegate }
1827+
1828+ onPressed: {
1829+ function matchDelegate(obj) { return String(obj.objectName).indexOf("appDelegate") >= 0; }
1830+
1831+ var delegateAtCenter = Functions.itemAt(appContainer, x, y, matchDelegate);
1832+ if (!delegateAtCenter) return;
1833+
1834+ appDelegate = delegateAtCenter;
1835+ }
1836+
1837+ onClicked: {
1838+ if (sideStage.shown) {
1839+ sideStage.hide();
1840+ } else {
1841+ sideStage.show();
1842+ priv.updateMainAndSideStageIndexes()
1843+ }
1844+ }
1845+
1846+ onDragStarted: {
1847+ // If we're dragging to the sidestage.
1848+ if (!sideStage.shown) {
1849+ sideStage.show();
1850+ }
1851+ }
1852+
1853+ Component {
1854+ id: dragComponent
1855+ SurfaceContainer {
1856+ property Item appDelegate
1857+
1858+ surface: appDelegate ? appDelegate.surface : null
1859+
1860+ consumesInput: false
1861+ interactive: false
1862+ focus: false
1863+ requestedWidth: appDelegate.requestedWidth
1864+ requestedHeight: appDelegate.requestedHeight
1865+
1866+ width: units.gu(40)
1867+ height: units.gu(40)
1868+
1869+ Drag.hotSpot.x: width/2
1870+ Drag.hotSpot.y: height/2
1871+ // only accept opposite stage.
1872+ Drag.keys: {
1873+ if (!surface) return "Disabled";
1874+ if (appDelegate.isDash) return "Disabled";
1875+
1876+ if (appDelegate.stage === ApplicationInfo.MainStage) {
1877+ if (appDelegate.application.supportedOrientations
1878+ & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
1879+ return "MainStage";
1880+ }
1881+ return "Disabled";
1882+ }
1883+ return "SideStage";
1884+ }
1885+ }
1886+ }
1887+ }
1888+}
qml/Stage/StageMaths.qmlnew file+79
@@ -0,0 +1,79 @@
1+import QtQuick 2.4
2+import Unity.Application 0.1
3+import Ubuntu.Components 1.3
4+
5+QtObject {
6+ id: root
7+
8+ // input
9+ property int itemIndex: 0
10+ property int nextInStack: 0
11+ property int sceneWidth: 0
12+ property int sideStageWidth: 0
13+ property int sideStageX: sceneWidth
14+ property bool animateX: false
15+ property int leftEdgeDragProgress: 0
16+
17+ property int stage: ApplicationInfoInterface.MainStage
18+ property var thisDelegate: null
19+ property var mainStageDelegate: null
20+ property var sideStageDelegate: null
21+
22+ // output
23+
24+ // We need to shuffle z ordering a bit in order to keep side stage apps above main stage apps.
25+ // We don't want to really reorder them in the model because that allows us to keep track
26+ // of the last focused order.
27+ readonly property int itemZ: {
28+ // only shuffle when we've got a main and side stage
29+ if (thisDelegate.isDash && thisDelegate != mainStageDelegate && leftEdgeDragProgress > 0) {
30+ return -1; // Keep the dash behind all other apps for the left edge gesture
31+ }
32+
33+ if (!sideStageDelegate) return itemIndex;
34+
35+ // don't shuffle indexes greater than "actives or next"
36+ if (itemIndex > 2) return itemIndex;
37+
38+ if (thisDelegate == mainStageDelegate) {
39+ // Active main stage always at 0
40+ return 0;
41+ }
42+
43+ if (nextInStack > 0) {
44+ var stageOfNextInStack = appRepeater.itemAt(nextInStack).stage;
45+
46+ if (itemIndex === nextInStack) {
47+ // this is the next app in stack.
48+
49+ if (stage === ApplicationInfoInterface.SideStage) {
50+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
51+ return Math.min(2, topLevelSurfaceList.count-1);
52+ }
53+ return 1;
54+ }
55+ if (stageOfNextInStack === ApplicationInfoInterface.SideStage) {
56+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
57+ return 1;
58+ }
59+ return Math.min(2, topLevelSurfaceList.count-1);
60+ }
61+ return Math.min(index+1, topLevelSurfaceList.count-1);
62+ }
63+
64+
65+ property int itemX: {
66+ if (mainStageDelegate == thisDelegate) {
67+ return thisDelegate.isDash ? 0 : leftEdgeDragProgress;
68+ }
69+ if (sideStageDelegate == thisDelegate) {
70+ return sideStageX;
71+ }
72+ return thisDelegate.isDash && leftEdgeDragProgress > 0 ? 0 : sceneWidth;
73+ }
74+ Behavior on itemX { enabled: root.animateX; UbuntuNumberAnimation {} }
75+
76+ readonly property int itemWidth: stage == ApplicationInfoInterface.MainStage ?
77+ sideStageDelegate != null ? sideStageX : sceneWidth :
78+ stage == ApplicationInfoInterface.SideStage ? sideStageWidth : sceneWidth
79+}
qml/Stages/StagedFullscreenPolicy.qml → qml/Stage/StagedFullscreenPolicy.qmlrenamed

The content is the same.

qml/Stages/SurfaceContainer.qml → qml/Stage/SurfaceContainer.qmlrenamed+5−52
@@ -23,6 +23,8 @@ import Unity.Application 0.1 // for MirSurfaceItem
23FocusScope {
23FocusScope {
24 id: root
24 id: root
25 objectName: "surfaceContainer"
25 objectName: "surfaceContainer"
26+ implicitWidth: surfaceItem.implicitWidth
27+ implicitHeight: surfaceItem.implicitHeight
26
28
27 // Must be set from outside
29 // Must be set from outside
28 property var surface: null
30 property var surface: null
@@ -32,7 +34,6 @@ FocusScope {
32 property int requestedHeight: -1
34 property int requestedHeight: -1
33 property bool interactive
35 property bool interactive
34 property int surfaceOrientationAngle: 0
36 property int surfaceOrientationAngle: 0
35− property bool resizeSurface: true
36 property bool isPromptSurface: false
37 property bool isPromptSurface: false
37 // FIME - dont export, use interactive property. Need to fix qtmir to handle consumesInputChanged
38 // FIME - dont export, use interactive property. Need to fix qtmir to handle consumesInputChanged
38 // to update surface activeFocus. See mock MirSurfaceItem.
39 // to update surface activeFocus. See mock MirSurfaceItem.
@@ -58,35 +59,15 @@ FocusScope {
58 MirSurfaceItem {
59 MirSurfaceItem {
59 id: surfaceItem
60 id: surfaceItem
60 objectName: "surfaceItem"
61 objectName: "surfaceItem"
62+ anchors.fill: parent
61
63
62 focus: true
64 focus: true
63
65
64 fillMode: MirSurfaceItem.PadOrCrop
66 fillMode: MirSurfaceItem.PadOrCrop
65 consumesInput: true
67 consumesInput: true
66
68
67− surfaceWidth: {
68− if (root.resizeSurface) {
69− if (root.requestedWidth >= 0) {
69+ surfaceWidth: root.requestedWidth
70− return root.requestedWidth;
71− } else {
72− return width;
73− }
74− } else {
75− return -1;
76− }
77− }
78−
79− surfaceHeight: {
80− if (root.resizeSurface) {
81− if (root.requestedHeight >= 0) {
70+ surfaceHeight: root.requestedHeight
82− return root.requestedHeight;
83− } else {
84− return height;
85− }
86− } else {
87− return -1;
88− }
89− }
90
71
91 enabled: root.interactive
72 enabled: root.interactive
92 antialiasing: !root.interactive
73 antialiasing: !root.interactive
@@ -99,34 +80,6 @@ FocusScope {
99 enabled: surfaceItem.enabled
80 enabled: surfaceItem.enabled
100 }
81 }
101
82
102− // MirSurface size drives SurfaceContainer size
103− Binding {
104− target: surfaceItem; property: "width"; value: root.surface ? root.surface.size.width : 0
105− when: root.requestedWidth >= 0 && root.surface
106− }
107− Binding {
108− target: surfaceItem; property: "height"; value: root.surface ? root.surface.size.height : 0
109− when: root.requestedHeight >= 0 && root.surface
110− }
111− Binding {
112− target: root; property: "width"; value: surfaceItem.width
113− when: root.requestedWidth >= 0
114− }
115− Binding {
116− target: root; property: "height"; value: surfaceItem.height
117− when: root.requestedHeight >= 0
118− }
119−
120− // SurfaceContainer size drives MirSurface size
121− Binding {
122− target: surfaceItem; property: "width"; value: root.width
123− when: root.requestedWidth < 0
124− }
125− Binding {
126− target: surfaceItem; property: "height"; value: root.height
127− when: root.requestedHeight < 0
128− }
129−
130 Loader {
83 Loader {
131 id: animationsLoader
84 id: animationsLoader
132 objectName: "animationsLoader"
85 objectName: "animationsLoader"
qml/Stages/TabletSideStageTouchGesture.qml → qml/Stage/TabletSideStageTouchGesture.qmlrenamed

The content is the same.

qml/Stages/TabletStage.qml → qml/Stage/TabletStage.qmlrenamed

The content is the same.

qml/Stages/TopLevelSurfaceRepeater.qml → qml/Stage/TopLevelSurfaceRepeater.qmlrenamed+9
@@ -55,4 +55,13 @@ Repeater {
55 startingUp = false;
55 startingUp = false;
56 }
56 }
57 }
57 }
58+
59+ function indexOf(delegateItem) {
60+ for (var i = 0; i < count; i++) {
61+ if (itemAt(i) === delegateItem) {
62+ return i;
63+ }
64+ }
65+ return -1;
66+ }
58}
67}
qml/Stages/TransformedSpreadDelegate.qml → qml/Stage/TransformedSpreadDelegate.qmlrenamed

The content is the same.

qml/Stages/TransformedTabletSpreadDelegate.qml → qml/Stage/TransformedTabletSpreadDelegate.qmlrenamed

The content is the same.

qml/Stages/WindowControlsOverlay.qml → qml/Stage/WindowControlsOverlay.qmlrenamed

The content is the same.

qml/Stages/WindowDecoration.qml → qml/Stage/WindowDecoration.qmlrenamed+1−1
@@ -109,7 +109,7 @@ MouseArea {
109 onMaximizeClicked: root.maximizeClicked();
109 onMaximizeClicked: root.maximizeClicked();
110 onMaximizeHorizontallyClicked: if (root.target.canBeMaximizedHorizontally) root.maximizeHorizontallyClicked();
110 onMaximizeHorizontallyClicked: if (root.target.canBeMaximizedHorizontally) root.maximizeHorizontallyClicked();
111 onMaximizeVerticallyClicked: if (root.target.canBeMaximizedVertically) root.maximizeVerticallyClicked();
111 onMaximizeVerticallyClicked: if (root.target.canBeMaximizedVertically) root.maximizeVerticallyClicked();
112− closeButtonShown: root.target.application.appId !== "unity8-dash"
112+ closeButtonShown: root.target.appId !== "unity8-dash"
113 }
113 }
114
114
115 Item {
115 Item {
qml/Stage/WindowInfoItem.qmlnew file+53
@@ -0,0 +1,53 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+
4+Item {
5+ id: root
6+ implicitWidth: Math.max(iconShape.width, titleLabel.width)
7+ implicitHeight: iconShape.height + titleLabel.height + labelMargin + iconMargin
8+ property alias title: titleLabel.text
9+ property alias iconSource: icon.source
10+
11+ property real iconHeight: (height - titleLabel.height) * 0.65
12+ property real iconMargin: (height - titleLabel.height) * 0.25
13+ property real labelMargin: (height - titleLabel.height) * 0.1
14+ property int maxWidth: units.gu(10)
15+
16+ signal clicked()
17+
18+ ProportionalShape {
19+ id: iconShape
20+ anchors {
21+ top: parent.top
22+ topMargin: iconMargin
23+ left: parent.left
24+ }
25+ height: iconHeight
26+ borderSource: "undefined"
27+ aspect: UbuntuShape.Flat
28+ source: Image {
29+ id: icon
30+ sourceSize.width: iconShape.width
31+ sourceSize.height: iconShape.height
32+ cache: false // see lpbug#1543290 why no cache
33+ }
34+ }
35+
36+ MouseArea {
37+ anchors.fill: iconShape
38+ onClicked: root.clicked()
39+ }
40+
41+ Label {
42+ id: titleLabel
43+ anchors {
44+ left: iconShape.left
45+ top: iconShape.bottom
46+ topMargin: labelMargin
47+ }
48+ width: root.maxWidth
49+ fontSize: 'small'
50+ color: 'white'
51+ elide: Label.ElideRight
52+ }
53+}
qml/Stages/WindowResizeArea.qml → qml/Stage/WindowResizeArea.qmlrenamed+32−31
@@ -75,14 +75,15 @@ MouseArea {
75
75
76 function loadWindowState() {
76 function loadWindowState() {
77 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
77 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
78− Qt.rect(target.requestedX, target.requestedY, defaultWidth, defaultHeight));
78+ Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
79
79
80+
80− target.requestedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
81+ target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
81− target.requestedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
82+ target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
82 root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
83 root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
83− target.requestedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.requestedWidth),
84+ target.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.windowedWidth),
84 (target.fullscreen ? 0 : root.leftMargin)); });
85 (target.fullscreen ? 0 : root.leftMargin)); });
85− target.requestedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight); });
86+ target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.windowedHeight), PanelState.panelHeight); });
86
87
87 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
88 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
88 target.restore(false /* animated */, windowState);
89 target.restore(false /* animated */, windowState);
@@ -111,28 +112,28 @@ MouseArea {
111
112
112 readonly property int minimumWidth: root.target ? Math.max(root.minWidth, root.target.minimumWidth) : root.minWidth
113 readonly property int minimumWidth: root.target ? Math.max(root.minWidth, root.target.minimumWidth) : root.minWidth
113 onMinimumWidthChanged: {
114 onMinimumWidthChanged: {
114− if (target.requestedWidth < minimumWidth) {
115+ if (target.windowedWidth < minimumWidth) {
115− target.requestedWidth = minimumWidth;
116+ target.windowedWidth = minimumWidth;
116 }
117 }
117 }
118 }
118 readonly property int minimumHeight: root.target ? Math.max(root.minHeight, root.target.minimumHeight) : root.minHeight
119 readonly property int minimumHeight: root.target ? Math.max(root.minHeight, root.target.minimumHeight) : root.minHeight
119 onMinimumHeightChanged: {
120 onMinimumHeightChanged: {
120− if (target.requestedHeight < minimumHeight) {
121+ if (target.windowedHeight < minimumHeight) {
121− target.requestedHeight = minimumHeight;
122+ target.windowedHeight = minimumHeight;
122 }
123 }
123 }
124 }
124 readonly property int maximumWidth: root.target && root.target.maximumWidth >= minimumWidth && root.target.maximumWidth > 0
125 readonly property int maximumWidth: root.target && root.target.maximumWidth >= minimumWidth && root.target.maximumWidth > 0
125 ? root.target.maximumWidth : maxSafeInt
126 ? root.target.maximumWidth : maxSafeInt
126 onMaximumWidthChanged: {
127 onMaximumWidthChanged: {
127− if (target.requestedWidth > maximumWidth) {
128+ if (target.windowedWidth > maximumWidth) {
128− target.requestedWidth = maximumWidth;
129+ target.windowedWidth = maximumWidth;
129 }
130 }
130 }
131 }
131 readonly property int maximumHeight: root.target && root.target.maximumHeight >= minimumHeight && root.target.maximumHeight > 0
132 readonly property int maximumHeight: root.target && root.target.maximumHeight >= minimumHeight && root.target.maximumHeight > 0
132 ? root.target.maximumHeight : maxSafeInt
133 ? root.target.maximumHeight : maxSafeInt
133 onMaximumHeightChanged: {
134 onMaximumHeightChanged: {
134− if (target.requestedHeight > maximumHeight) {
135+ if (target.windowedHeight > maximumHeight) {
135− target.requestedHeight = maximumHeight;
136+ target.windowedHeight = maximumHeight;
136 }
137 }
137 }
138 }
138 readonly property int widthIncrement: {
139 readonly property int widthIncrement: {
@@ -247,8 +248,8 @@ MouseArea {
247 var pos = mapToItem(root.target.parent, mouseX, mouseY);
248 var pos = mapToItem(root.target.parent, mouseX, mouseY);
248 d.startMousePosX = pos.x;
249 d.startMousePosX = pos.x;
249 d.startMousePosY = pos.y;
250 d.startMousePosY = pos.y;
250− d.startX = target.requestedX;
251+ d.startX = target.windowedX;
251− d.startY = target.requestedY;
252+ d.startY = target.windowedY;
252 d.startWidth = target.width;
253 d.startWidth = target.width;
253 d.startHeight = target.height;
254 d.startHeight = target.height;
254 d.currentWidth = target.width;
255 d.currentWidth = target.width;
@@ -285,53 +286,53 @@ MouseArea {
285
286
286 if (d.leftBorder) {
287 if (d.leftBorder) {
287 var newTargetX = d.startX + deltaX;
288 var newTargetX = d.startX + deltaX;
288− var rightBorderX = target.requestedX + target.width;
289+ var rightBorderX = target.windowedX + target.width;
289 if (rightBorderX > newTargetX + d.minimumWidth) {
290 if (rightBorderX > newTargetX + d.minimumWidth) {
290 if (rightBorderX < newTargetX + d.maximumWidth) {
291 if (rightBorderX < newTargetX + d.maximumWidth) {
291− target.requestedWidth = rightBorderX - newTargetX;
292+ target.windowedWidth = rightBorderX - newTargetX;
292 } else {
293 } else {
293− target.requestedWidth = d.maximumWidth;
294+ target.windowedWidth = d.maximumWidth;
294 }
295 }
295 } else {
296 } else {
296− target.requestedWidth = d.minimumWidth;
297+ target.windowedWidth = d.minimumWidth;
297 }
298 }
298
299
299 } else if (d.rightBorder) {
300 } else if (d.rightBorder) {
300 var newWidth = d.startWidth + deltaX;
301 var newWidth = d.startWidth + deltaX;
301 if (newWidth > d.minimumWidth) {
302 if (newWidth > d.minimumWidth) {
302 if (newWidth < d.maximumWidth) {
303 if (newWidth < d.maximumWidth) {
303− target.requestedWidth = newWidth;
304+ target.windowedWidth = newWidth;
304 } else {
305 } else {
305− target.requestedWidth = d.maximumWidth;
306+ target.windowedWidth = d.maximumWidth;
306 }
307 }
307 } else {
308 } else {
308− target.requestedWidth = d.minimumWidth;
309+ target.windowedWidth = d.minimumWidth;
309 }
310 }
310 }
311 }
311
312
312 if (d.topBorder) {
313 if (d.topBorder) {
313 var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
314 var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
314− var bottomBorderY = target.requestedY + target.height;
315+ var bottomBorderY = target.windowedY + target.height;
315 if (bottomBorderY > newTargetY + d.minimumHeight) {
316 if (bottomBorderY > newTargetY + d.minimumHeight) {
316 if (bottomBorderY < newTargetY + d.maximumHeight) {
317 if (bottomBorderY < newTargetY + d.maximumHeight) {
317− target.requestedHeight = bottomBorderY - newTargetY;
318+ target.windowedHeight = bottomBorderY - newTargetY;
318 } else {
319 } else {
319− target.requestedHeight = d.maximumHeight;
320+ target.windowedHeight = d.maximumHeight;
320 }
321 }
321 } else {
322 } else {
322− target.requestedHeight = d.minimumHeight;
323+ target.windowedHeight = d.minimumHeight;
323 }
324 }
324
325
325 } else if (d.bottomBorder) {
326 } else if (d.bottomBorder) {
326 var newHeight = d.startHeight + deltaY;
327 var newHeight = d.startHeight + deltaY;
327 if (newHeight > d.minimumHeight) {
328 if (newHeight > d.minimumHeight) {
328 if (newHeight < d.maximumHeight) {
329 if (newHeight < d.maximumHeight) {
329− target.requestedHeight = newHeight;
330+ target.windowedHeight = newHeight;
330 } else {
331 } else {
331− target.requestedHeight = d.maximumHeight;
332+ target.windowedHeight = d.maximumHeight;
332 }
333 }
333 } else {
334 } else {
334− target.requestedHeight = d.minimumHeight;
335+ target.windowedHeight = d.minimumHeight;
335 }
336 }
336 }
337 }
337 }
338 }
@@ -340,13 +341,13 @@ MouseArea {
340 target: root.target
341 target: root.target
341 onWidthChanged: {
342 onWidthChanged: {
342 if (d.moveLeftBorder) {
343 if (d.moveLeftBorder) {
343− target.requestedX += d.currentWidth - target.width;
344+ target.windowedX += d.currentWidth - target.width;
344 }
345 }
345 d.currentWidth = target.width;
346 d.currentWidth = target.width;
346 }
347 }
347 onHeightChanged: {
348 onHeightChanged: {
348 if (d.moveTopBorder) {
349 if (d.moveTopBorder) {
349− target.requestedY += d.currentHeight - target.height;
350+ target.windowedY += d.currentHeight - target.height;
350 }
351 }
351 d.currentHeight = target.height;
352 d.currentHeight = target.height;
352 }
353 }
qml/Stages/WindowedFullscreenPolicy.qml → qml/Stage/WindowedFullscreenPolicy.qmlrenamed

The content is the same.

qml/Stages/graphics/PageHeaderBaseDividerBottom@18.png → qml/Stage/graphics/PageHeaderBaseDividerBottom@18.pngrenamed

Binary file not shown.

qml/Stages/graphics/PageHeaderBaseDividerLight@18.png → qml/Stage/graphics/PageHeaderBaseDividerLight@18.pngrenamed

Binary file not shown.

qml/Stages/graphics/PageHeaderBaseDividerLight@18.sci → qml/Stage/graphics/PageHeaderBaseDividerLight@18.scirenamed

The content is the same.

qml/Stages/graphics/arrows-centre.png → qml/Stage/graphics/arrows-centre.pngrenamed

Binary file not shown.

qml/Stages/graphics/arrows.png → qml/Stage/graphics/arrows.pngrenamed

Binary file not shown.

qml/Stages/graphics/sidestage_drag.svg → qml/Stage/graphics/sidestage_drag.svgrenamed

The content is the same.

qml/Stages/graphics/sidestage_handle@20.png → qml/Stage/graphics/sidestage_handle@20.pngrenamed

Binary file not shown.

qml/Stages/graphics/sidestage_handle@20.sci → qml/Stage/graphics/sidestage_handle@20.scirenamed

The content is the same.

qml/Stages/graphics/sidestage_open.svg → qml/Stage/graphics/sidestage_open.svgrenamed

The content is the same.

qml/Stages/graphics/window-close.svg → qml/Stage/graphics/window-close.svgrenamed

The content is the same.

qml/Stages/DecoratedWindow.qmldeleted−196
@@ -1,196 +0,0 @@
1−/*
2− * Copyright (C) 2014-2016 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.4
18−import Ubuntu.Components 1.3
19−import Unity.Application 0.1
20−import Unity.ApplicationMenu 0.1
21−import Unity.Indicators 0.1 as Indicators
22−import "../Components/PanelState"
23−
24−FocusScope {
25− id: root
26−
27− width: !counterRotate ? applicationWindow.width : applicationWindow.height
28− height: visibleDecorationHeight + (!counterRotate ? applicationWindow.height : applicationWindow.width)
29−
30− property alias application: applicationWindow.application
31− property alias surface: applicationWindow.surface
32− readonly property alias focusedSurface: applicationWindow.focusedSurface
33− property alias active: decoration.active
34− readonly property alias title: applicationWindow.title
35− property alias fullscreen: applicationWindow.fullscreen
36− property alias maximizeButtonShown: decoration.maximizeButtonShown
37−
38− readonly property bool decorationShown: !fullscreen
39− property bool highlightShown: false
40− property real shadowOpacity: 1
41−
42− property real requestedWidth
43− property real requestedHeight
44−
45− property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
46− readonly property real visibleDecorationHeight: root.decorationShown ? decoration.height : 0
47− readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
48−
49− readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
50− readonly property int minimumHeight: visibleDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
51− readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
52− readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
53− + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
54− readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
55− readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
56−
57− property alias overlayShown: decoration.overlayShown
58− property alias stageWidth: moveHandler.stageWidth
59− property alias stageHeight: moveHandler.stageHeight
60− readonly property alias dragging: moveHandler.dragging
61−
62− readonly property Item clientAreaItem: applicationWindow
63−
64− signal closeClicked()
65− signal maximizeClicked()
66− signal maximizeHorizontallyClicked()
67− signal maximizeVerticallyClicked()
68− signal minimizeClicked()
69− signal decorationPressed()
70− signal decorationReleased()
71−
72− Rectangle {
73− id: selectionHighlight
74− anchors.fill: parent
75− anchors.margins: -units.gu(1)
76− color: "white"
77− opacity: highlightShown ? 0.15 : 0
78− }
79−
80− Rectangle {
81− anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
82− height: units.dp(2)
83− color: theme.palette.normal.focus
84− visible: highlightShown
85− }
86−
87− BorderImage {
88− anchors {
89− fill: root
90− margins: active ? -units.gu(2) : -units.gu(1.5)
91− }
92− source: "graphics/dropshadow2gu.sci"
93− opacity: root.shadowOpacity * .3
94− visible: !fullscreen
95− }
96−
97− ApplicationWindow {
98− id: applicationWindow
99− objectName: "appWindow"
100− anchors.top: parent.top
101− anchors.topMargin: decoration.height
102− anchors.left: parent.left
103− readonly property real requestedHeightMinusDecoration: root.requestedHeight - root.visibleDecorationHeight
104− requestedHeight: !counterRotate ? requestedHeightMinusDecoration : root.requestedWidth
105− requestedWidth: !counterRotate ? root.requestedWidth : requestedHeightMinusDecoration
106− interactive: true
107− focus: true
108−
109− transform: Rotation {
110− readonly property int rotationAngle: applicationWindow.application &&
111− applicationWindow.application.rotatesWindowContents
112− ? ((360 - applicationWindow.surfaceOrientationAngle) % 360) : 0
113− origin.x: {
114− if (rotationAngle == 90) return applicationWindow.height / 2;
115− else if (rotationAngle == 270) return applicationWindow.width / 2;
116− else if (rotationAngle == 180) return applicationWindow.width / 2;
117− else return 0;
118− }
119− origin.y: {
120− if (rotationAngle == 90) return applicationWindow.height / 2;
121− else if (rotationAngle == 270) return applicationWindow.width / 2;
122− else if (rotationAngle == 180) return applicationWindow.height / 2;
123− else return 0;
124− }
125− angle: rotationAngle
126− }
127− }
128−
129− MouseArea {
130− anchors { left: parent.left; top: parent.top; right: parent.right }
131− height: units.gu(3)
132−
133− drag.target: Item {}
134− drag.filterChildren: true
135− drag.threshold: 0
136−
137− onPressed: root.decorationPressed();
138− onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
139− onPositionChanged: moveHandler.handlePositionChanged(mouse)
140− onReleased: {
141− root.decorationReleased();
142− moveHandler.handleReleased();
143− }
144−
145− WindowDecoration {
146− id: decoration
147− target: root.parent
148− objectName: "appWindowDecoration"
149− anchors.fill: parent
150− title: applicationWindow.title
151− visible: root.decorationShown
152−
153− onCloseClicked: root.closeClicked();
154− onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
155− onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
156− onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
157− onMinimizeClicked: root.minimizeClicked();
158−
159− enableMenus: active &&
160− (PanelState.focusedPersistentSurfaceId !== surface.persistentId ||
161− (PanelState.focusedPersistentSurfaceId === surface.persistentId && !PanelState.focusedSurfaceMaximized))
162− menu: sharedAppModel.model
163−
164− Indicators.SharedUnityMenuModel {
165− id: sharedAppModel
166− property var menus: surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : []
167− property var menuService: menus.length > 0 ? menus[0] : null
168−
169− busName: menuService ? menuService.service : ""
170− menuObjectPath: menuService && menuService.menuPath ? menuService.menuPath : ""
171− actions: menuService && menuService.actionPath ? { "unity": menuService.actionPath } : {}
172− }
173−
174− Connections {
175− target: ApplicationMenuRegistry
176− onSurfaceMenuRegistered: {
177− if (surface && surfaceId === surface.persistentId) {
178− sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
179− }
180− }
181− onSurfaceMenuUnregistered: {
182− if (surface && surfaceId === surface.persistentId) {
183− sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
184− }
185− }
186− }
187− }
188− }
189−
190− MoveHandler {
191− id: moveHandler
192− objectName: "moveHandler"
193− target: root.parent
194− buttonsWidth: decoration.buttonsWidth
195− }
196−}
qml/Stages/DesktopStage.qmldeleted−839
@@ -1,839 +0,0 @@
1−/*
2− * Copyright (C) 2014-2016 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.4
18−import Ubuntu.Components 1.3
19−import Unity.Application 0.1
20−import "../Components/PanelState"
21−import "../Components"
22−import Utils 0.1
23−import Ubuntu.Gestures 0.1
24−import GlobalShortcut 1.0
25−
26−AbstractStage {
27− id: root
28− anchors.fill: parent
29− paintBackground: false
30−
31− // functions to be called from outside
32− function updateFocusedAppOrientation() { /* TODO */ }
33− function updateFocusedAppOrientationAnimated() { /* TODO */}
34− function pushRightEdge(amount) {
35− if (spread.state === "") {
36− edgeBarrier.push(amount);
37− }
38− }
39− function closeFocusedDelegate() {
40− if (priv.focusedAppDelegate && !priv.focusedAppDelegate.isDash) {
41− priv.focusedAppDelegate.close();
42− }
43− }
44−
45− // Used by TutorialRight
46− property bool spreadShown: spread.state == "altTab"
47−
48− // used by the snap windows (edge maximize) feature
49− readonly property alias previewRectangle: fakeRectangle
50−
51− mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
52−
53− // application windows never rotate independently
54− mainAppWindowOrientationAngle: shellOrientationAngle
55−
56− orientationChangesEnabled: true
57−
58−
59− itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
60− priv.focusedAppDelegate.surface.confinesMousePointer ?
61− priv.focusedAppDelegate.clientAreaItem : null;
62−
63− GlobalShortcut {
64− id: showSpreadShortcut
65− shortcut: Qt.MetaModifier|Qt.Key_W
66− onTriggered: spread.state = "altTab"
67− }
68−
69− GlobalShortcut {
70− id: minimizeAllShortcut
71− shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_D
72− onTriggered: priv.minimizeAllWindows()
73− }
74−
75− GlobalShortcut {
76− id: maximizeWindowShortcut
77− shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
78− onTriggered: priv.focusedAppDelegate.maximize()
79− active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximized
80− }
81−
82− GlobalShortcut {
83− id: maximizeWindowLeftShortcut
84− shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
85− onTriggered: priv.focusedAppDelegate.maximizeLeft()
86− active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximizedLeftRight
87− }
88−
89− GlobalShortcut {
90− id: maximizeWindowRightShortcut
91− shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
92− onTriggered: priv.focusedAppDelegate.maximizeRight()
93− active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximizedLeftRight
94− }
95−
96− GlobalShortcut {
97− id: minimizeRestoreShortcut
98− shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
99− onTriggered: priv.focusedAppDelegate.anyMaximized
100− ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
101− active: priv.focusedAppDelegate !== null
102− }
103−
104− GlobalShortcut {
105− shortcut: Qt.AltModifier|Qt.Key_Print
106− onTriggered: root.itemSnapshotRequested(priv.focusedAppDelegate)
107− active: priv.focusedAppDelegate !== null
108− }
109−
110− Connections {
111− target: root.topLevelSurfaceList
112− onCountChanged: {
113− if (spread.state == "altTab") {
114− spread.cancel();
115− }
116− }
117− }
118−
119− QtObject {
120− id: priv
121− objectName: "DesktopStagePrivate"
122−
123− property var focusedAppDelegate: null
124− onFocusedAppDelegateChanged: {
125− if (spread.state == "altTab") {
126− spread.state = "";
127− }
128− }
129−
130− property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
131−
132− function updateForegroundMaximizedApp() {
133− var found = false;
134− for (var i = 0; i < appRepeater.count && !found; i++) {
135− var item = appRepeater.itemAt(i);
136− if (item && item.visuallyMaximized) {
137− foregroundMaximizedAppDelegate = item;
138− found = true;
139− }
140− }
141− if (!found) {
142− foregroundMaximizedAppDelegate = null;
143− }
144− }
145−
146− function minimizeAllWindows() {
147− for (var i = 0; i < appRepeater.count; i++) {
148− var appDelegate = appRepeater.itemAt(i);
149− if (appDelegate && !appDelegate.minimized) {
150− appDelegate.minimize();
151− }
152− }
153− }
154−
155− function focusNext() {
156− for (var i = 0; i < appRepeater.count; i++) {
157− var appDelegate = appRepeater.itemAt(i);
158− if (appDelegate && !appDelegate.minimized) {
159− appDelegate.focus = true;
160− return;
161− }
162− }
163− }
164−
165− readonly property real virtualKeyboardHeight: SurfaceManager.inputMethodSurface
166− ? SurfaceManager.inputMethodSurface.inputBounds.height
167− : 0
168− }
169−
170− Connections {
171− target: PanelState
172− onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
173− onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.minimize(); } }
174− onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.restoreFromMaximized(); } }
175− }
176−
177− Binding {
178− target: PanelState
179− property: "decorationsVisible"
180− value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized
181− && spread.state == ""
182− }
183−
184− Binding {
185− target: PanelState
186− property: "title"
187− value: {
188− if (spread.state == "") {
189− if (priv.focusedAppDelegate.maximized)
190− return priv.focusedAppDelegate.title
191− else
192− return priv.focusedAppDelegate.appName
193− }
194− return ""
195− }
196− when: priv.focusedAppDelegate
197− }
198−
199− Binding {
200− target: PanelState
201− property: "focusedPersistentSurfaceId"
202− value: {
203− if (priv.focusedAppDelegate !== null && spread.state == "") {
204− if (priv.focusedAppDelegate.surface) {
205− return priv.focusedAppDelegate.surface.persistentId;
206− }
207− }
208− return "";
209− }
210− when: priv.focusedAppDelegate
211− }
212−
213− Binding {
214− target: PanelState
215− property: "dropShadow"
216− value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null
217− }
218−
219− Binding {
220− target: PanelState
221− property: "closeButtonShown"
222− value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
223− }
224−
225− Component.onDestruction: {
226− PanelState.title = "";
227− PanelState.decorationsVisible = false;
228− PanelState.dropShadow = false;
229− }
230−
231− Instantiator {
232− model: root.applicationManager
233− delegate: Binding {
234− target: model.application
235− property: "requestedState"
236−
237− // TODO: figure out some lifecycle policy, like suspending minimized apps
238− // if running on a tablet or something.
239− // TODO: If the device has a dozen suspended apps because it was running
240− // in staged mode, when it switches to Windowed mode it will suddenly
241− // resume all those apps at once. We might want to avoid that.
242− value: ApplicationInfoInterface.RequestedRunning // Always running for now
243− }
244− }
245−
246− Binding {
247− target: MirFocusController
248− property: "focusedSurface"
249− value: priv.focusedAppDelegate ? priv.focusedAppDelegate.focusedSurface : null
250− when: !appRepeater.startingUp && root.parent
251− }
252−
253− FocusScope {
254− id: appContainer
255− objectName: "appContainer"
256− anchors.fill: parent
257− focus: spread.state !== "altTab"
258−
259− Wallpaper {
260− id: wallpaper
261− anchors.fill: parent
262− source: root.background
263− }
264−
265− TopLevelSurfaceRepeater {
266− id: appRepeater
267− model: topLevelSurfaceList
268− objectName: "appRepeater"
269−
270− delegate: FocusScope {
271− id: appDelegate
272− objectName: "appDelegate_" + model.id
273− // z might be overriden in some cases by effects, but we need z ordering
274− // to calculate occlusion detection
275− property int normalZ: topLevelSurfaceList.count - index
276− onNormalZChanged: {
277− if (visuallyMaximized) {
278− priv.updateForegroundMaximizedApp();
279− }
280− }
281− z: normalZ
282− x: requestedX // may be overridden in some states. Do not directly write to this.
283− y: requestedY // may be overridden in some states. Do not directly write to this.
284− property real requestedX: priv.focusedAppDelegate ? priv.focusedAppDelegate.x + units.gu(3) : (normalZ - 1) * units.gu(3)
285− property real requestedY: priv.focusedAppDelegate ? priv.focusedAppDelegate.y + units.gu(3) : normalZ * units.gu(3)
286−
287− Binding {
288− target: appDelegate
289− property: "y"
290− value: appDelegate.requestedY -
291− Math.min(appDelegate.requestedY - PanelState.panelHeight,
292− Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
293− when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
294− && SurfaceManager.inputMethodSurface
295− && SurfaceManager.inputMethodSurface.state != Mir.HiddenState
296− && SurfaceManager.inputMethodSurface.state != Mir.MinimizedState
297−
298− }
299−
300− width: decoratedWindow.width
301− height: decoratedWindow.height
302−
303− Connections {
304− target: root
305− onShellOrientationAngleChanged: {
306− // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
307− if (application && application.rotatesWindowContents) {
308− if (state == "normal" || state == "restored") {
309− var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
310− angleDiff = (360 + angleDiff) % 360;
311− if (angleDiff === 90 || angleDiff === 270) {
312− var aux = decoratedWindow.requestedHeight;
313− decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.visibleDecorationHeight;
314− decoratedWindow.requestedWidth = aux - decoratedWindow.visibleDecorationHeight;
315− }
316− }
317− decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
318− } else {
319− decoratedWindow.surfaceOrientationAngle = 0;
320− }
321− }
322− }
323−
324− readonly property alias application: decoratedWindow.application
325− readonly property alias minimumWidth: decoratedWindow.minimumWidth
326− readonly property alias minimumHeight: decoratedWindow.minimumHeight
327− readonly property alias maximumWidth: decoratedWindow.maximumWidth
328− readonly property alias maximumHeight: decoratedWindow.maximumHeight
329− readonly property alias widthIncrement: decoratedWindow.widthIncrement
330− readonly property alias heightIncrement: decoratedWindow.heightIncrement
331− property int requestedWidth: -1
332− property int requestedHeight: -1
333−
334− readonly property bool maximized: windowState === WindowStateStorage.WindowStateMaximized
335− readonly property bool maximizedLeft: windowState === WindowStateStorage.WindowStateMaximizedLeft
336− readonly property bool maximizedRight: windowState === WindowStateStorage.WindowStateMaximizedRight
337− readonly property bool maximizedHorizontally: windowState === WindowStateStorage.WindowStateMaximizedHorizontally
338− readonly property bool maximizedVertically: windowState === WindowStateStorage.WindowStateMaximizedVertically
339− readonly property bool maximizedTopLeft: windowState === WindowStateStorage.WindowStateMaximizedTopLeft
340− readonly property bool maximizedTopRight: windowState === WindowStateStorage.WindowStateMaximizedTopRight
341− readonly property bool maximizedBottomLeft: windowState === WindowStateStorage.WindowStateMaximizedBottomLeft
342− readonly property bool maximizedBottomRight: windowState === WindowStateStorage.WindowStateMaximizedBottomRight
343− readonly property bool anyMaximized: maximized || maximizedLeft || maximizedRight || maximizedHorizontally || maximizedVertically ||
344− maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
345−
346− readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
347− readonly property alias fullscreen: decoratedWindow.fullscreen
348−
349− readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
350− readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
351− (maximumHeight == 0 || maximumHeight >= appContainer.height)
352− readonly property bool canBeCornerMaximized: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
353− (maximumHeight == 0 || maximumHeight >= appContainer.height/2)
354− readonly property bool canBeMaximizedHorizontally: maximumWidth == 0 || maximumWidth >= appContainer.width
355− readonly property bool canBeMaximizedVertically: maximumHeight == 0 || maximumHeight >= appContainer.height
356−
357− property int windowState: WindowStateStorage.WindowStateNormal
358− property bool animationsEnabled: true
359− property alias title: decoratedWindow.title
360− readonly property string appName: model.application ? model.application.name : ""
361− property bool visuallyMaximized: false
362− property bool visuallyMinimized: false
363−
364− readonly property var surface: model.surface
365− readonly property alias resizeArea: resizeArea
366− readonly property alias focusedSurface: decoratedWindow.focusedSurface
367− readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
368−
369− readonly property bool isDash: model.application.appId == "unity8-dash"
370− readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
371−
372− function claimFocus() {
373− if (spread.state == "altTab") {
374− spread.cancel();
375− }
376− appDelegate.restore(true /* animated */, appDelegate.windowState);
377− }
378− Connections {
379− target: model.surface
380− onFocusRequested: claimFocus();
381− }
382− Connections {
383− target: model.application
384− onFocusRequested: {
385− if (!model.surface) {
386− // when an app has no surfaces, we assume there's only one entry representing it:
387− // this delegate.
388− claimFocus();
389− } else {
390− // if the application has surfaces, focus request should be at surface-level.
391− }
392− }
393− }
394−
395− onFocusChanged: {
396− if (appRepeater.startingUp)
397− return;
398−
399− if (focus) {
400− // If we're orphan (!parent) it means this stage is no longer the current one
401− // and will be deleted shortly. So we should no longer have a say over the model
402− if (root.parent) {
403− topLevelSurfaceList.raiseId(model.id);
404− }
405−
406− priv.focusedAppDelegate = appDelegate;
407− } else if (!focus && priv.focusedAppDelegate === appDelegate) {
408− priv.focusedAppDelegate = null;
409− // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
410− MirFocusController.focusedSurface = null;
411− }
412− }
413− Component.onCompleted: {
414− if (application && application.rotatesWindowContents) {
415− decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
416− } else {
417− decoratedWindow.surfaceOrientationAngle = 0;
418− }
419−
420− // NB: We're differentiating if this delegate was created in response to a new entry in the model
421− // or if the Repeater is just populating itself with delegates to match the model it received.
422− if (!appRepeater.startingUp) {
423− // a top level window is always the focused one when it first appears, unfocusing
424− // any preexisting one
425− focus = true;
426− }
427− }
428− Component.onDestruction: {
429− if (!root.parent) {
430− // This stage is about to be destroyed. Don't mess up with the model at this point
431− return;
432− }
433−
434− if (visuallyMaximized) {
435− priv.updateForegroundMaximizedApp();
436− }
437−
438− if (focus) {
439− // focus some other window
440− for (var i = 0; i < appRepeater.count; i++) {
441− var appDelegate = appRepeater.itemAt(i);
442− if (appDelegate && !appDelegate.minimized && i != index) {
443− appDelegate.focus = true;
444− return;
445− }
446− }
447− }
448− }
449−
450− onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
451−
452− visible: (
453− !visuallyMinimized
454− && !greeter.fullyShown
455− && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
456− )
457− || decoratedWindow.fullscreen
458− || (spread.state == "altTab" && index === spread.highlightedIndex)
459−
460− function close() {
461− model.surface.close();
462− }
463−
464− function maximize(animated) {
465− animationsEnabled = (animated === undefined) || animated;
466− windowState = WindowStateStorage.WindowStateMaximized;
467− }
468− function maximizeLeft(animated) {
469− animationsEnabled = (animated === undefined) || animated;
470− windowState = WindowStateStorage.WindowStateMaximizedLeft;
471− }
472− function maximizeRight(animated) {
473− animationsEnabled = (animated === undefined) || animated;
474− windowState = WindowStateStorage.WindowStateMaximizedRight;
475− }
476− function maximizeHorizontally(animated) {
477− animationsEnabled = (animated === undefined) || animated;
478− windowState = WindowStateStorage.WindowStateMaximizedHorizontally;
479− }
480− function maximizeVertically(animated) {
481− animationsEnabled = (animated === undefined) || animated;
482− windowState = WindowStateStorage.WindowStateMaximizedVertically;
483− }
484− function maximizeTopLeft(animated) {
485− animationsEnabled = (animated === undefined) || animated;
486− windowState = WindowStateStorage.WindowStateMaximizedTopLeft;
487− }
488− function maximizeTopRight(animated) {
489− animationsEnabled = (animated === undefined) || animated;
490− windowState = WindowStateStorage.WindowStateMaximizedTopRight;
491− }
492− function maximizeBottomLeft(animated) {
493− animationsEnabled = (animated === undefined) || animated;
494− windowState = WindowStateStorage.WindowStateMaximizedBottomLeft;
495− }
496− function maximizeBottomRight(animated) {
497− animationsEnabled = (animated === undefined) || animated;
498− windowState = WindowStateStorage.WindowStateMaximizedBottomRight;
499− }
500− function minimize(animated) {
501− animationsEnabled = (animated === undefined) || animated;
502− windowState |= WindowStateStorage.WindowStateMinimized; // add the minimized bit
503− }
504− function restoreFromMaximized(animated) {
505− animationsEnabled = (animated === undefined) || animated;
506− windowState = WindowStateStorage.WindowStateRestored;
507− }
508− function restore(animated,state) {
509− animationsEnabled = (animated === undefined) || animated;
510− windowState = state || WindowStateStorage.WindowStateRestored;
511− windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
512− focus = true;
513− }
514−
515− function playFocusAnimation() {
516− focusAnimation.start()
517− }
518−
519− UbuntuNumberAnimation {
520− id: focusAnimation
521− target: appDelegate
522− property: "scale"
523− from: 0.98
524− to: 1
525− duration: UbuntuAnimation.SnapDuration
526− }
527−
528− // unlike requestedX/Y, this is the last known grab position before being pushed against edges/corners
529− // when restoring, the window should return to these, not to the place where it was dropped near the edge
530− property real restoredX
531− property real restoredY
532−
533− states: [
534− State {
535− name: "fullscreen"; when: appDelegate.fullscreen && !appDelegate.minimized
536− PropertyChanges {
537− target: appDelegate;
538− x: rotation == 0 ? 0 : (parent.width - width) / 2 + (shellOrientationAngle == 90 ? -PanelState.panelHeight : PanelState.panelHeight)
539− y: rotation == 0 ? -PanelState.panelHeight : (parent.height - height) / 2
540− requestedWidth: appContainer.width;
541− requestedHeight: appContainer.height;
542− }
543− },
544− State {
545− name: "normal";
546− when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
547− PropertyChanges {
548− target: appDelegate;
549− visuallyMinimized: false;
550− visuallyMaximized: false
551− }
552− },
553− State {
554− name: "restored";
555− when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
556− extend: "normal"
557− PropertyChanges {
558− target: appDelegate;
559− requestedX: restoredX;
560− requestedY: restoredY;
561− }
562− },
563− State {
564− name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
565− PropertyChanges {
566− target: appDelegate;
567− requestedX: root.leftMargin;
568− requestedY: 0;
569− requestedWidth: appContainer.width - root.leftMargin;
570− requestedHeight: appContainer.height;
571− visuallyMinimized: false;
572− visuallyMaximized: true
573− }
574− },
575− State {
576− name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
577− PropertyChanges {
578− target: appDelegate
579− requestedX: root.leftMargin
580− requestedY: PanelState.panelHeight
581− requestedWidth: (appContainer.width - root.leftMargin)/2
582− requestedHeight: appContainer.height - PanelState.panelHeight
583− }
584− },
585− State {
586− name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
587− extend: "maximizedLeft"
588− PropertyChanges {
589− target: appDelegate;
590− requestedX: (appContainer.width + root.leftMargin)/2
591− }
592− },
593− State {
594− name: "maximizedTopLeft"; when: appDelegate.maximizedTopLeft && !appDelegate.minimized
595− PropertyChanges {
596− target: appDelegate
597− requestedX: root.leftMargin
598− requestedY: PanelState.panelHeight
599− requestedWidth: (appContainer.width - root.leftMargin)/2
600− requestedHeight: (appContainer.height - PanelState.panelHeight)/2
601− }
602− },
603− State {
604− name: "maximizedTopRight"; when: appDelegate.maximizedTopRight && !appDelegate.minimized
605− extend: "maximizedTopLeft"
606− PropertyChanges {
607− target: appDelegate
608− requestedX: (appContainer.width + root.leftMargin)/2
609− }
610− },
611− State {
612− name: "maximizedBottomLeft"; when: appDelegate.maximizedBottomLeft && !appDelegate.minimized
613− PropertyChanges {
614− target: appDelegate
615− requestedX: root.leftMargin
616− requestedY: (appContainer.height + PanelState.panelHeight)/2
617− requestedWidth: (appContainer.width - root.leftMargin)/2
618− requestedHeight: appContainer.height/2
619− }
620− },
621− State {
622− name: "maximizedBottomRight"; when: appDelegate.maximizedBottomRight && !appDelegate.minimized
623− extend: "maximizedBottomLeft"
624− PropertyChanges {
625− target: appDelegate
626− requestedX: (appContainer.width + root.leftMargin)/2
627− }
628− },
629− State {
630− name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
631− PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: requestedY; requestedWidth: appContainer.width - root.leftMargin }
632− },
633− State {
634− name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
635− PropertyChanges { target: appDelegate; requestedX: requestedX; requestedY: PanelState.panelHeight; requestedHeight: appContainer.height - PanelState.panelHeight }
636− },
637− State {
638− name: "minimized"; when: appDelegate.minimized
639− PropertyChanges {
640− target: appDelegate;
641− requestedX: -appDelegate.width / 2;
642− scale: units.gu(5) / appDelegate.width;
643− opacity: 0;
644− visuallyMinimized: true;
645− visuallyMaximized: false
646− }
647− }
648− ]
649− transitions: [
650− Transition {
651− to: "normal,restored"
652− enabled: appDelegate.animationsEnabled
653− PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
654− UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
655− },
656− Transition {
657− to: "minimized"
658− enabled: appDelegate.animationsEnabled
659− PropertyAction { target: appDelegate; property: "visuallyMaximized" }
660− SequentialAnimation {
661− UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
662− PropertyAction { target: appDelegate; property: "visuallyMinimized" }
663− ScriptAction {
664− script: {
665− if (appDelegate.minimized) {
666− appDelegate.focus = false;
667− priv.focusNext();
668− }
669− }
670− }
671− }
672− },
673− Transition {
674− to: "*" //maximized and fullscreen
675− enabled: appDelegate.animationsEnabled
676− PropertyAction { target: appDelegate; property: "visuallyMinimized" }
677− SequentialAnimation {
678− UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
679− PropertyAction { target: appDelegate; property: "visuallyMaximized" }
680− ScriptAction { script: { fakeRectangle.stop(); } }
681− }
682− }
683− ]
684−
685− Binding {
686− id: previewBinding
687− target: appDelegate
688− property: "z"
689− value: topLevelSurfaceList.count + 1
690− when: index == spread.highlightedIndex && spread.ready
691− }
692−
693− Binding {
694− target: PanelState
695− property: "decorationsAlwaysVisible"
696− value: appDelegate && appDelegate.maximized && touchControls.overlayShown
697− }
698−
699− WindowResizeArea {
700− id: resizeArea
701− objectName: "windowResizeArea"
702−
703− // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
704− anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
705−
706− target: appDelegate
707− minWidth: units.gu(10)
708− minHeight: units.gu(10)
709− borderThickness: units.gu(2)
710− windowId: model.application.appId // FIXME: Change this to point to windowId once we have such a thing
711− screenWidth: appContainer.width
712− screenHeight: appContainer.height
713− leftMargin: root.leftMargin
714−
715− onPressed: { appDelegate.focus = true; }
716−
717− Component.onCompleted: {
718− loadWindowState();
719− }
720−
721− property bool saveStateOnDestruction: true
722− Connections {
723− target: root
724− onStageAboutToBeUnloaded: {
725− resizeArea.saveWindowState();
726− resizeArea.saveStateOnDestruction = false;
727− fullscreenPolicy.active = false;
728− }
729− }
730− Component.onDestruction: {
731− if (saveStateOnDestruction) {
732− saveWindowState();
733− }
734− }
735− }
736−
737− DecoratedWindow {
738− id: decoratedWindow
739− objectName: "decoratedWindow"
740− anchors.left: appDelegate.left
741− anchors.top: appDelegate.top
742− application: model.application
743− surface: model.surface
744− active: appDelegate.focus
745− focus: true
746− maximizeButtonShown: appDelegate.canBeMaximized
747− overlayShown: touchControls.overlayShown
748− stageWidth: appContainer.width
749− stageHeight: appContainer.height
750−
751− requestedWidth: appDelegate.requestedWidth
752− requestedHeight: appDelegate.requestedHeight
753−
754− onCloseClicked: { appDelegate.close(); }
755− onMaximizeClicked: appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
756− onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
757− onMaximizeVerticallyClicked: appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
758− onMinimizeClicked: appDelegate.minimize()
759− onDecorationPressed: { appDelegate.focus = true; }
760− onDecorationReleased: fakeRectangle.commit();
761− }
762−
763− WindowControlsOverlay {
764− id: touchControls
765− target: appDelegate
766− stageWidth: appContainer.width
767− stageHeight: appContainer.height
768−
769− onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
770− onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
771− onFakeMaximizeRightAnimationRequested: if (!appDelegate.maximizedRight) fakeRectangle.maximizeRight(amount, true)
772− onFakeMaximizeTopLeftAnimationRequested: if (!appDelegate.maximizedTopLeft) fakeRectangle.maximizeTopLeft(amount, true);
773− onFakeMaximizeTopRightAnimationRequested: if (!appDelegate.maximizedTopRight) fakeRectangle.maximizeTopRight(amount, true);
774− onFakeMaximizeBottomLeftAnimationRequested: if (!appDelegate.maximizedBottomLeft) fakeRectangle.maximizeBottomLeft(amount, true);
775− onFakeMaximizeBottomRightAnimationRequested: if (!appDelegate.maximizedBottomRight) fakeRectangle.maximizeBottomRight(amount, true);
776− onStopFakeAnimation: fakeRectangle.stop();
777− onDragReleased: fakeRectangle.commit();
778− }
779−
780− WindowedFullscreenPolicy {
781− id: fullscreenPolicy
782− active: true
783− surface: model.surface
784− }
785− }
786− }
787− }
788−
789− FakeMaximizeDelegate {
790− id: fakeRectangle
791− target: priv.focusedAppDelegate
792− leftMargin: root.leftMargin
793− appContainerWidth: appContainer.width
794− appContainerHeight: appContainer.height
795− }
796−
797− EdgeBarrier {
798− id: edgeBarrier
799−
800− // NB: it does its own positioning according to the specified edge
801− edge: Qt.RightEdge
802−
803− onPassed: { spread.show(); }
804− material: Component {
805− Item {
806− Rectangle {
807− width: parent.height
808− height: parent.width
809− rotation: 90
810− anchors.centerIn: parent
811− gradient: Gradient {
812− GradientStop { position: 0.0; color: Qt.rgba(0.16,0.16,0.16,0.5)}
813− GradientStop { position: 1.0; color: Qt.rgba(0.16,0.16,0.16,0)}
814− }
815− }
816− }
817− }
818− }
819−
820− SwipeArea {
821− direction: Direction.Leftwards
822− anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
823− width: units.gu(1)
824− onDraggingChanged: { if (dragging) { spread.show(); } }
825− }
826−
827− DesktopSpread {
828− id: spread
829− objectName: "spread"
830− anchors.fill: appContainer
831− workspace: appContainer
832− focus: state == "altTab"
833− altTabPressed: root.altTabPressed
834−
835− onPlayFocusAnimation: {
836− appRepeater.itemAt(index).playFocusAnimation();
837− }
838− }
839−}
qml/Tutorial/TutorialRight.qml+1−1
@@ -24,7 +24,7 @@ TutorialPage {
24 property string usageScenario
24 property string usageScenario
25
25
26 // When on phone or tablet, fade out as the drag progresses
26 // When on phone or tablet, fade out as the drag progresses
27− opacityOverride: usageScenario === "desktop" ? 1 : 1 - stage.dragProgress * 2
27+ opacityOverride: usageScenario === "desktop" ? 1 : 1 - stage.rightEdgeDragProgress * 2
28
28
29 // Else on desktop, fade out when the spread is shown
29 // Else on desktop, fade out when the spread is shown
30 Connections {
30 Connections {
qml/Stages/graphics/dropshadow2gu@30.png → qml/graphics/dropshadow2gu@30.pngrenamed

Binary file not shown.

qml/Stages/graphics/dropshadow2gu@30.sci → qml/graphics/dropshadow2gu@30.scirenamed

The content is the same.

tests/graphics/applicationIcons/dash.png → tests/graphics/applicationIcons/dash@18.pngrenamed

Binary file not shown.

tests/mocks/Unity/Application/ApplicationInfo.cpp+2−2
@@ -79,7 +79,7 @@ void ApplicationInfo::createSurface()
79{
79{
80 if (state() == ApplicationInfo::Stopped) { return; }
80 if (state() == ApplicationInfo::Stopped) { return; }
81
81
82− QString surfaceName = name();
82+ QString surfaceName = name() + "s window title";
83 if (m_surfaceList->count() > 0) {
83 if (m_surfaceList->count() > 0) {
84 surfaceName.append(QString(" %1").arg(m_surfaceList->count()+1));
84 surfaceName.append(QString(" %1").arg(m_surfaceList->count()+1));
85 }
85 }
@@ -138,7 +138,7 @@ void ApplicationInfo::createSurface()
138
138
139void ApplicationInfo::setIconId(const QString &iconId)
139void ApplicationInfo::setIconId(const QString &iconId)
140{
140{
141− setIcon(QString("../../graphics/applicationIcons/%2@18.png")
141+ setIcon(QString(sourceDirectory() + "/tests/graphics/applicationIcons/%2@18.png")
142 .arg(iconId));
142 .arg(iconId));
143}
143}
144
144
tests/mocks/Unity/Application/ApplicationManager.cpp+2
@@ -295,6 +295,7 @@ void ApplicationManager::buildListOfAvailableApplications()
295 application->setAppId("unity8-dash");
295 application->setAppId("unity8-dash");
296 application->setName("Unity 8 Mock Dash");
296 application->setName("Unity 8 Mock Dash");
297 application->setScreenshotId("unity8-dash");
297 application->setScreenshotId("unity8-dash");
298+ application->setIconId("dash");
298 m_availableApplications.append(application);
299 m_availableApplications.append(application);
299
300
300 application = new ApplicationInfo(this);
301 application = new ApplicationInfo(this);
@@ -403,6 +404,7 @@ void ApplicationManager::buildListOfAvailableApplications()
403 application->setAppId("notes-app");
404 application->setAppId("notes-app");
404 application->setName("Notepad");
405 application->setName("Notepad");
405 application->setIconId("notepad");
406 application->setIconId("notepad");
407+// application->setStage(ApplicationInfoInterface::SideStage);
406 m_availableApplications.append(application);
408 m_availableApplications.append(application);
407
409
408 application = new ApplicationInfo(this);
410 application = new ApplicationInfo(this);
tests/mocks/Unity/Application/MirSurface.cpp+1
@@ -256,6 +256,7 @@ void MirSurface::updateVisibility()
256
256
257 m_visible = newVisible;
257 m_visible = newVisible;
258 Q_EMIT visibleChanged(m_visible);
258 Q_EMIT visibleChanged(m_visible);
259+ updateInputBoundsAfterResize();
259 }
260 }
260}
261}
261
262
tests/mocks/Unity/Application/MirSurfaceItem.cpp+13
@@ -60,9 +60,13 @@ MirSurfaceItem::MirSurfaceItem(QQuickItem *parent)
60
60
61 connect(this, &QQuickItem::activeFocusChanged, this, &MirSurfaceItem::updateMirSurfaceActiveFocus);
61 connect(this, &QQuickItem::activeFocusChanged, this, &MirSurfaceItem::updateMirSurfaceActiveFocus);
62 connect(this, &QQuickItem::visibleChanged, this, &MirSurfaceItem::updateMirSurfaceVisibility);
62 connect(this, &QQuickItem::visibleChanged, this, &MirSurfaceItem::updateMirSurfaceVisibility);
63+
63 connect(this, &MirSurfaceItem::consumesInputChanged, this, [this]() {
64 connect(this, &MirSurfaceItem::consumesInputChanged, this, [this]() {
64 updateMirSurfaceActiveFocus(hasActiveFocus());
65 updateMirSurfaceActiveFocus(hasActiveFocus());
65 });
66 });
67+
68+ // We're just clipping contents in the mock. The real QtMir would copy only relevant buffer instead
69+ setClip(true);
66}
70}
67
71
68MirSurfaceItem::~MirSurfaceItem()
72MirSurfaceItem::~MirSurfaceItem()
@@ -181,6 +185,9 @@ void MirSurfaceItem::createQmlContentItem()
181 m_qmlItem = qobject_cast<QQuickItem*>(m_qmlContentComponent->create());
185 m_qmlItem = qobject_cast<QQuickItem*>(m_qmlContentComponent->create());
182 m_qmlItem->setParentItem(this);
186 m_qmlItem->setParentItem(this);
183
187
188+ m_qmlItem->setWidth(m_surfaceWidth);
189+ m_qmlItem->setHeight(m_surfaceHeight);
190+
184 setImplicitWidth(m_qmlItem->implicitWidth());
191 setImplicitWidth(m_qmlItem->implicitWidth());
185 setImplicitHeight(m_qmlItem->implicitHeight());
192 setImplicitHeight(m_qmlItem->implicitHeight());
186
193
@@ -350,6 +357,7 @@ int MirSurfaceItem::surfaceWidth() const
350
357
351void MirSurfaceItem::setSurfaceWidth(int value)
358void MirSurfaceItem::setSurfaceWidth(int value)
352{
359{
360+// qDebug() << "setSurfaceWidth called" << value;
353 if (value != -1 && m_surfaceWidth != value) {
361 if (value != -1 && m_surfaceWidth != value) {
354 m_surfaceWidth = value;
362 m_surfaceWidth = value;
355 Q_EMIT surfaceWidthChanged(m_surfaceWidth);
363 Q_EMIT surfaceWidthChanged(m_surfaceWidth);
@@ -375,6 +383,11 @@ void MirSurfaceItem::updateSurfaceSize()
375{
383{
376 if (m_qmlSurface && m_surfaceWidth > 0 && m_surfaceHeight > 0) {
384 if (m_qmlSurface && m_surfaceWidth > 0 && m_surfaceHeight > 0) {
377 m_qmlSurface->resize(m_surfaceWidth, m_surfaceHeight);
385 m_qmlSurface->resize(m_surfaceWidth, m_surfaceHeight);
386+ if (m_qmlItem) {
387+ m_qmlItem->setWidth(m_surfaceWidth);
388+ m_qmlItem->setHeight(m_surfaceHeight);
389+ }
390+ setImplicitSize(m_surfaceWidth, m_surfaceHeight);
378 }
391 }
379}
392}
380
393
tests/mocks/Unity/Application/MirSurfaceListModel.cpp−1
@@ -84,7 +84,6 @@ void MirSurfaceListModel::prependSurface(MirSurface *surface)
84
84
85void MirSurfaceListModel::connectSurface(MirSurface *surface)
85void MirSurfaceListModel::connectSurface(MirSurface *surface)
86{
86{
87− connect(surface, &MirSurface::raiseRequested, this, [this, surface](){ this->raise(surface); });
88 connect(surface, &QObject::destroyed, this, [this, surface](){ this->removeSurface(surface); });
87 connect(surface, &QObject::destroyed, this, [this, surface](){ this->removeSurface(surface); });
89}
88}
90
89
tests/mocks/Unity/Application/SurfaceManager.cpp+7−6
@@ -36,11 +36,11 @@ SurfaceManager::SurfaceManager(QObject *parent) :
36 the_surface_manager = this;
36 the_surface_manager = this;
37
37
38 m_virtualKeyboard = new VirtualKeyboard;
38 m_virtualKeyboard = new VirtualKeyboard;
39+ const QString persistentId = m_virtualKeyboard->persistentId();
39− connect(m_virtualKeyboard, &QObject::destroyed, this, [this](QObject *obj) {
40+ connect(m_virtualKeyboard, &QObject::destroyed, this, [this, persistentId](QObject*) {
40− MirSurface* surface = qobject_cast<MirSurface*>(obj);
41 m_virtualKeyboard = nullptr;
41 m_virtualKeyboard = nullptr;
42 Q_EMIT inputMethodSurfaceChanged();
42 Q_EMIT inputMethodSurfaceChanged();
43− Q_EMIT surfaceDestroyed(surface);
43+ Q_EMIT surfaceDestroyed(persistentId);
44 });
44 });
45}
45}
46
46
@@ -56,9 +56,10 @@ MirSurface *SurfaceManager::createSurface(const QString& name,
56 const QUrl& screenshot)
56 const QUrl& screenshot)
57{
57{
58 MirSurface* surface = new MirSurface(name, type, state, screenshot);
58 MirSurface* surface = new MirSurface(name, type, state, screenshot);
59+ const QString persistentId = surface->persistentId();
60+
59− connect(surface, &QObject::destroyed, this, [this](QObject *obj) {
61+ connect(surface, &QObject::destroyed, this, [this, persistentId](QObject*) {
60− MirSurface* surface = qobject_cast<MirSurface*>(obj);
61− Q_EMIT surfaceDestroyed(surface);
62+ Q_EMIT surfaceDestroyed(persistentId);
62 });
63 });
63
64
64 surface->setMinimumWidth(m_newSurfaceMinimumWidth);
65 surface->setMinimumWidth(m_newSurfaceMinimumWidth);
tests/mocks/Unity/Application/SurfaceManager.h+1−1
@@ -70,7 +70,7 @@ Q_SIGNALS:
70 void inputMethodSurfaceChanged();
70 void inputMethodSurfaceChanged();
71 void countChanged();
71 void countChanged();
72 void surfaceCreated(MirSurface *surface);
72 void surfaceCreated(MirSurface *surface);
73− void surfaceDestroyed(MirSurface*surface);
73+ void surfaceDestroyed(const QString& persistentSurfaceId);
74
74
75 void newSurfaceMinimumWidthChanged(int value);
75 void newSurfaceMinimumWidthChanged(int value);
76 void newSurfaceMaximumWidthChanged(int value);
76 void newSurfaceMaximumWidthChanged(int value);
tests/mocks/Unity/Application/VirtualKeyboard.cpp+9−7
@@ -39,13 +39,15 @@ void VirtualKeyboard::updateInputBoundsAfterResize()
39{
39{
40 int width = this->width();
40 int width = this->width();
41
41
42− int height;
42+ int height = 0;
43+ if (visible()) {
43− if (this->width() > this->height()) {
44+ if (this->width() > this->height()) {
44− // landscape
45+ // landscape
45− height = this->height() * 0.4;
46+ height = this->height() * 0.4;
46− } else {
47+ } else {
47− // portrait
48+ // portrait
48− height = this->width() * 0.6;
49+ height = this->width() * 0.6;
50+ }
49 }
51 }
50
52
51 int x = 0;
53 int x = 0;
tests/mocks/Unity/Application/resources/MirSurfaceItem.qml+2−5
@@ -20,11 +20,8 @@ Rectangle {
20 id: root
20 id: root
21 color: "pink"
21 color: "pink"
22
22
23− implicitWidth: units.gu(40)
23+ implicitWidth: width
24− implicitHeight: units.gu(70)
24+ implicitHeight: height
25−
26− width: parent ? parent.width : implicitWidth
27− height: parent ? parent.height : implicitHeight
28
25
29 property alias screenshotSource: screenshotImage.source
26 property alias screenshotSource: screenshotImage.source
30 property int orientationAngle
27 property int orientationAngle
tests/mocks/Unity/ApplicationMenu/mockapplicationmenuregistry.cpp+5
@@ -40,3 +40,8 @@ void MockApplicationMenuRegistry::RegisterSurfaceMenu(const QString &surface,
40 QDBusObjectPath(actionObjectPath),
40 QDBusObjectPath(actionObjectPath),
41 service);
41 service);
42}
42}
43+
44+void MockApplicationMenuRegistry::UnregisterSurfaceMenu(const QString &surfaceId, const QDBusObjectPath &menuObjectPath)
45+{
46+ ApplicationMenuRegistry::UnregisterSurfaceMenu(surfaceId, menuObjectPath);
47+}
tests/mocks/Unity/ApplicationMenu/mockapplicationmenuregistry.h+3
@@ -31,6 +31,9 @@ public:
31 const QString &actionObjectPath,
31 const QString &actionObjectPath,
32 const QString &service);
32 const QString &service);
33
33
34+ Q_INVOKABLE void UnregisterSurfaceMenu(const QString &surfaceId,
35+ const QDBusObjectPath &menuObjectPath);
36+
34private:
37private:
35 MockApplicationMenuRegistry(QObject *parent = 0);
38 MockApplicationMenuRegistry(QObject *parent = 0);
36};
39};
tests/qmltests/ApplicationMenuDataLoader.qmlnew file+54
@@ -0,0 +1,54 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+import Unity.Application 0.1
4+import Unity.ApplicationMenu 0.1
5+import Unity.Indicators 0.1 as Indicators
6+
7+Object {
8+ Connections {
9+ target: SurfaceManager
10+ onSurfaceCreated: {
11+ var fakeMenuPath = "/" + surface.persistentId.replace(/\W+/g, "");;
12+
13+ ApplicationMenuRegistry.RegisterSurfaceMenu(surface.persistentId, fakeMenuPath, fakeMenuPath, ":1");
14+ Indicators.UnityMenuModelCache.setCachedModelData(fakeMenuPath, generateTestData(5, 3, 3, "menu"));
15+ }
16+ onSurfaceDestroyed: {
17+ ApplicationMenuRegistry.UnregisterSurfaceMenu(persistentSurfaceId, "/app");
18+ }
19+ }
20+
21+ function generateTestData(length, depth, separatorInterval, prefix) {
22+ var data = [];
23+
24+ if (prefix === undefined) prefix = "menu"
25+
26+ for (var i = 0; i < length; i++) {
27+
28+ var menuCode = String.fromCharCode(i+65);
29+
30+ var isSeparator = separatorInterval > 0 && ((i+1) % separatorInterval == 0);
31+ var row = {
32+ "rowData": { // 1
33+ "label": prefix + "&" + menuCode,
34+ "sensitive": true,
35+ "isSeparator": isSeparator,
36+ "icon": "",
37+ "ext": {},
38+ "action": prefix + menuCode,
39+ "actionState": {},
40+ "isCheck": false,
41+ "isRadio": false,
42+ "isToggled": false,
43+ "shortcut": ""
44+ }
45+ }
46+ if (!isSeparator && depth > 1) {
47+ var submenu = generateTestData(length, depth-1, separatorInterval, prefix + menuCode + ".");
48+ row["submenu"] = submenu;
49+ }
50+ data[i] = row;
51+ }
52+ return data;
53+ }
54+}
tests/qmltests/CMakeLists.txt+9−10
@@ -88,16 +88,15 @@ add_unity8_qmltest(Panel/Indicators IndicatorItem)
88add_unity8_qmltest(Panel/Indicators IndicatorsLight)
88add_unity8_qmltest(Panel/Indicators IndicatorsLight)
89add_unity8_qmltest(Panel/Indicators MenuItemFactory)
89add_unity8_qmltest(Panel/Indicators MenuItemFactory)
90add_unity8_qmltest(Panel/Indicators MessageMenuItemFactory)
90add_unity8_qmltest(Panel/Indicators MessageMenuItemFactory)
91−add_unity8_qmltest(Stages ApplicationWindow)
91+add_unity8_qmltest(Stage ApplicationWindow)
92−add_unity8_qmltest(Stages DecoratedWindow)
92+add_unity8_qmltest(Stage DesktopStage)
93−add_unity8_qmltest(Stages DesktopStage)
94−add_unity8_qmltest(Stages PhoneStage)
93+add_unity8_qmltest(Stage PhoneStage)
95−add_unity8_qmltest(Stages SpreadDelegate)
94+add_unity8_qmltest(Stage SurfaceContainer)
96−add_unity8_qmltest(Stages SurfaceContainer)
97−add_unity8_qmltest(Stages TabletStage)
95+add_unity8_qmltest(Stage TabletStage)
98−add_unity8_qmltest(Stages WindowResizeArea)
96+add_unity8_qmltest(Stage WindowResizeArea)
99−add_unity8_qmltest(Stages WindowDecoration)
97+add_unity8_qmltest(Stage Splash)
100−add_unity8_qmltest(Stages Splash)
98+add_unity8_qmltest(Stage DecoratedWindow)
99+add_unity8_qmltest(Stage WindowDecoration)
101add_unity8_qmltest(Tutorial Tutorial)
100add_unity8_qmltest(Tutorial Tutorial)
102add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
101add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
103add_unity8_qmltest(utils/Unity/Test UnityTest)
102add_unity8_qmltest(utils/Unity/Test UnityTest)
tests/qmltests/Panel/tst_Panel.qml−3
@@ -46,9 +46,6 @@ PanelTest {
46
46
47 Component.onCompleted: {
47 Component.onCompleted: {
48 theme.name = "Ubuntu.Components.Themes.SuruDark"
48 theme.name = "Ubuntu.Components.Themes.SuruDark"
49−
50− ApplicationMenuRegistry.RegisterSurfaceMenu("dialerAppSurfaceId", "/dialerapp", "/dialerapp", ":2");
51− Indicators.UnityMenuModelCache.setCachedModelData("/dialerapp", appMenuData.dialerData);
52 }
49 }
53
50
54 Rectangle {
51 Rectangle {
tests/qmltests/Stages/ApplicationCheckBox.qml → tests/qmltests/Stage/ApplicationCheckBox.qmlrenamed

The content is the same.

tests/qmltests/Stages/SizeHintField.qml → tests/qmltests/Stage/SizeHintField.qmlrenamed

The content is the same.

tests/qmltests/Stages/SurfaceManagerControls.qml → tests/qmltests/Stage/SurfaceManagerControls.qmlrenamed

The content is the same.

tests/qmltests/Stages/SurfaceManagerField.qml → tests/qmltests/Stage/SurfaceManagerField.qmlrenamed

The content is the same.

tests/qmltests/Stages/tst_ApplicationWindow.qml → tests/qmltests/Stage/tst_ApplicationWindow.qmlrenamed+1−1
@@ -19,7 +19,7 @@ import QtQuick.Layouts 1.1
19import QtTest 1.0
19import QtTest 1.0
20import Unity.Test 0.1 as UT
20import Unity.Test 0.1 as UT
21import ".."
21import ".."
22−import "../../../qml/Stages"
22+import "../../../qml/Stage"
23import Ubuntu.Components 1.3
23import Ubuntu.Components 1.3
24import Ubuntu.Components.ListItems 1.3 as ListItem
24import Ubuntu.Components.ListItems 1.3 as ListItem
25import Unity.Application 0.1
25import Unity.Application 0.1
tests/qmltests/Stage/tst_DecoratedWindow.qmlnew file+260
@@ -0,0 +1,260 @@
1+/*
2+ * Copyright 2014-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.4
18+import QtTest 1.0
19+import Unity.Test 0.1 as UT
20+import ".."
21+import "../../../qml/Components"
22+import "../../../qml/Components/PanelState"
23+import "../../../qml/Stage"
24+import Ubuntu.Components 1.3
25+import Ubuntu.Components.ListItems 1.3 as ListItem
26+import Unity.Application 0.1
27+import Unity.ApplicationMenu 0.1
28+import Unity.Indicators 0.1 as Indicators
29+
30+Rectangle {
31+ color: "red"
32+ id: root
33+ width: fakeShell.shortestDimension + controls.width
34+ height: fakeShell.longestDimension
35+
36+ Component.onCompleted: {
37+ QuickUtils.keyboardAttached = true;
38+ theme.name = "Ubuntu.Components.Themes.SuruDark"
39+ }
40+
41+ property QtObject fakeApplication: null
42+
43+ Binding {
44+ target: UT.MouseTouchAdaptor
45+ property: "enabled"
46+ value: false
47+ }
48+
49+ ApplicationMenuDataLoader { }
50+
51+ Item {
52+ id: fakeShell
53+
54+ readonly property real shortestDimension: units.gu(100)
55+ readonly property real longestDimension: units.gu(70)
56+
57+ width: landscape ? longestDimension : shortestDimension
58+ height: landscape ? shortestDimension : longestDimension
59+
60+ x: landscape ? (height - width) / 2 : 0
61+ y: landscape ? (width - height) / 2 : 0
62+
63+ property bool landscape: orientationAngle == 90 || orientationAngle == 270
64+ property int orientationAngle: shellOrientationAngleSelector.value
65+
66+ rotation: orientationAngle
67+
68+ WindowResizeArea {
69+ target: loader
70+ borderThickness: units.gu(2)
71+ }
72+
73+ Loader {
74+ id: loader
75+ property int windowedX: units.gu(1)
76+ property int windowedY: units.gu(1)
77+ property int windowedWidth: units.gu(50)
78+ property int windowedHeight: units.gu(40)
79+ x: windowedX
80+ y: windowedY
81+ width: item ? item.implicitWidth : 0
82+ height: item ? item.implicitHeight : 0
83+
84+ active: false
85+ property bool itemDestroyed: false
86+
87+ sourceComponent: DecoratedWindow {
88+ id: decoratedWindow
89+
90+ anchors.fill: parent
91+ application: fakeApplication
92+ requestedWidth: loader.windowedWidth
93+ requestedHeight: loader.windowedHeight
94+ active: true
95+ surface: fakeApplication && fakeApplication.surfaceList.count > 0 ? fakeApplication.surfaceList.get(0) : null
96+
97+ Binding {
98+ target: PanelState
99+ property: "focusedPersistentSurfaceId"
100+ value: decoratedWindow.surface ? decoratedWindow.surface.persistentId : "x"
101+ }
102+
103+ Component.onCompleted: {
104+ loader.itemDestroyed = false;
105+ }
106+ }
107+
108+ Rectangle { anchors.fill: parent; color: "green"; opacity: 1 }
109+ }
110+ }
111+
112+
113+ Rectangle {
114+ id: controls
115+ color: theme.palette.normal.background
116+ width: units.gu(30)
117+ anchors {
118+ top: parent.top
119+ bottom: parent.bottom
120+ right: parent.right
121+ }
122+
123+ Column {
124+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
125+ spacing: units.gu(1)
126+ Button {
127+ id: loadWidthDialerApp
128+ text: "Load with dialer-app"
129+ onClicked: { testCase.restartWithApp("dialer-app"); }
130+ }
131+ Button {
132+ id: loadWithWeatherApp
133+ text: "Load with ubuntu-weather-app"
134+ onClicked: { testCase.restartWithApp("ubuntu-weather-app"); }
135+ }
136+ Button {
137+ id: loadWithGalleryApp
138+ text: "Load with gallery-app"
139+ onClicked: { testCase.restartWithApp("gallery-app"); }
140+ }
141+ Button {
142+ text: "toggle has decoration"
143+ onClicked: loader.item.hasDecoration = !loader.item.hasDecoration
144+ }
145+ Button {
146+ text: "show/hide decoration"
147+ onClicked: loader.item.showDecoration = !loader.item.showDecoration
148+ }
149+ Label {
150+ text: "scale to preview progress"
151+ }
152+
153+ Slider {
154+ value: 0
155+ minimumValue: 0
156+ maximumValue: 1
157+ live: true
158+ onValueChanged: loader.item.scaleToPreviewProgress = value
159+ }
160+ ListItem.ItemSelector {
161+ id: shellOrientationAngleSelector
162+ anchors { left: parent.left; right: parent.right }
163+ text: "shellOrientationAngle"
164+ model: ["0", "90", "180", "270"]
165+ property int value: selectedIndex * 90
166+ }
167+ Button {
168+ text: "matchShellOrientation()"
169+ onClicked: { loader.item.matchShellOrientation(); }
170+ }
171+ Button {
172+ text: "animateToShellOrientation()"
173+ onClicked: { loader.item.animateToShellOrientation(); }
174+ }
175+ }
176+ }
177+
178+ UT.UnityTestCase {
179+ id: testCase
180+ name: "DecoratedWindow"
181+ when: windowShown
182+
183+ property Item decoratedWindow: loader.item
184+
185+ function init() {
186+ }
187+
188+ function cleanup() {
189+ unloadWindow();
190+ root.fakeApplication = null;
191+ killApps();
192+ }
193+
194+ function restartWithApp(appId) {
195+ if (loader.active) {
196+ unloadWindow();
197+ }
198+ if (root.fakeApplication) {
199+ ApplicationManager.stopApplication(root.fakeApplication.appId);
200+ }
201+
202+ root.fakeApplication = ApplicationManager.startApplication(appId);
203+ loader.active = true;
204+ tryCompare(loader, "status", Loader.Ready);
205+ }
206+
207+ function unloadWindow() {
208+ loader.active = false;
209+ tryCompare(loader, "status", Loader.Null);
210+ tryCompare(loader, "item", null);
211+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
212+ // item might still be alive. So if we set Loader.active back to true
213+ // again right now we will get the very same Shell instance back. So no reload
214+ // actually took place. Likely because Loader waits until the next event loop
215+ // iteration to do its work. So to ensure the reload, we will wait until the
216+ // Shell instance gets destroyed.
217+ tryCompare(loader, "itemDestroyed", true);
218+
219+ }
220+
221+ function test_keepsSceneTransformationWhenShellRotates_data() {
222+ return [
223+ {tag: "0", selectedIndex: 0},
224+ {tag: "90", selectedIndex: 1},
225+ {tag: "180", selectedIndex: 2},
226+ {tag: "270", selectedIndex: 3}
227+ ];
228+ }
229+ function test_keepsSceneTransformationWhenShellRotates(data) {
230+ loadWithGalleryApp.clicked();
231+
232+ // Wait until it reaches the state we are interested on.
233+ // It begins with "startingUp"
234+ tryCompare(decoratedWindow, "counterRotate", false);
235+ var oldWidth = decoratedWindow.width
236+ var oldHeight = decoratedWindow.height
237+ var oldX = decoratedWindow.x
238+ var oldY = decoratedWindow.y
239+
240+ shellOrientationAngleSelector.selectedIndex = data.selectedIndex;
241+
242+ // must keep same aspect ratio
243+ compare(decoratedWindow.width, oldWidth);
244+ compare(decoratedWindow.height, oldHeight);
245+
246+
247+ // and scene transformation must be the identity (ie, no rotation or translation)
248+ compare(decoratedWindow.x, oldX);
249+ compare(decoratedWindow.y, oldY);
250+ }
251+
252+ function test_showHighLight() {
253+ loadWithGalleryApp.clicked();
254+ var highlightRect = findChild(loader.item, "selectionHighlight")
255+ tryCompare(highlightRect, "visible", false)
256+ loader.item.showHighlight = true;
257+ tryCompare(highlightRect, "visible", true)
258+ }
259+ }
260+}
tests/qmltests/Stages/tst_DesktopStage.qml → tests/qmltests/Stage/tst_DesktopStage.qmlrenamed+30−83
@@ -26,14 +26,14 @@ import WindowManager 0.1
26import Utils 0.1
26import Utils 0.1
27
27
28import ".." // For EdgeBarrierControls
28import ".." // For EdgeBarrierControls
29−import "../../../qml/Stages"
29+import "../../../qml/Stage"
30import "../../../qml/Components"
30import "../../../qml/Components"
31import "../../../qml/Components/PanelState"
31import "../../../qml/Components/PanelState"
32
32
33Item {
33Item {
34 id: root
34 id: root
35− width: desktopStageLoader.width + controls.width
35+ width: stageLoader.width + controls.width
36− height: desktopStageLoader.height
36+ height: stageLoader.height
37
37
38 property var greeter: { fullyShown: true }
38 property var greeter: { fullyShown: true }
39
39
@@ -43,23 +43,12 @@ Item {
43 value: false
43 value: false
44 }
44 }
45
45
46− DesktopMenuData {
46+ ApplicationMenuDataLoader { }
47− id: appMenuData
48− }
49
47
50 Component.onCompleted: {
48 Component.onCompleted: {
51 QuickUtils.keyboardAttached = true;
49 QuickUtils.keyboardAttached = true;
52 theme.name = "Ubuntu.Components.Themes.SuruDark";
50 theme.name = "Ubuntu.Components.Themes.SuruDark";
53 resetGeometry();
51 resetGeometry();
54−
55− ApplicationMenuRegistry.RegisterSurfaceMenu("DialerId", "/dialerapp", "/dialerapp", ":0");
56− Indicators.UnityMenuModelCache.setCachedModelData("/dialerapp", appMenuData.dialerData);
57−
58− ApplicationMenuRegistry.RegisterSurfaceMenu("CameraId", "/cameraapp", "/cameraapp", ":1");
59− Indicators.UnityMenuModelCache.setCachedModelData("/cameraapp", appMenuData.cameraData);
60−
61− ApplicationMenuRegistry.RegisterSurfaceMenu("GalleryId", "/galleryapp", "/galleryapp", ":2");
62− Indicators.UnityMenuModelCache.setCachedModelData("/galleryapp", appMenuData.galleryData);
63 }
52 }
64
53
65 function resetGeometry() {
54 function resetGeometry() {
@@ -79,7 +68,7 @@ Item {
79 }
68 }
80
69
81 Loader {
70 Loader {
82− id: desktopStageLoader
71+ id: stageLoader
83 x: ((root.width - controls.width) - width) / 2
72 x: ((root.width - controls.width) - width) / 2
84 y: (root.height - height) / 2
73 y: (root.height - height) / 2
85 width: units.gu(160*0.9)
74 width: units.gu(160*0.9)
@@ -89,7 +78,7 @@ Item {
89
78
90 property bool itemDestroyed: false
79 property bool itemDestroyed: false
91 sourceComponent: Component {
80 sourceComponent: Component {
92− DesktopStage {
81+ Stage {
93 anchors.fill: parent
82 anchors.fill: parent
94 background: "/usr/share/backgrounds/warty-final-ubuntu.png"
83 background: "/usr/share/backgrounds/warty-final-ubuntu.png"
95 focus: true
84 focus: true
@@ -98,17 +87,19 @@ Item {
98 edgeBarrierControls.target = testCase.findChild(this, "edgeBarrierController");
87 edgeBarrierControls.target = testCase.findChild(this, "edgeBarrierController");
99 }
88 }
100 Component.onDestruction: {
89 Component.onDestruction: {
101− desktopStageLoader.itemDestroyed = true;
90+ stageLoader.itemDestroyed = true;
102 }
91 }
103 orientations: Orientations {}
92 orientations: Orientations {}
104 applicationManager: ApplicationManager
93 applicationManager: ApplicationManager
105 topLevelSurfaceList: topSurfaceList
94 topLevelSurfaceList: topSurfaceList
95+ interactive: true
96+ mode: "windowed"
106 }
97 }
107 }
98 }
108
99
109 MouseArea {
100 MouseArea {
110 id: clickThroughTester
101 id: clickThroughTester
111− anchors.fill: desktopStageLoader.item
102+ anchors.fill: stageLoader.item
112 acceptedButtons: Qt.AllButtons
103 acceptedButtons: Qt.AllButtons
113 hoverEnabled: true
104 hoverEnabled: true
114 }
105 }
@@ -146,7 +137,7 @@ Item {
146 id: edgeBarrierControls
137 id: edgeBarrierControls
147 text: "Drag here to pull out spread"
138 text: "Drag here to pull out spread"
148 backgroundColor: "blue"
139 backgroundColor: "blue"
149− onDragged: { desktopStageLoader.item.pushRightEdge(amount); }
140+ onDragged: { stageLoader.item.pushRightEdge(amount); }
150 }
141 }
151
142
152 Divider {}
143 Divider {}
@@ -173,7 +164,7 @@ Item {
173 name: "DesktopStage"
164 name: "DesktopStage"
174 when: windowShown
165 when: windowShown
175
166
176− property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null
167+ property Item stage: stageLoader.status === Loader.Ready ? stageLoader.item : null
177
168
178 function init() {
169 function init() {
179 // wait until unity8-dash is up and running.
170 // wait until unity8-dash is up and running.
@@ -189,29 +180,29 @@ Item {
189 }
180 }
190
181
191 function cleanup() {
182 function cleanup() {
192− desktopStageLoader.itemDestroyed = false;
183+ stageLoader.itemDestroyed = false;
193− desktopStageLoader.active = false;
184+ stageLoader.active = false;
194
185
195− tryCompare(desktopStageLoader, "status", Loader.Null);
186+ tryCompare(stageLoader, "status", Loader.Null);
196− tryCompare(desktopStageLoader, "item", null);
187+ tryCompare(stageLoader, "item", null);
197 // Loader.status might be Loader.Null and Loader.item might be null but the Loader
188 // Loader.status might be Loader.Null and Loader.item might be null but the Loader
198 // actually took place. Likely because Loader waits until the next event loop
189 // actually took place. Likely because Loader waits until the next event loop
199 // iteration to do its work. So to ensure the reload, we will wait until the
190 // iteration to do its work. So to ensure the reload, we will wait until the
200 // Shell instance gets destroyed.
191 // Shell instance gets destroyed.
201− tryCompare(desktopStageLoader, "itemDestroyed", true);
192+ tryCompare(stageLoader, "itemDestroyed", true);
202
193
203 killApps();
194 killApps();
204
195
205 root.resetGeometry();
196 root.resetGeometry();
206
197
207− desktopStageLoader.active = true;
198+ stageLoader.active = true;
208− tryCompare(desktopStageLoader, "status", Loader.Ready);
199+ tryCompare(stageLoader, "status", Loader.Ready);
209
200
210 mouseEaterSpy.clear();
201 mouseEaterSpy.clear();
211 }
202 }
212
203
213 function waitUntilAppSurfaceShowsUp(surfaceId) {
204 function waitUntilAppSurfaceShowsUp(surfaceId) {
214− var appDelegate = findChild(desktopStage, "appDelegate_" + surfaceId);
205+ var appDelegate = findChild(stage, "appDelegate_" + surfaceId);
215 verify(appDelegate);
206 verify(appDelegate);
216 var appWindow = findChild(appDelegate, "appWindow");
207 var appWindow = findChild(appDelegate, "appWindow");
217 verify(appWindow);
208 verify(appWindow);
@@ -229,7 +220,7 @@ Item {
229 if (app) {
220 if (app) {
230 for (var i = 0; i < topSurfaceList.count; i++) {
221 for (var i = 0; i < topSurfaceList.count; i++) {
231 if (topSurfaceList.applicationAt(i).appId === appId) {
222 if (topSurfaceList.applicationAt(i).appId === appId) {
232− var appRepeater = findChild(desktopStage, "appRepeater");
223+ var appRepeater = findChild(stage, "appRepeater");
233 verify(appRepeater);
224 verify(appRepeater);
234 return appRepeater.itemAt(i);
225 return appRepeater.itemAt(i);
235 }
226 }
@@ -242,7 +233,7 @@ Item {
242 waitUntilAppSurfaceShowsUp(surfaceId);
233 waitUntilAppSurfaceShowsUp(surfaceId);
243 compare(app.surfaceList.count, 1);
234 compare(app.surfaceList.count, 1);
244
235
245− return findChild(desktopStage, "appDelegate_" + surfaceId);
236+ return findChild(stage, "appDelegate_" + surfaceId);
246 } catch(err) {
237 } catch(err) {
247 throw new Error("startApplication("+appId+") called from line " + util.callerLine(1) + " failed!");
238 throw new Error("startApplication("+appId+") called from line " + util.callerLine(1) + " failed!");
248 }
239 }
@@ -340,7 +331,7 @@ Item {
340 }
331 }
341
332
342 function findDecoratedWindow(surfaceId) {
333 function findDecoratedWindow(surfaceId) {
343− var appDelegate = findChild(desktopStage, "appDelegate_" + surfaceId);
334+ var appDelegate = findChild(stage, "appDelegate_" + surfaceId);
344 if (!appDelegate) {
335 if (!appDelegate) {
345 console.warn("Could not find appDelegate for surfaceId="+surfaceId);
336 console.warn("Could not find appDelegate for surfaceId="+surfaceId);
346 return null;
337 return null;
@@ -349,7 +340,7 @@ Item {
349 }
340 }
350
341
351 function findWindowDecoration(surfaceId) {
342 function findWindowDecoration(surfaceId) {
352− var appDelegate = findChild(desktopStage, "appDelegate_" + surfaceId);
343+ var appDelegate = findChild(stage, "appDelegate_" + surfaceId);
353 if (!appDelegate) {
344 if (!appDelegate) {
354 console.warn("Could not find appDelegate for surfaceId="+surfaceId);
345 console.warn("Could not find appDelegate for surfaceId="+surfaceId);
355 return null;
346 return null;
@@ -481,8 +472,8 @@ Item {
481
472
482 mouseClick(dialerDelegate);
473 mouseClick(dialerDelegate);
483
474
484− var desktopStagePriv = findInvisibleChild(desktopStage, "DesktopStagePrivate");
475+ var stagePriv = findInvisibleChild(stage, "DesktopStagePrivate");
485− tryCompare(desktopStagePriv, "focusedAppDelegate", dialerDelegate);
476+ tryCompare(stagePriv, "focusedAppDelegate", dialerDelegate);
486
477
487 keyClick(Qt.Key_F4, Qt.AltModifier); // Alt+F4 shortcut to close
478 keyClick(Qt.Key_F4, Qt.AltModifier); // Alt+F4 shortcut to close
488
479
@@ -533,35 +524,6 @@ Item {
533 tryCompare(MirFocusController, "focusedSurface", null); // verify still no surface is focused
524 tryCompare(MirFocusController, "focusedSurface", null); // verify still no surface is focused
534 }
525 }
535
526
536− function test_oskDisplacesWindow_data() {
537− return [
538− {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5), oskEnabled: true},
539− {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
540− {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
541− {tag: "osk not on this screen", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: units.gu(10), oskEnabled: false},
542− ]
543− }
544−
545− function test_oskDisplacesWindow(data) {
546− desktopStageLoader.item.oskEnabled = data.oskEnabled
547− var dashAppDelegate = startApplication("unity8-dash");
548− var oldOSKState = SurfaceManager.inputMethodSurface.state;
549− SurfaceManager.inputMethodSurface.state = Mir.RestoredState;
550− verify(dashAppDelegate);
551− dashAppDelegate.requestedHeight = data.windowHeight;
552− dashAppDelegate.requestedY = data.windowY;
553− SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
554− var initialY = dashAppDelegate.y;
555− verify(initialY > PanelState.panelHeight);
556−
557− SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));
558− tryCompare(dashAppDelegate, "y", data.targetDisplacement);
559−
560− SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
561− tryCompare(dashAppDelegate, "y", initialY);
562− SurfaceManager.inputMethodSurface.state = oldOSKState;
563− }
564−
565 function test_minimizeApplicationHidesSurface() {
527 function test_minimizeApplicationHidesSurface() {
566 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
528 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
567 var dashSurface = topSurfaceList.surfaceAt(0);
529 var dashSurface = topSurfaceList.surfaceAt(0);
@@ -614,6 +576,8 @@ Item {
614 var gmailDelegate = startApplication("gmail-webapp");
576 var gmailDelegate = startApplication("gmail-webapp");
615 verify(gmailDelegate);
577 verify(gmailDelegate);
616
578
579+ wait(2000)
580+
617 var gmailMaximizeButton = findChild(gmailDelegate, "maximizeWindowButton");
581 var gmailMaximizeButton = findChild(gmailDelegate, "maximizeWindowButton");
618 verify(gmailMaximizeButton);
582 verify(gmailMaximizeButton);
619 mouseClick(gmailMaximizeButton);
583 mouseClick(gmailMaximizeButton);
@@ -626,6 +590,7 @@ Item {
626 tryCompare(mapApp.surfaceList.get(0), "visible", false);
590 tryCompare(mapApp.surfaceList.get(0), "visible", false);
627
591
628 ApplicationManager.stopApplication("gmail-webapp");
592 ApplicationManager.stopApplication("gmail-webapp");
593+ wait(2000)
629
594
630 tryCompare(mapApp.surfaceList.get(0), "visible", true);
595 tryCompare(mapApp.surfaceList.get(0), "visible", true);
631 tryCompare(dialerApp.surfaceList.get(0), "visible", true);
596 tryCompare(dialerApp.surfaceList.get(0), "visible", true);
@@ -725,7 +690,7 @@ Item {
725 tryCompare(overlay, "visible", data.result);
690 tryCompare(overlay, "visible", data.result);
726
691
727 if (data.result) { // if shown, try to hide it by clicking outside
692 if (data.result) { // if shown, try to hide it by clicking outside
728− mouseClick(desktopStage);
693+ mouseClick(stage);
729 tryCompare(overlay, "visible", false);
694 tryCompare(overlay, "visible", false);
730 }
695 }
731 }
696 }
@@ -784,24 +749,6 @@ Item {
784 tryCompareFunction(function(){return posBefore == posAfter;}, data.button !== Qt.LeftButton ? true : false);
749 tryCompareFunction(function(){return posBefore == posAfter;}, data.button !== Qt.LeftButton ? true : false);
785 }
750 }
786
751
787− function test_preventMouseEventsThruDesktopSpread() {
788− var spread = findChild(desktopStage, "spread");
789− verify(spread);
790− spread.show();
791− tryCompareFunction( function(){ return spread.ready }, true );
792−
793− mouseEaterSpy.signalName = "wheel";
794− mouseWheel(spread, spread.width/2, spread.height/2, 10, 10);
795− tryCompare(mouseEaterSpy, "count", 0);
796−
797− mouseEaterSpy.clear();
798− mouseEaterSpy.signalName = "clicked";
799− mouseClick(spread, spread.width/2, spread.height/2, Qt.RightButton);
800− tryCompare(mouseEaterSpy, "count", 0);
801−
802− spread.cancel();
803− }
804−
805 function test_eatWindowDecorationMouseEvents_data() {
752 function test_eatWindowDecorationMouseEvents_data() {
806 return [
753 return [
807 {tag: "left mouse click", signalName: "clicked", button: Qt.LeftButton },
754 {tag: "left mouse click", signalName: "clicked", button: Qt.LeftButton },
tests/qmltests/Stages/tst_PhoneStage.qml → tests/qmltests/Stage/tst_PhoneStage.qmlrenamed+146−211
@@ -19,7 +19,7 @@ import QtTest 1.0
19import Unity.Test 0.1 as UT
19import Unity.Test 0.1 as UT
20import ".."
20import ".."
21import "../../../qml/Components"
21import "../../../qml/Components"
22−import "../../../qml/Stages"
22+import "../../../qml/Stage"
23import Ubuntu.Components 1.3
23import Ubuntu.Components 1.3
24import Unity.Application 0.1
24import Unity.Application 0.1
25import WindowManager 0.1
25import WindowManager 0.1
@@ -31,16 +31,18 @@ Item {
31
31
32 property var greeter: { fullyShown: true }
32 property var greeter: { fullyShown: true }
33
33
34− PhoneStage {
34+ ApplicationMenuDataLoader { }
35− id: phoneStage
35+
36+ Stage {
37+ id: stage
36 anchors { fill: parent; rightMargin: units.gu(30) }
38 anchors { fill: parent; rightMargin: units.gu(30) }
37 focus: true
39 focus: true
38 dragAreaWidth: units.gu(2)
40 dragAreaWidth: units.gu(2)
39− maximizedAppTopMargin: units.gu(3)
40 interactive: true
41 interactive: true
41 shellOrientation: Qt.PortraitOrientation
42 shellOrientation: Qt.PortraitOrientation
42 orientations: Orientations {}
43 orientations: Orientations {}
43 applicationManager: ApplicationManager
44 applicationManager: ApplicationManager
45+ mode: "staged"
44 topLevelSurfaceList: TopLevelSurfaceList {
46 topLevelSurfaceList: TopLevelSurfaceList {
45 id: topLevelSurfaceList
47 id: topLevelSurfaceList
46 applicationsModel: ApplicationManager
48 applicationsModel: ApplicationManager
@@ -66,9 +68,9 @@ Item {
66 id: edgeBarrierControls
68 id: edgeBarrierControls
67 text: "Drag here to pull out spread"
69 text: "Drag here to pull out spread"
68 backgroundColor: "blue"
70 backgroundColor: "blue"
69− onDragged: { phoneStage.pushRightEdge(amount); }
71+ onDragged: { stage.pushRightEdge(amount); }
70 Component.onCompleted: {
72 Component.onCompleted: {
71− edgeBarrierControls.target = testCase.findChild(phoneStage, "edgeBarrierController");
73+ edgeBarrierControls.target = testCase.findChild(stage, "edgeBarrierController");
72 }
74 }
73 }
75 }
74 Repeater {
76 Repeater {
@@ -84,11 +86,37 @@ Item {
84 name: "PhoneStage"
86 name: "PhoneStage"
85 when: windowShown
87 when: windowShown
86
88
89+ function init() {
90+ // wait until unity8-dash is up and running.
91+ // it's started automatically by ApplicationManager mock implementation
92+ tryCompare(ApplicationManager, "count", 1);
93+ var dashApp = ApplicationManager.findApplication("unity8-dash");
94+ verify(dashApp);
95+ tryCompare(dashApp, "state", ApplicationInfoInterface.Running);
96+ }
97+
98+ function cleanup() {
99+ ApplicationManager.requestFocusApplication("unity8-dash");
100+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
101+ tryCompare(stage, "state", "staged");
102+ waitForRendering(stage);
103+
104+ killApps();
105+ // wait for Stage to stabilize back into its initial state
106+ var appRepeater = findChild(stage, "appRepeater");
107+ tryCompare(appRepeater, "count", 1);
108+ tryCompare(appRepeater.itemAt(0), "x", 0);
109+
110+ stage.shellOrientationAngle = 0;
111+
112+ waitForRendering(stage)
113+ }
114+
87 function findAppWindowForSurfaceId(surfaceId) {
115 function findAppWindowForSurfaceId(surfaceId) {
88− var delegateObjectName = "spreadDelegate_" + surfaceId;
116+ var delegateObjectName = "appDelegate_" + surfaceId;
89− var spreadDelegate = findChild(phoneStage, delegateObjectName);
117+ var spreadDelegate = findChild(stage, delegateObjectName);
90 if (!spreadDelegate) {
118 if (!spreadDelegate) {
91− console.warn("Failed to find " + delegateObjectName + " in phoneStage ("+phoneStage+")");
119+ console.warn("Failed to find " + delegateObjectName + " in stage");
92 return null;
120 return null;
93 }
121 }
94 var appWindow = findChild(spreadDelegate, "appWindow");
122 var appWindow = findChild(spreadDelegate, "appWindow");
@@ -108,33 +136,29 @@ Item {
108 function addApps(count) {
136 function addApps(count) {
109 if (count == undefined) count = 1;
137 if (count == undefined) count = 1;
110 for (var i = 0; i < count; i++) {
138 for (var i = 0; i < count; i++) {
139+ var startingAppId = ApplicationManager.availableApplications[ApplicationManager.count];
111 var appSurfaceId = topLevelSurfaceList.nextId;
140 var appSurfaceId = topLevelSurfaceList.nextId;
112− var app = ApplicationManager.startApplication(ApplicationManager.availableApplications[ApplicationManager.count])
141+ var app = ApplicationManager.startApplication(startingAppId)
113 tryCompare(app, "state", ApplicationInfoInterface.Running)
142 tryCompare(app, "state", ApplicationInfoInterface.Running)
114− var spreadView = findChild(phoneStage, "spreadView");
115− tryCompare(spreadView, "contentX", -spreadView.shift);
116 waitUntilAppSurfaceShowsUp(appSurfaceId);
143 waitUntilAppSurfaceShowsUp(appSurfaceId);
117− waitForRendering(phoneStage)
144+ waitForRendering(stage)
145+ tryCompare(ApplicationManager, "focusedApplicationId", startingAppId)
118 }
146 }
119 }
147 }
120
148
121 function performEdgeSwipeToShowAppSpread() {
149 function performEdgeSwipeToShowAppSpread() {
122− var spreadView = findChild(phoneStage, "spreadView");
123−
124− // Keep it inside the PhoneStage otherwise the controls on the right side will
150+ // Keep it inside the Stage otherwise the controls on the right side will
125 // capture the press thus the "- 2" on startX.
151 // capture the press thus the "- 2" on startX.
126− var startX = phoneStage.width - 2;
152+ var startX = stage.width - 2;
127− var startY = phoneStage.height / 2;
153+ var startY = stage.height / 2;
128 var endY = startY;
154 var endY = startY;
129− var endX = phoneStage.width / 2;
155+ var endX = stage.width / 2;
130
156
131− touchFlick(phoneStage, startX, startY, endX, endY,
157+ touchFlick(stage, startX, startY, endX, endY,
132 true /* beginTouch */, true /* endTouch */, units.gu(10), 50);
158 true /* beginTouch */, true /* endTouch */, units.gu(10), 50);
133
159
134− tryCompare(spreadView, "phase", 2);
160+ tryCompare(stage, "state", "spread");
135− tryCompare(spreadView, "flicking", false);
136− tryCompare(spreadView, "moving", false);
137− waitForRendering(phoneStage);
161+ waitForRendering(stage);
138 }
162 }
139
163
140 function swipeSurfaceUpwards(surfaceId) {
164 function swipeSurfaceUpwards(surfaceId) {
@@ -163,7 +187,7 @@ Item {
163
187
164 function waitUntilAppDelegateStopsMoving(targetSurfaceId)
188 function waitUntilAppDelegateStopsMoving(targetSurfaceId)
165 {
189 {
166− var targetAppDelegate = findChild(phoneStage, "spreadDelegate_" + targetSurfaceId);
190+ var targetAppDelegate = findChild(stage, "appDelegate_" + targetSurfaceId);
167 verify(targetAppDelegate);
191 verify(targetAppDelegate);
168 var lastValue = undefined;
192 var lastValue = undefined;
169 do {
193 do {
@@ -172,79 +196,39 @@ Item {
172 } while (lastValue != targetAppDelegate.animatedProgress);
196 } while (lastValue != targetAppDelegate.animatedProgress);
173 }
197 }
174
198
175− function test_shortFlick() {
176− addApps(2)
177− var startX = phoneStage.width - units.gu(1);
178− var startY = phoneStage.height / 2;
179− var endX = startX - units.gu(4);
180− var endY = startY;
181−
182− var activeApp = ApplicationManager.get(0);
183− var inactiveApp = ApplicationManager.get(1);
184−
185− touchFlick(phoneStage, startX, startY, endX, endY,
186− true /* beginTouch */, true /* endTouch */, units.gu(10), 50);
187−
188− tryCompare(ApplicationManager, "focusedApplicationId", inactiveApp.appId)
189−
190− touchFlick(phoneStage, startX, startY, endX, endY,
191− true /* beginTouch */, true /* endTouch */, units.gu(10), 50);
192−
193− tryCompare(ApplicationManager, "focusedApplicationId", activeApp.appId)
194− }
195−
196 function test_enterSpread_data() {
199 function test_enterSpread_data() {
197 return [
200 return [
198− {tag: "<position1 (linear movement)", positionMarker: "positionMarker1", linear: true, offset: 0, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 },
201+ {tag: "<breakPoint (trigger)", progress: .2, cancel: false, endState: "staged", newFocusedIndex: 1 },
199− {tag: "<position1 (non-linear movement)", positionMarker: "positionMarker1", linear: false, offset: 0, endPhase: 0, targetPhase: 0, newFocusedIndex: 0 },
202+ {tag: "<breakPoint (cancel)", progress: .2, cancel: true, endState: "staged", newFocusedIndex: 0 },
200− {tag: ">position1", positionMarker: "positionMarker1", linear: true, offset: +5, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 },
203+ {tag: ">breakPoint (trigger)", progress: .5, cancel: false, endState: "spread", newFocusedIndex: 0 },
201− {tag: "<position2 (linear)", positionMarker: "positionMarker2", linear: true, offset: 0, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 },
204+ {tag: ">breakPoint (cancel)", progress: .8, cancel: true, endState: "staged", newFocusedIndex: 0 },
202− {tag: "<position2 (non-linear)", positionMarker: "positionMarker2", linear: false, offset: 0, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 },
203− {tag: ">position2", positionMarker: "positionMarker2", linear: true, offset: +5, endPhase: 1, targetPhase: 0, newFocusedIndex: 1 },
204− {tag: "<position3", positionMarker: "positionMarker3", linear: true, offset: 0, endPhase: 1, targetPhase: 0, newFocusedIndex: 1 },
205− {tag: ">position3", positionMarker: "positionMarker3", linear: true, offset: +5, endPhase: 1, targetPhase: 2, newFocusedIndex: 2 },
206 ];
205 ];
207 }
206 }
208
207
209 function test_enterSpread(data) {
208 function test_enterSpread(data) {
210 addApps(5)
209 addApps(5)
211
210
212− var spreadView = findChild(phoneStage, "spreadView");
213−
214− // Keep it inside the PhoneStage otherwise the controls on the right side will
211+ // Keep it inside the Stage otherwise the controls on the right side will
215 // capture the press thus the "- 2" on startX.
212 // capture the press thus the "- 2" on startX.
216− var startX = phoneStage.width - 2;
213+ var startX = stage.width - 2;
217− var startY = phoneStage.height / 2;
214+ var startY = stage.height / 2;
218 var endY = startY;
215 var endY = startY;
219− var endX = spreadView.width - (spreadView.width * spreadView[data.positionMarker]) - data.offset
216+ var endX = stage.width - (stage.width * data.progress) - stage.dragAreaWidth;
220− - phoneStage.dragAreaWidth;
221
217
222 var oldFocusedApp = ApplicationManager.get(0);
218 var oldFocusedApp = ApplicationManager.get(0);
223 var newFocusedApp = ApplicationManager.get(data.newFocusedIndex);
219 var newFocusedApp = ApplicationManager.get(data.newFocusedIndex);
224
220
225− touchFlick(phoneStage, startX, startY, endX, endY,
221+ touchFlick(stage, startX, startY, endX, endY,
226 true /* beginTouch */, false /* endTouch */, units.gu(10), 50);
222 true /* beginTouch */, false /* endTouch */, units.gu(10), 50);
227
223
228− tryCompare(spreadView, "phase", data.endPhase)
229−
230− if (!data.linear) {
224+ if (data.cancel) {
231− touchFlick(phoneStage, endX, endY, endX + units.gu(.5), endY,
225+ touchFlick(stage, endX, endY, endX + units.gu(5), endY,
232− false /* beginTouch */, false /* endTouch */, units.gu(10), 50);
226+ false /* beginTouch */, true /* endTouch */, units.gu(10), 50);
233− touchFlick(phoneStage, endY + units.gu(.5), endY, endX, endY,
227+ } else {
234− false /* beginTouch */, false /* endTouch */, units.gu(10), 50);
228+ touchRelease(stage, endX, endY); }
235− }
236−
237− touchRelease(phoneStage, endX, endY);
238−
239− tryCompare(spreadView, "phase", data.targetPhase)
240−
241− if (data.targetPhase == 2) {
242− var app2 = findChild(spreadView, "spreadDelegate_" + topLevelSurfaceList.idAt(2));
243− tryCompare(app2, "swipeToCloseEnabled", true);
244− mouseClick(app2, units.gu(1), units.gu(1));
245− }
246
229
230+ tryCompare(stage, "state", data.endState);
247− tryCompare(ApplicationManager, "focusedApplicationId", newFocusedApp.appId);
231+ tryCompare(ApplicationManager, "focusedApplicationId", data.endState == "spread" ? oldFocusedApp.appId : newFocusedApp.appId);
248 }
232 }
249
233
250 function test_selectAppFromSpread_data() {
234 function test_selectAppFromSpread_data() {
@@ -263,32 +247,26 @@ Item {
263 function test_selectAppFromSpread(data) {
247 function test_selectAppFromSpread(data) {
264 addApps(data.total)
248 addApps(data.total)
265
249
266− var spreadView = findChild(phoneStage, "spreadView");
267−
268 performEdgeSwipeToShowAppSpread();
250 performEdgeSwipeToShowAppSpread();
269
251
270− tryCompare(spreadView, "phase", 2);
271−
272− var tile = findChild(spreadView, "spreadDelegate_" + topLevelSurfaceList.idAt(data.index));
252+ var tile = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(data.index));
273 var appId = ApplicationManager.get(data.index).appId;
253 var appId = ApplicationManager.get(data.index).appId;
274
254
275− if (tile.mapToItem(spreadView, 0, 0).x > spreadView.width) {
255+ if (tile.mapToItem(stage, 0, 0).x > stage.width - units.gu(3)) {
276 // Item is not visible... Need to flick the spread
256 // Item is not visible... Need to flick the spread
277− var startX = phoneStage.width - units.gu(1);
257+ var startX = stage.width - units.gu(1);
278− var startY = phoneStage.height / 2;
258+ var startY = stage.height / 2;
279 var endY = startY;
259 var endY = startY;
280 var endX = units.gu(2);
260 var endX = units.gu(2);
281− touchFlick(phoneStage, startX, startY, endX, endY, true, true, units.gu(10), 50)
261+ touchFlick(stage, startX, startY, endX, endY, true, true, units.gu(10), 50)
282− tryCompare(spreadView, "flicking", false);
283− tryCompare(spreadView, "moving", false);
284−// waitForRendering(phoneStage);
285 }
262 }
286
263
287 console.log("clicking app", data.index, "(", appId, ")")
264 console.log("clicking app", data.index, "(", appId, ")")
265+ var dragArea = findChild(tile, "dragArea");
288− tryCompare(tile, "swipeToCloseEnabled", true);
266+ tryCompare(dragArea, "closeable", true);
289− mouseClick(spreadView, tile.mapToItem(spreadView, 0, 0).x + units.gu(1), spreadView.height / 2)
267+ mouseClick(stage, tile.mapToItem(stage, 0, 0).x + units.gu(1), stage.height / 2)
290 tryCompare(ApplicationManager, "focusedApplicationId", appId);
268 tryCompare(ApplicationManager, "focusedApplicationId", appId);
291− tryCompare(spreadView, "phase", 0);
269+ tryCompare(stage, "state", "staged");
292 }
270 }
293
271
294 function test_select_data() {
272 function test_select_data() {
@@ -302,16 +280,22 @@ Item {
302 function test_select(data) {
280 function test_select(data) {
303 addApps(5);
281 addApps(5);
304
282
305− var spreadView = findChild(phoneStage, "spreadView");
306 var selectedApp = ApplicationManager.get(data.index);
283 var selectedApp = ApplicationManager.get(data.index);
284+ var appRepeater = findChild(stage, "appRepeater");
285+ var selectedAppDeleage = appRepeater.itemAt(data.index);
307
286
308 performEdgeSwipeToShowAppSpread();
287 performEdgeSwipeToShowAppSpread();
309
288
310− phoneStage.select(selectedApp.appId);
289+ print("tapping", selectedAppDeleage.appId, selectedAppDeleage.visible)
290+ if (selectedAppDeleage.x > stage.width - units.gu(5)) {
291+ touchFlick(stage, stage.width - units.gu(2), stage.height / 2, units.gu(2), stage.height / 2, true, true, units.gu(2), 10)
292+ }
293+
294+ tap(selectedAppDeleage, 1, 1);
311
295
312− tryCompare(spreadView, "contentX", -spreadView.shift);
296+ tryCompare(stage, "state", "staged");
313
297
314− compare(ApplicationManager.focusedApplicationId, selectedApp.appId);
298+ tryCompare(ApplicationManager, "focusedApplicationId", selectedApp.appId);
315 }
299 }
316
300
317 function test_backgroundClickCancelsSpread() {
301 function test_backgroundClickCancelsSpread() {
@@ -320,37 +304,14 @@ Item {
320 var focusedAppId = ApplicationManager.focusedApplicationId;
304 var focusedAppId = ApplicationManager.focusedApplicationId;
321
305
322 performEdgeSwipeToShowAppSpread();
306 performEdgeSwipeToShowAppSpread();
307+ tryCompare(stage, "state", "spread");
323
308
324− mouseClick(phoneStage, units.gu(1), units.gu(1));
309+ mouseClick(stage, units.gu(1), units.gu(1));
325
310
326− // Make sure the spread is in the idle position
311+ tryCompare(stage, "state", "staged");
327− var spreadView = findChild(phoneStage, "spreadView");
328− tryCompare(spreadView, "contentX", -spreadView.shift);
329
312
330 // Make sure the same app is still focused
313 // Make sure the same app is still focused
331− compare(focusedAppId, ApplicationManager.focusedApplicationId);
314+ tryCompare(ApplicationManager, "focusedApplicationId", focusedAppId);
332− }
333−
334− function init() {
335− // wait until unity8-dash is up and running.
336− // it's started automatically by ApplicationManager mock implementation
337− tryCompare(ApplicationManager, "count", 1);
338− var dashApp = ApplicationManager.findApplication("unity8-dash");
339− verify(dashApp);
340− tryCompare(dashApp, "state", ApplicationInfoInterface.Running);
341− }
342−
343− function cleanup() {
344− killApps();
345−
346− phoneStage.shellOrientationAngle = 0;
347− phoneStage.select(ApplicationManager.get(0).appId);
348−
349− // wait for PhoneStage to stabilize back into its initial state
350− var spreadView = findChild(phoneStage, "spreadView");
351− while (spreadView.phase !== 0 || spreadView.contentX !== -spreadView.shift || spreadView.selectedIndex != -1) {
352− wait(50);
353− }
354 }
315 }
355
316
356 function test_focusNewTopMostAppAfterFocusedOneClosesItself() {
317 function test_focusNewTopMostAppAfterFocusedOneClosesItself() {
@@ -370,60 +331,9 @@ Item {
370 tryCompare(firstApp, "focused", true);
331 tryCompare(firstApp, "focused", true);
371 }
332 }
372
333
373− function test_cantCloseWhileSnapping() {
374− addApps(2);
375−
376− performEdgeSwipeToShowAppSpread();
377−
378− var spreadView = findChild(phoneStage, "spreadView");
379− var selectedApp = ApplicationManager.get(2);
380−
381− performEdgeSwipeToShowAppSpread();
382−
383− var app0 = findChild(spreadView, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
384− var app1 = findChild(spreadView, "spreadDelegate_" + topLevelSurfaceList.idAt(1));
385− var app2 = findChild(spreadView, "spreadDelegate_" + topLevelSurfaceList.idAt(2));
386−
387− var dragArea0 = findChild(app0, "dragArea");
388− var dragArea1 = findChild(app1, "dragArea");
389− var dragArea2 = findChild(app2, "dragArea");
390−
391− compare(dragArea0.enabled, true);
392− compare(dragArea1.enabled, true);
393− compare(dragArea2.enabled, true);
394−
395− phoneStage.select(selectedApp.appId);
396−
397− // Make sure all drag areas are disabled instantly. Don't use tryCompare here!
398− compare(dragArea0.enabled, false);
399− compare(dragArea1.enabled, false);
400− compare(dragArea2.enabled, false);
401−
402− tryCompare(spreadView, "contentX", -spreadView.shift)
403− }
404−
405− function test_cantAccessPhoneStageWhileRightEdgeGesture() {
406− var spreadView = findChild(phoneStage, "spreadView");
407− var eventEaterArea = findChild(phoneStage, "eventEaterArea")
408−
409− var startX = phoneStage.width - 2;
410− var startY = phoneStage.height / 2;
411− var endY = startY;
412− var endX = phoneStage.width / 2;
413−
414− touchFlick(phoneStage, startX, startY, endX, endY,
415− true /* beginTouch */, false /* endTouch */, units.gu(10), 50);
416−
417− compare(eventEaterArea.enabled, true);
418−
419− touchRelease(phoneStage, endX, endY);
420−
421− compare(eventEaterArea.enabled, false);
422− }
423−
424 function test_leftEdge_data() {
334 function test_leftEdge_data() {
425 return [
335 return [
426− { tag: "normal", inSpread: false, leftEdgeDragWidth: units.gu(5), shouldMoveApp: true },
336+ { tag: "normal", inSpread: false, leftEdgeDragWidth: units.gu(20), shouldMoveApp: true },
427 { tag: "inSpread", inSpread: true, leftEdgeDragWidth: units.gu(5), shouldMoveApp: false }
337 { tag: "inSpread", inSpread: true, leftEdgeDragWidth: units.gu(5), shouldMoveApp: false }
428 ]
338 ]
429 }
339 }
@@ -435,22 +345,24 @@ Item {
435 performEdgeSwipeToShowAppSpread();
345 performEdgeSwipeToShowAppSpread();
436 }
346 }
437
347
438− var focusedDelegate = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
348+ var focusedDelegate = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
349+ var currentX = focusedDelegate.x;
350+
439− phoneStage.inverseProgress = data.leftEdgeDragWidth;
351+ stage.leftEdgeDragProgress = data.leftEdgeDragWidth;
440
352
441− tryCompare(focusedDelegate, "x", data.shouldMoveApp ? data.leftEdgeDragWidth : 0);
353+ tryCompare(focusedDelegate, "x", data.shouldMoveApp ? data.leftEdgeDragWidth : currentX);
442
354
443− phoneStage.inverseProgress = 0;
355+ stage.leftEdgeDragProgress = 0;
444
356
445− tryCompare(focusedDelegate, "x", 0);
357+ tryCompare(focusedDelegate, "x", currentX);
446 }
358 }
447
359
448 function test_focusedAppIsTheOnlyRunningApp() {
360 function test_focusedAppIsTheOnlyRunningApp() {
449 addApps(2);
361 addApps(2);
450
362
451− var delegateA = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
363+ var delegateA = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
452 verify(delegateA);
364 verify(delegateA);
453− var delegateB = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(1));
365+ var delegateB = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(1));
454 verify(delegateB);
366 verify(delegateB);
455
367
456 // A is focused and running, B is unfocused and suspended
368 // A is focused and running, B is unfocused and suspended
@@ -461,7 +373,7 @@ Item {
461
373
462 // Switch foreground/focused appp from A to B
374 // Switch foreground/focused appp from A to B
463 performEdgeSwipeToShowAppSpread();
375 performEdgeSwipeToShowAppSpread();
464− phoneStage.select(delegateB.application.appId);
376+ tap(delegateB, 1, 1);
465
377
466 // Now it's the other way round
378 // Now it's the other way round
467 // A is unfocused and suspended, B is focused and running
379 // A is unfocused and suspended, B is focused and running
@@ -474,15 +386,15 @@ Item {
474 function test_dashRemainsRunningIfStageIsToldSo() {
386 function test_dashRemainsRunningIfStageIsToldSo() {
475 addApps(1);
387 addApps(1);
476
388
477− var delegateDash = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(1));
389+ var delegateDash = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(1));
478 verify(delegateDash);
390 verify(delegateDash);
479 compare(delegateDash.application.appId, "unity8-dash");
391 compare(delegateDash.application.appId, "unity8-dash");
480
392
481− var delegateOther = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
393+ var delegateOther = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
482 verify(delegateOther);
394 verify(delegateOther);
483
395
484 performEdgeSwipeToShowAppSpread();
396 performEdgeSwipeToShowAppSpread();
485− phoneStage.select("unity8-dash");
397+ tap(delegateDash, 1, 1);
486
398
487 tryCompare(delegateDash, "focus", true);
399 tryCompare(delegateDash, "focus", true);
488 tryCompare(delegateDash.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
400 tryCompare(delegateDash.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
@@ -490,41 +402,40 @@ Item {
490 compare(delegateOther.application.requestedState, ApplicationInfoInterface.RequestedSuspended);
402 compare(delegateOther.application.requestedState, ApplicationInfoInterface.RequestedSuspended);
491
403
492 performEdgeSwipeToShowAppSpread();
404 performEdgeSwipeToShowAppSpread();
493− phoneStage.select(delegateOther.application.appId);
405+ tap(delegateOther, 1, 1);
494−
495 // The other app gets focused and running but dash is kept running despite being unfocused
406 // The other app gets focused and running but dash is kept running despite being unfocused
407+ tryCompare(delegateOther, "focus", true);
408+ tryCompare(delegateOther.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
496 tryCompare(delegateDash, "focus", false);
409 tryCompare(delegateDash, "focus", false);
497 tryCompare(delegateDash.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
410 tryCompare(delegateDash.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
498− compare(delegateOther.focus, true);
499− compare(delegateOther.application.requestedState, ApplicationInfoInterface.RequestedRunning);
500 }
411 }
501
412
502 function test_foregroundAppIsSuspendedWhenStageIsSuspended() {
413 function test_foregroundAppIsSuspendedWhenStageIsSuspended() {
503 addApps(1);
414 addApps(1);
504
415
505− var delegate = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
416+ var delegate = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
506 verify(delegate);
417 verify(delegate);
507
418
508 compare(delegate.focus, true);
419 compare(delegate.focus, true);
509 compare(delegate.application.requestedState, ApplicationInfoInterface.RequestedRunning);
420 compare(delegate.application.requestedState, ApplicationInfoInterface.RequestedRunning);
510
421
511− phoneStage.suspended = true;
422+ stage.suspended = true;
512
423
513 tryCompare(delegate.application, "requestedState", ApplicationInfoInterface.RequestedSuspended);
424 tryCompare(delegate.application, "requestedState", ApplicationInfoInterface.RequestedSuspended);
514
425
515− phoneStage.suspended = false;
426+ stage.suspended = false;
516
427
517 tryCompare(delegate.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
428 tryCompare(delegate.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
518 }
429 }
519
430
520 function test_mouseEdgePush() {
431 function test_mouseEdgePush() {
521− var spreadView = findChild(phoneStage, "spreadView")
522 addApps(1);
432 addApps(1);
523− mouseMove(phoneStage, phoneStage.width - 1, units.gu(10));
433+ mouseMove(stage, stage.width - 1, units.gu(10));
524 for (var i = 0; i < units.gu(10); i++) {
434 for (var i = 0; i < units.gu(10); i++) {
525− phoneStage.pushRightEdge(1);
435+ stage.pushRightEdge(1);
526 }
436 }
527− tryCompare(spreadView, "phase", 2);
437+ mouseMove(stage, stage.width - units.gu(5), units.gu(10));
438+ compare(stage.state, "spread");
528 }
439 }
529
440
530 function test_closeSurfaceOfMultiSurfaceApp() {
441 function test_closeSurfaceOfMultiSurfaceApp() {
@@ -539,19 +450,44 @@ Item {
539
450
540 performEdgeSwipeToShowAppSpread();
451 performEdgeSwipeToShowAppSpread();
541
452
542− var appDelegate = findChild(phoneStage, "spreadDelegate_" + surface1Id);
453+ var appDelegate = findChild(stage, "appDelegate_" + surface1Id);
543− verify(appDelegate);
454+ var dragArea = findChild(appDelegate, "dragArea")
544− tryCompare(appDelegate, "swipeToCloseEnabled", true);
455+ verify(dragArea);
456+ tryCompare(dragArea, "closeable", true);
545
457
546 compare(webbrowserApp.surfaceList.count, 2);
458 compare(webbrowserApp.surfaceList.count, 2);
547− compare(webbrowserApp.state, ApplicationInfoInterface.Running);
548
459
549 swipeSurfaceUpwards(surface1Id);
460 swipeSurfaceUpwards(surface1Id);
550
461
551 // Surface must eventually be gone
462 // Surface must eventually be gone
552 tryCompareFunction(function() { return topLevelSurfaceList.indexForId(surface1Id); }, -1);
463 tryCompareFunction(function() { return topLevelSurfaceList.indexForId(surface1Id); }, -1);
553 tryCompare(webbrowserApp.surfaceList, "count", 1);
464 tryCompare(webbrowserApp.surfaceList, "count", 1);
554− compare(webbrowserApp.state, ApplicationInfoInterface.Running);
465+ }
466+
467+ function test_swipeToClose_data() {
468+ return [
469+ { tag: "closeable", closeable: true },
470+ { tag: "not closeable", closeable: false }
471+ ]
472+ }
473+
474+ function test_swipeToClose(data) {
475+ var surface1Id = topLevelSurfaceList.nextId;
476+ var webbrowserApp = ApplicationManager.startApplication("webbrowser-app");
477+ waitUntilAppSurfaceShowsUp(surface1Id);
478+
479+ performEdgeSwipeToShowAppSpread();
480+
481+ var appDelegate = findChild(stage, "appDelegate_" + surface1Id);
482+ var dragArea = findChild(appDelegate, "dragArea")
483+ verify(dragArea);
484+ dragArea.closeable = data.closeable;
485+
486+ var oldCount = ApplicationManager.count;
487+
488+ swipeSurfaceUpwards(surface1Id);
489+
490+ tryCompare(ApplicationManager, "count", data.closeable ? oldCount - 1 : oldCount);
555 }
491 }
556
492
557 /*
493 /*
@@ -632,11 +568,10 @@ Item {
632
568
633 performEdgeSwipeToShowAppSpread();
569 performEdgeSwipeToShowAppSpread();
634
570
635− {
636− var appDelegate = findChild(phoneStage, "spreadDelegate_" + webbrowserSurfaceId);
571+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
637− verify(appDelegate);
572+ var dragArea = findChild(appDelegate, "dragArea");
638− tryCompare(appDelegate, "swipeToCloseEnabled", true);
573+ verify(dragArea);
639− }
574+ tryCompare(dragArea, "closeable", true);
640
575
641 swipeSurfaceUpwards(webbrowserSurfaceId);
576 swipeSurfaceUpwards(webbrowserSurfaceId);
642
577
tests/qmltests/Stages/tst_Splash.qml → tests/qmltests/Stage/tst_Splash.qmlrenamed+1−1
@@ -18,7 +18,7 @@ import QtQuick 2.4
18import QtTest 1.0
18import QtTest 1.0
19import Unity.Test 0.1 as UT
19import Unity.Test 0.1 as UT
20import ".."
20import ".."
21−import "../../../qml/Stages"
21+import "../../../qml/Stage"
22import Ubuntu.Components 1.3
22import Ubuntu.Components 1.3
23import Unity.Application 0.1
23import Unity.Application 0.1
24
24
tests/qmltests/Stages/tst_SpreadDelegate.qml → tests/qmltests/Stage/tst_SpreadDelegate.qmlrenamed

The content is the same.

tests/qmltests/Stages/tst_SurfaceContainer.qml → tests/qmltests/Stage/tst_SurfaceContainer.qmlrenamed+2−2
@@ -20,7 +20,7 @@ import QtTest 1.0
20import Unity.Test 0.1 as UT
20import Unity.Test 0.1 as UT
21import Ubuntu.Components 1.3
21import Ubuntu.Components 1.3
22import Unity.Application 0.1
22import Unity.Application 0.1
23−import "../../../qml/Stages"
23+import "../../../qml/Stage"
24
24
25Rectangle {
25Rectangle {
26 color: "red"
26 color: "red"
@@ -87,7 +87,7 @@ Rectangle {
87 }
87 }
88 Row {
88 Row {
89 CheckBox {id: promptCheckbox; checked: false; activeFocusOnPress: false
89 CheckBox {id: promptCheckbox; checked: false; activeFocusOnPress: false
90− enabled: surfaceContainerLoader.item.surface === null }
90+ enabled: surfaceContainerLoader.item && surfaceContainerLoader.item.surface === null }
91 Label { text: "isPromptSurface" }
91 Label { text: "isPromptSurface" }
92 }
92 }
93
93
tests/qmltests/Stages/tst_TabletStage.qml → tests/qmltests/Stage/tst_TabletStage.qmlrenamed+103−238
@@ -24,53 +24,37 @@ import Utils 0.1
24import WindowManager 0.1
24import WindowManager 0.1
25
25
26import ".."
26import ".."
27−import "../../../qml/Stages"
27+import "../../../qml/Stage"
28import "../../../qml/Components"
28import "../../../qml/Components"
29
29
30Rectangle {
30Rectangle {
31 id: root
31 id: root
32 color: "grey"
32 color: "grey"
33− width: tabletStageLoader.width + controls.width
33+ width: units.gu(160*0.7)
34− height: tabletStageLoader.height
34+ height: units.gu(100*0.7)
35
35
36 property var greeter: { fullyShown: true }
36 property var greeter: { fullyShown: true }
37
37
38− TopLevelSurfaceList {
38+ ApplicationMenuDataLoader { }
39− id: topSurfaceList
40− applicationsModel: ApplicationManager
41− }
42−
43− Loader {
44− id: tabletStageLoader
45−
46− x: ((root.width - controls.width) - width) / 2
47− y: (root.height - height) / 2
48− width: units.gu(160*0.7)
49− height: units.gu(100*0.7)
50
39
40+ Stage {
41+ id: stage
42+ anchors { fill: parent; rightMargin: units.gu(30) }
43+ dragAreaWidth: units.gu(2)
44+ interactive: true
45+ shellOrientation: Qt.LandscapeOrientation
46+ nativeWidth: width
47+ nativeHeight: height
48+ orientations: Orientations {
49+ native_: Qt.LandscapeOrientation
50+ primary: Qt.LandscapeOrientation
51+ }
51 focus: true
52 focus: true
52−
53+ mode: "stagedWithSideStage"
53− property bool itemDestroyed: false
54− sourceComponent: Component {
55− TabletStage {
56− anchors.fill: parent
57− Component.onDestruction: {
58− tabletStageLoader.itemDestroyed = true;
59− }
60− dragAreaWidth: units.gu(2)
61− maximizedAppTopMargin: units.gu(3)
62− interactive: true
63− shellOrientation: Qt.LandscapeOrientation
64− nativeWidth: width
65− nativeHeight: height
66− orientations: Orientations {
67− native_: Qt.LandscapeOrientation
68− primary: Qt.LandscapeOrientation
69− }
70− focus: true
71− applicationManager: ApplicationManager
54+ applicationManager: ApplicationManager
72− topLevelSurfaceList: topSurfaceList
55+ topLevelSurfaceList: TopLevelSurfaceList {
73− }
56+ id: topLevelSurfaceList
57+ applicationsModel: ApplicationManager
74 }
58 }
75 }
59 }
76
60
@@ -84,7 +68,7 @@ Rectangle {
84 right: parent.right
68 right: parent.right
85 }
69 }
86
70
87− // don't let mouse clicks in the controls area disturb the TabletStage behind it
71+ // don't let mouse clicks in the controls area disturb the Stage behind it
88 MouseArea { anchors.fill: parent }
72 MouseArea { anchors.fill: parent }
89
73
90 Column {
74 Column {
@@ -95,15 +79,16 @@ Rectangle {
95 id: edgeBarrierControls
79 id: edgeBarrierControls
96 text: "Drag here to pull out spread"
80 text: "Drag here to pull out spread"
97 backgroundColor: "blue"
81 backgroundColor: "blue"
98− onDragged: { tabletStageLoader.item.pushRightEdge(amount); }
82+ onDragged: { stage.pushRightEdge(amount); }
99 Component.onCompleted: {
83 Component.onCompleted: {
100− edgeBarrierControls.target = testCase.findChild(tabletStageLoader, "edgeBarrierController");
84+ edgeBarrierControls.target = testCase.findChild(stage, "edgeBarrierController");
101 }
85 }
102 }
86 }
103
87
104 Button {
88 Button {
105 text: testCase.sideStage ? testCase.sideStage.shown ? "Hide Side-stage" : "Show Side-stage" : ""
89 text: testCase.sideStage ? testCase.sideStage.shown ? "Hide Side-stage" : "Show Side-stage" : ""
106 enabled: testCase.sideStage
90 enabled: testCase.sideStage
91+ activeFocusOnPress: false
107 onClicked: {
92 onClicked: {
108 if (testCase.sideStage.shown) testCase.sideStage.hide();
93 if (testCase.sideStage.shown) testCase.sideStage.hide();
109 else testCase.sideStage.show();
94 else testCase.sideStage.show();
@@ -140,46 +125,50 @@ Rectangle {
140 name: "TabletStage"
125 name: "TabletStage"
141 when: windowShown
126 when: windowShown
142
127
143− property Item tabletStage: tabletStageLoader.status === Loader.Ready ? tabletStageLoader.item : null
128+ readonly property alias topSurfaceList: stage.topLevelSurfaceList
144− property Item sideStage: tabletStage ? findChild(tabletStage, "sideStage") : null
129+ property Item sideStage: stage ? findChild(stage, "sideStage") : null
145
130
146 function init() {
131 function init() {
147 stageSaver.clear();
132 stageSaver.clear();
148− tabletStageLoader.active = true;
149− tryCompare(tabletStageLoader, "status", Loader.Ready);
150
133
151 tryCompare(topSurfaceList, "count", 1);
134 tryCompare(topSurfaceList, "count", 1);
152 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
135 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
153
136
154 // this is very strange, but sometimes the test starts without
137 // this is very strange, but sometimes the test starts without
155− // TabletStage components having finished loading themselves
138+ // Stage components having finished loading themselves
156 var appWindow = null
139 var appWindow = null
157 while (!appWindow) {
140 while (!appWindow) {
158 appWindow = findAppWindowForSurfaceId(topSurfaceList.idAt(0));
141 appWindow = findAppWindowForSurfaceId(topSurfaceList.idAt(0));
159 if (!appWindow) {
142 if (!appWindow) {
160− console.log("didn't find unity8-dash appWindow in " + tabletStage + ". Trying again...");
143+ console.log("didn't find unity8-dash appWindow in Stage. Trying again...");
161 wait(50);
144 wait(50);
162 }
145 }
163 }
146 }
164
147
165 waitUntilAppSurfaceShowsUp(topSurfaceList.idAt(0));
148 waitUntilAppSurfaceShowsUp(topSurfaceList.idAt(0));
166 sideStage.hideNow()
149 sideStage.hideNow()
150+ tryCompare(sideStage, "x", stage.width)
167 }
151 }
168
152
169 function cleanup() {
153 function cleanup() {
170− tabletStageLoader.itemDestroyed = false;
154+ ApplicationManager.requestFocusApplication("unity8-dash");
171− tabletStageLoader.active = false;
155+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
172−
156+ tryCompare(stage, "state", "stagedWithSideStage");
173− tryCompare(tabletStageLoader, "status", Loader.Null);
157+ waitForRendering(stage);
174− tryCompare(tabletStageLoader, "item", null);
175− // Loader.status might be Loader.Null and Loader.item might be null but the Loader
176− // actually took place. Likely because Loader waits until the next event loop
177− // iteration to do its work. So to ensure the reload, we will wait until the
178− // Shell instance gets destroyed.
179− tryCompare(tabletStageLoader, "itemDestroyed", true);
180
158
181 killApps();
159 killApps();
160+
161+ // wait for Stage to stabilize back into its initial state
162+ var appRepeater = findChild(stage, "appRepeater");
163+ tryCompare(appRepeater, "count", 1);
164+ tryCompare(appRepeater.itemAt(0), "x", 0);
165+
166+ sideStage.hideNow();
167+ tryCompare(sideStage, "x", stage.width)
168+ waitForRendering(stage)
169+
182 WindowStateStorage.clear();
170 WindowStateStorage.clear();
171+ wait(100)
183 }
172 }
184
173
185 function waitUntilAppSurfaceShowsUp(surfaceId) {
174 function waitUntilAppSurfaceShowsUp(surfaceId) {
@@ -191,7 +180,7 @@ Rectangle {
191 }
180 }
192
181
193 function findAppWindowForSurfaceId(surfaceId) {
182 function findAppWindowForSurfaceId(surfaceId) {
194− var spreadDelegate = findChild(tabletStage, "spreadDelegate_" + surfaceId);
183+ var spreadDelegate = findChild(stage, "appDelegate_" + surfaceId);
195 if (!spreadDelegate) {
184 if (!spreadDelegate) {
196 return null;
185 return null;
197 }
186 }
@@ -210,7 +199,7 @@ Rectangle {
210
199
211 function waitUntilAppDelegateStopsMoving(targetSurfaceId)
200 function waitUntilAppDelegateStopsMoving(targetSurfaceId)
212 {
201 {
213− var targetAppDelegate = findChild(tabletStage, "spreadDelegate_" + targetSurfaceId);
202+ var targetAppDelegate = findChild(stage, "appDelegate_" + targetSurfaceId);
214 verify(targetAppDelegate);
203 verify(targetAppDelegate);
215 var lastValue = undefined;
204 var lastValue = undefined;
216 do {
205 do {
@@ -220,15 +209,9 @@ Rectangle {
220 }
209 }
221
210
222 function performEdgeSwipeToShowAppSpread() {
211 function performEdgeSwipeToShowAppSpread() {
223− touchFlick(tabletStage,
212+ touchFlick(stage, stage.width - (stage.dragAreaWidth / 2), stage.height / 2, stage.x + 1, stage.height / 2);
224− tabletStage.width - (tabletStage.dragAreaWidth / 2), tabletStage.height / 2,
225− tabletStage.x + 1, tabletStage.height / 2);
226
213
227− var spreadView = findChild(tabletStage, "spreadView");
214+ tryCompare(stage, "state", "spread");
228− verify(spreadView);
229− tryCompare(spreadView, "phase", 2);
230− tryCompare(spreadView, "flicking", false);
231− tryCompare(spreadView, "moving", false);
232 }
215 }
233
216
234 function swipeSurfaceUpwards(surfaceId) {
217 function swipeSurfaceUpwards(surfaceId) {
@@ -244,17 +227,12 @@ Rectangle {
244
227
245 function dragToSideStage(surfaceId) {
228 function dragToSideStage(surfaceId) {
246 sideStage.showNow();
229 sideStage.showNow();
247− var targetAppDelegate = findChild(tabletStage, "spreadDelegate_" + surfaceId);
230+ var targetAppDelegate = findChild(stage, "appDelegate_" + surfaceId);
248
231
249− var pos = tabletStage.width - sideStage.width - (tabletStage.width - sideStage.width) / 2;
232+ var pos = stage.width - sideStage.width - (stage.width - sideStage.width) / 2;
250− var end_pos = tabletStage.width - sideStage.width / 2;
233+ var end_pos = stage.width - sideStage.width / 2;
251
234
252− multiTouchDragUntil([0,1,2],
235+ multiTouchDragUntil([0,1,2], stage, pos, stage.height / 2, units.gu(3), 0,
253− tabletStage,
254− pos,
255− tabletStage.height / 2,
256− units.gu(3),
257− 0,
258 function() {
236 function() {
259 pos += units.gu(3);
237 pos += units.gu(3);
260 return sideStage.shown && !sideStage.showAnimation.running &&
238 return sideStage.shown && !sideStage.showAnimation.running &&
@@ -265,16 +243,16 @@ Rectangle {
265
243
266 function dragToMainStage(surfaceId) {
244 function dragToMainStage(surfaceId) {
267 sideStage.showNow();
245 sideStage.showNow();
268− var targetAppDelegate = findChild(tabletStage, "spreadDelegate_" + surfaceId);
246+ var targetAppDelegate = findChild(stage, "appDelegate_" + surfaceId);
269 verify(targetAppDelegate);
247 verify(targetAppDelegate);
270
248
271− var pos = tabletStage.width - sideStage.width / 2;
249+ var pos = stage.width - sideStage.width / 2;
272− var end_pos = tabletStage.width - sideStage.width - (tabletStage.width - sideStage.width) / 2;
250+ var end_pos = stage.width - sideStage.width - (stage.width - sideStage.width) / 2;
273
251
274 multiTouchDragUntil([0,1,2],
252 multiTouchDragUntil([0,1,2],
275− tabletStage,
253+ stage,
276 pos,
254 pos,
277− tabletStage.height / 2,
255+ stage.height / 2,
278 -units.gu(3),
256 -units.gu(3),
279 0,
257 0,
280 function() {
258 function() {
@@ -290,7 +268,7 @@ Rectangle {
290 var webbrowserSurfaceId = topSurfaceList.nextId;
268 var webbrowserSurfaceId = topSurfaceList.nextId;
291 webbrowserCheckBox.checked = true;
269 webbrowserCheckBox.checked = true;
292 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
270 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
293− var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
271+ var webbrowserDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
294 verify(webbrowserDelegate);
272 verify(webbrowserDelegate);
295 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
273 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
296 var webbrowserWindow = findAppWindowForSurfaceId(webbrowserSurfaceId);
274 var webbrowserWindow = findAppWindowForSurfaceId(webbrowserSurfaceId);
@@ -303,7 +281,7 @@ Rectangle {
303 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
281 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
304
282
305 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
283 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
306− var dialerDelegate = findChild(tabletStage, "spreadDelegate_" + dialerSurfaceId);
284+ var dialerDelegate = findChild(stage, "appDelegate_" + dialerSurfaceId);
307 verify(dialerDelegate);
285 verify(dialerDelegate);
308 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
286 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
309
287
@@ -336,17 +314,18 @@ Rectangle {
336
314
337 performEdgeSwipeToShowAppSpread();
315 performEdgeSwipeToShowAppSpread();
338
316
339− var appDelegate = findChild(tabletStage, "spreadDelegate_" + dialerSurfaceId);
317+ var appDelegate = findChild(stage, "appDelegate_" + dialerSurfaceId);
340− verify(appDelegate);
318+ var dragArea = findChild(appDelegate, "dragArea");
319+ verify(dragArea);
341 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
320 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
342− tryCompare(appDelegate, "swipeToCloseEnabled", true);
321+ tryCompare(dragArea, "closeable", true);
343
322
344 swipeSurfaceUpwards(dialerSurfaceId);
323 swipeSurfaceUpwards(dialerSurfaceId);
345
324
346 // Check that dialer-app has been closed
325 // Check that dialer-app has been closed
347
326
348 tryCompareFunction(function() {
327 tryCompareFunction(function() {
349− return findChild(tabletStage, "appWindow_" + dialerCheckBox.appId);
328+ return findChild(stage, "appWindow_" + dialerCheckBox.appId);
350 }, null);
329 }, null);
351
330
352 tryCompareFunction(function() {
331 tryCompareFunction(function() {
@@ -359,7 +338,7 @@ Rectangle {
359 webbrowserCheckBox.checked = true;
338 webbrowserCheckBox.checked = true;
360 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
339 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
361 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
340 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
362− var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
341+ var webbrowserDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
363 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
342 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
364
343
365 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Running);
344 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Running);
@@ -368,7 +347,7 @@ Rectangle {
368 galleryCheckBox.checked = true;
347 galleryCheckBox.checked = true;
369 waitUntilAppSurfaceShowsUp(gallerySurfaceId);
348 waitUntilAppSurfaceShowsUp(gallerySurfaceId);
370 var galleryApp = ApplicationManager.findApplication(galleryCheckBox.appId);
349 var galleryApp = ApplicationManager.findApplication(galleryCheckBox.appId);
371− var galleryDelegate = findChild(tabletStage, "spreadDelegate_" + gallerySurfaceId);
350+ var galleryDelegate = findChild(stage, "appDelegate_" + gallerySurfaceId);
372 compare(galleryDelegate.stage, ApplicationInfoInterface.MainStage);
351 compare(galleryDelegate.stage, ApplicationInfoInterface.MainStage);
373
352
374 tryCompare(galleryApp, "state", ApplicationInfoInterface.Running);
353 tryCompare(galleryApp, "state", ApplicationInfoInterface.Running);
@@ -389,7 +368,7 @@ Rectangle {
389 WindowStateStorage.saveStage(facebookCheckBox.appId, ApplicationInfoInterface.SideStage)
368 WindowStateStorage.saveStage(facebookCheckBox.appId, ApplicationInfoInterface.SideStage)
390 WindowStateStorage.saveStage(dialerCheckBox.appId, ApplicationInfoInterface.SideStage)
369 WindowStateStorage.saveStage(dialerCheckBox.appId, ApplicationInfoInterface.SideStage)
391
370
392− var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
371+ var stagesPriv = findInvisibleChild(stage, "DesktopStagePrivate");
393 verify(stagesPriv);
372 verify(stagesPriv);
394
373
395 // launch two main stage apps
374 // launch two main stage apps
@@ -398,7 +377,7 @@ Rectangle {
398 var webbrowserSurfaceId = topSurfaceList.nextId;
377 var webbrowserSurfaceId = topSurfaceList.nextId;
399 webbrowserCheckBox.checked = true;
378 webbrowserCheckBox.checked = true;
400 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
379 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
401− var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
380+ var webbrowserDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
402 verify(webbrowserDelegate);
381 verify(webbrowserDelegate);
403 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
382 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
404 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
383 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
@@ -407,7 +386,7 @@ Rectangle {
407 galleryCheckBox.checked = true;
386 galleryCheckBox.checked = true;
408 waitUntilAppSurfaceShowsUp(gallerySurfaceId);
387 waitUntilAppSurfaceShowsUp(gallerySurfaceId);
409 var galleryApp = ApplicationManager.findApplication(galleryCheckBox.appId);
388 var galleryApp = ApplicationManager.findApplication(galleryCheckBox.appId);
410− var galleryDelegate = findChild(tabletStage, "spreadDelegate_" + gallerySurfaceId);
389+ var galleryDelegate = findChild(stage, "appDelegate_" + gallerySurfaceId);
411 compare(galleryDelegate.stage, ApplicationInfoInterface.MainStage);
390 compare(galleryDelegate.stage, ApplicationInfoInterface.MainStage);
412
391
413 compare(stagesPriv.mainStageAppId, galleryCheckBox.appId);
392 compare(stagesPriv.mainStageAppId, galleryCheckBox.appId);
@@ -419,14 +398,14 @@ Rectangle {
419 dialerCheckBox.checked = true;
398 dialerCheckBox.checked = true;
420 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
399 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
421 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
400 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
422− var dialerDelegate = findChild(tabletStage, "spreadDelegate_" + dialerSurfaceId);
401+ var dialerDelegate = findChild(stage, "appDelegate_" + dialerSurfaceId);
423 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
402 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
424
403
425 var facebookSurfaceId = topSurfaceList.nextId;
404 var facebookSurfaceId = topSurfaceList.nextId;
426 facebookCheckBox.checked = true;
405 facebookCheckBox.checked = true;
427 waitUntilAppSurfaceShowsUp(facebookSurfaceId);
406 waitUntilAppSurfaceShowsUp(facebookSurfaceId);
428 var facebookApp = ApplicationManager.findApplication(facebookCheckBox.appId);
407 var facebookApp = ApplicationManager.findApplication(facebookCheckBox.appId);
429− var facebookDelegate = findChild(tabletStage, "spreadDelegate_" + facebookSurfaceId);
408+ var facebookDelegate = findChild(stage, "appDelegate_" + facebookSurfaceId);
430 compare(facebookDelegate.stage, ApplicationInfoInterface.SideStage);
409 compare(facebookDelegate.stage, ApplicationInfoInterface.SideStage);
431
410
432 compare(stagesPriv.sideStageAppId, facebookCheckBox.appId);
411 compare(stagesPriv.sideStageAppId, facebookCheckBox.appId);
@@ -461,40 +440,31 @@ Rectangle {
461 webbrowserCheckBox.checked = true;
440 webbrowserCheckBox.checked = true;
462 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
441 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
463 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
442 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
464− var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
443+ var webbrowserDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
465 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
444 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
466
445
467 var dialerSurfaceId = topSurfaceList.nextId;
446 var dialerSurfaceId = topSurfaceList.nextId;
468 dialerCheckBox.checked = true;
447 dialerCheckBox.checked = true;
469 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
448 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
470 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
449 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
471− var dialerDelegate = findChild(tabletStage, "spreadDelegate_" + dialerSurfaceId);
450+ var dialerDelegate = findChild(stage, "appDelegate_" + dialerSurfaceId);
472 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
451 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
473
452
474
453
475 compare(webbrowserApp.requestedState, ApplicationInfoInterface.RequestedRunning);
454 compare(webbrowserApp.requestedState, ApplicationInfoInterface.RequestedRunning);
476 compare(dialerApp.requestedState, ApplicationInfoInterface.RequestedRunning);
455 compare(dialerApp.requestedState, ApplicationInfoInterface.RequestedRunning);
477
456
478− tabletStage.suspended = true;
457+ stage.suspended = true;
479
458
480 tryCompare(webbrowserApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
459 tryCompare(webbrowserApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
481 tryCompare(dialerApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
460 tryCompare(dialerApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
482
461
483− tabletStage.suspended = false;
462+ stage.suspended = false;
484
463
485 tryCompare(webbrowserApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
464 tryCompare(webbrowserApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
486 tryCompare(dialerApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
465 tryCompare(dialerApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
487 }
466 }
488
467
489− function test_mouseEdgePush() {
490− var spreadView = findChild(tabletStageLoader, "spreadView")
491− mouseMove(tabletStageLoader, tabletStageLoader.width - 1, units.gu(10));
492− for (var i = 0; i < units.gu(10); i++) {
493− tabletStageLoader.item.pushRightEdge(1);
494− }
495− tryCompare(spreadView, "phase", 2);
496− }
497−
498 function test_threeFingerTapOpensSideStage_data() {
468 function test_threeFingerTapOpensSideStage_data() {
499 return [
469 return [
500 { tag: "1 finger", touchIds: [0], result: false },
470 { tag: "1 finger", touchIds: [0], result: false },
@@ -505,7 +475,7 @@ Rectangle {
505 }
475 }
506
476
507 function test_threeFingerTapOpensSideStage(data) {
477 function test_threeFingerTapOpensSideStage(data) {
508− multiTouchTap(data.touchIds, tabletStage, tabletStage.width / 2, tabletStage.height / 2);
478+ multiTouchTap(data.touchIds, stage, stage.width / 2, stage.height / 2);
509 wait(200);
479 wait(200);
510 tryCompare(sideStage, "shown", data.result);
480 tryCompare(sideStage, "shown", data.result);
511 }
481 }
@@ -523,18 +493,13 @@ Rectangle {
523 function test_threeFingerTapClosesSideStage(data) {
493 function test_threeFingerTapClosesSideStage(data) {
524 sideStage.showNow();
494 sideStage.showNow();
525
495
526− multiTouchTap(data.touchIds, tabletStage, tabletStage.width / 2, tabletStage.height / 2);
496+ multiTouchTap(data.touchIds, stage, stage.width / 2, stage.height / 2);
527 wait(200);
497 wait(200);
528 tryCompare(sideStage, "shown", data.result);
498 tryCompare(sideStage, "shown", data.result);
529 }
499 }
530
500
531 function test_threeFingerDragOpensSidestage() {
501 function test_threeFingerDragOpensSidestage() {
532− multiTouchDragUntil([0,1,2],
502+ multiTouchDragUntil([0,1,2], stage, stage.width / 4, stage.height / 4, units.gu(1), 0,
533− tabletStage,
534− tabletStage.width / 4,
535− tabletStage.height / 4,
536− units.gu(1),
537− 0,
538 function() { return sideStage.shown; });
503 function() { return sideStage.shown; });
539 }
504 }
540
505
@@ -546,7 +511,7 @@ Rectangle {
546 }
511 }
547
512
548 function test_applicationLoadsInDefaultStage(data) {
513 function test_applicationLoadsInDefaultStage(data) {
549− var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
514+ var stagesPriv = findInvisibleChild(stage, "DesktopStagePrivate");
550 verify(stagesPriv);
515 verify(stagesPriv);
551
516
552 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
517 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
@@ -570,7 +535,7 @@ Rectangle {
570 function test_applicationLoadsInSavedStage(data) {
535 function test_applicationLoadsInSavedStage(data) {
571 WindowStateStorage.saveStage(webbrowserCheckBox.appId, data.stage)
536 WindowStateStorage.saveStage(webbrowserCheckBox.appId, data.stage)
572
537
573− var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
538+ var stagesPriv = findInvisibleChild(stage, "DesktopStagePrivate");
574 verify(stagesPriv);
539 verify(stagesPriv);
575
540
576 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
541 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
@@ -595,7 +560,7 @@ Rectangle {
595 WindowStateStorage.saveStage(webbrowserCheckBox.appId, data.fromStage);
560 WindowStateStorage.saveStage(webbrowserCheckBox.appId, data.fromStage);
596 stageSaver.clear();
561 stageSaver.clear();
597
562
598− var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
563+ var stagesPriv = findInvisibleChild(stage, "DesktopStagePrivate");
599 verify(stagesPriv);
564 verify(stagesPriv);
600
565
601 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
566 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
@@ -618,67 +583,38 @@ Rectangle {
618
583
619 function test_loadSideStageByDraggingFromMainStage() {
584 function test_loadSideStageByDraggingFromMainStage() {
620 sideStage.showNow();
585 sideStage.showNow();
586+ print("sidestage now shown. launching browser")
621 var webbrowserSurfaceId = topSurfaceList.nextId;
587 var webbrowserSurfaceId = topSurfaceList.nextId;
622 webbrowserCheckBox.checked = true;
588 webbrowserCheckBox.checked = true;
623 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
589 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
624
590
625− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
591+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
626 verify(appDelegate);
592 verify(appDelegate);
593+ waitForRendering(stage);
627 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
594 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
628
595
629 dragToSideStage(webbrowserSurfaceId);
596 dragToSideStage(webbrowserSurfaceId);
630
597
631− var spreadView = findChild(tabletStageLoader, "spreadView")
632− tryCompare(spreadView, "surfaceDragging", false);
633 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
598 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
634 }
599 }
635
600
636− function test_unloadSideStageByDraggingFromStageStage() {
601+ function test_unloadSideStageByDraggingFromSideStage() {
637 sideStage.showNow();
602 sideStage.showNow();
638 WindowStateStorage.saveStage(webbrowserCheckBox.appId, ApplicationInfoInterface.SideStage)
603 WindowStateStorage.saveStage(webbrowserCheckBox.appId, ApplicationInfoInterface.SideStage)
639 var webbrowserSurfaceId = topSurfaceList.nextId;
604 var webbrowserSurfaceId = topSurfaceList.nextId;
640 webbrowserCheckBox.checked = true;
605 webbrowserCheckBox.checked = true;
641 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
606 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
642
607
643− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
608+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
644 verify(appDelegate);
609 verify(appDelegate);
610+ waitForRendering(stage);
645 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
611 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
646
612
647 dragToMainStage(webbrowserSurfaceId);
613 dragToMainStage(webbrowserSurfaceId);
648
614
649− var spreadView = findChild(tabletStageLoader, "spreadView")
650− tryCompare(spreadView, "surfaceDragging", false);
651 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
615 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
652 }
616 }
653
617
654− function test_closeSurfaceOfMultiSurfaceApp() {
655− var surface1Id = topSurfaceList.nextId;
656− webbrowserCheckBox.checked = true;
657− waitUntilAppSurfaceShowsUp(surface1Id);
658− var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
659−
660− var surface2Id = topSurfaceList.nextId;
661− verify(surface1Id !== surface2Id); // sanity checking
662− webbrowserCheckBox.createSurface();
663− waitUntilAppSurfaceShowsUp(surface2Id);
664−
665− performEdgeSwipeToShowAppSpread();
666−
667− var appDelegate = findChild(tabletStage, "spreadDelegate_" + surface1Id);
668− verify(appDelegate);
669− tryCompare(appDelegate, "swipeToCloseEnabled", true);
670−
671− compare(webbrowserApp.surfaceList.count, 2);
672− compare(webbrowserApp.state, ApplicationInfoInterface.Running);
673−
674− swipeSurfaceUpwards(surface1Id);
675−
676− // Surface must eventually be gone
677− tryCompareFunction(function() { return topSurfaceList.indexForId(surface1Id); }, -1);
678− tryCompare(webbrowserApp.surfaceList, "count", 1);
679− compare(webbrowserApp.state, ApplicationInfoInterface.Running);
680− }
681−
682 /*
618 /*
683 1- Suspended app gets killed behind the scenes, causing its surface to go zombie.
619 1- Suspended app gets killed behind the scenes, causing its surface to go zombie.
684 2- Surface gets screenshotted and removed. Its slot in the topSurfaceList remains,
620 2- Surface gets screenshotted and removed. Its slot in the topSurfaceList remains,
@@ -724,64 +660,12 @@ Rectangle {
724 compare(webbrowserApp.surfaceList.count, 1);
660 compare(webbrowserApp.surfaceList.count, 1);
725 }
661 }
726
662
727− /*
728− 1 - user suspends an application (ie, focus a surface from a different application)
729− 2 - That suspended application gets killed, causing its surface to go zombie
730− 3 - user goes to spread and closes that zombie surface. Actually, by that time
731− Tablet shell will be displaying a screenshot of it instead, so there's no
732− MirSurface whatsoever backing it up.
733− */
734− function test_closeZombieSurface()
735− {
736− compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
737− var dashSurfaceId = topSurfaceList.idAt(0);
738− var dashSurface = topSurfaceList.surfaceAt(0);
739−
740− var webbrowserSurfaceId = topSurfaceList.nextId;
741− webbrowserCheckBox.checked = true;
742− waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
743− var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
744−
745− switchToSurface(dashSurfaceId);
746−
747− tryCompare(MirFocusController, "focusedSurface", dashSurface);
748− tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Suspended);
749−
750− compare(webbrowserApp.surfaceList.count, 1);
751−
752− // simulate the suspended app being killed by the out-of-memory daemon
753− webbrowserApp.surfaceList.get(0).setLive(false);
754−
755− // wait until the surface is gone
756− tryCompare(webbrowserApp.surfaceList, "count", 0);
757− compare(topSurfaceList.surfaceAt(topSurfaceList.indexForId(webbrowserSurfaceId)), null);
758−
759− performEdgeSwipeToShowAppSpread();
760−
761− {
762− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
763− verify(appDelegate);
764− tryCompare(appDelegate, "swipeToCloseEnabled", true);
765− }
766−
767− swipeSurfaceUpwards(webbrowserSurfaceId);
768−
769− // webbrowser entry is nowhere to be seen
770− tryCompareFunction(function(){return topSurfaceList.indexForId(webbrowserSurfaceId);}, -1);
771−
772− // nor is its app
773− compare(ApplicationManager.findApplication(webbrowserCheckBox.appId), null);
774−
775− // only unity8-dash surface is left
776− compare(topSurfaceList.count, 1);
777− }
778−
779 function test_draggingSurfaceKeepsSurfaceFocus() {
663 function test_draggingSurfaceKeepsSurfaceFocus() {
780 var webbrowserSurfaceId = topSurfaceList.nextId;
664 var webbrowserSurfaceId = topSurfaceList.nextId;
781 webbrowserCheckBox.checked = true;
665 webbrowserCheckBox.checked = true;
782 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
666 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
783
667
784− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
668+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
785 verify(appDelegate);
669 verify(appDelegate);
786 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
670 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
787
671
@@ -789,9 +673,8 @@ Rectangle {
789
673
790 dragToSideStage(webbrowserSurfaceId);
674 dragToSideStage(webbrowserSurfaceId);
791
675
792− var spreadView = findChild(tabletStageLoader, "spreadView")
793− tryCompare(spreadView, "surfaceDragging", false);
794 tryCompare(appDelegate.surface, "activeFocus", true);
676 tryCompare(appDelegate.surface, "activeFocus", true);
677+ tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
795 }
678 }
796
679
797 function test_dashDoesNotDragToSidestage() {
680 function test_dashDoesNotDragToSidestage() {
@@ -799,59 +682,41 @@ Rectangle {
799 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
682 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
800 var dashSurfaceId = topSurfaceList.idAt(0);
683 var dashSurfaceId = topSurfaceList.idAt(0);
801
684
802− var appDelegate = findChild(tabletStage, "spreadDelegate_" + dashSurfaceId);
685+ var appDelegate = findChild(stage, "appDelegate_" + dashSurfaceId);
803 verify(appDelegate);
686 verify(appDelegate);
804 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
687 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
805
688
806− var pos = tabletStage.width - sideStage.width - (tabletStage.width - sideStage.width) / 2;
689+ var pos = stage.width - sideStage.width - (stage.width - sideStage.width) / 2;
807− var end_pos = tabletStage.width - sideStage.width / 2;
690+ var end_pos = stage.width - sideStage.width / 2;
808
691
809− multiTouchDragUntil([0,1,2],
692+ multiTouchDragUntil([0,1,2], stage, pos, stage.height / 2, units.gu(3), 0,
810− tabletStage,
811− pos,
812− tabletStage.height / 2,
813− units.gu(3),
814− 0,
815 function() {
693 function() {
816 pos += units.gu(3);
694 pos += units.gu(3);
817 return sideStage.shown && !sideStage.showAnimation.running &&
695 return sideStage.shown && !sideStage.showAnimation.running &&
818 pos >= end_pos;
696 pos >= end_pos;
819 });
697 });
820
698
821− var spreadView = findChild(tabletStageLoader, "spreadView")
699+ waitForRendering(stage);
822− tryCompare(spreadView, "surfaceDragging", false);
823 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
700 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
824 }
701 }
825
702
826− function test_switchStageOnRotation() {
703+ function test_switchRestoreStageOnRotation() {
827 WindowStateStorage.saveStage(webbrowserCheckBox.appId, ApplicationInfoInterface.SideStage)
704 WindowStateStorage.saveStage(webbrowserCheckBox.appId, ApplicationInfoInterface.SideStage)
828 var webbrowserSurfaceId = topSurfaceList.nextId;
705 var webbrowserSurfaceId = topSurfaceList.nextId;
829 webbrowserCheckBox.checked = true;
706 webbrowserCheckBox.checked = true;
830 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
707 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
831
708
832− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
709+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
833 verify(appDelegate);
710 verify(appDelegate);
834 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
711 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
835
712
836− tabletStage.shellOrientation = Qt.PortraitOrientation;
837− tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
838− }
839−
840− function test_restoreOriginalStageOnRotation() {
841− var webbrowserSurfaceId = topSurfaceList.nextId;
842− webbrowserCheckBox.checked = true;
843− waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
844−
845− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
846− verify(appDelegate);
847−
848 dragToSideStage(webbrowserSurfaceId);
713 dragToSideStage(webbrowserSurfaceId);
849
714
850 // will be in sidestage now
715 // will be in sidestage now
851− tabletStage.shellOrientation = Qt.PortraitOrientation;
716+ stage.shellOrientation = Qt.PortraitOrientation;
852 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
717 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
853
718
854− tabletStage.shellOrientation = Qt.LandscapeOrientation;
719+ stage.shellOrientation = Qt.LandscapeOrientation;
855 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
720 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
856 }
721 }
857
722
@@ -860,25 +725,25 @@ Rectangle {
860 webbrowserCheckBox.checked = true;
725 webbrowserCheckBox.checked = true;
861 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
726 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
862
727
863− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
728+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
864 verify(appDelegate);
729 verify(appDelegate);
865
730
866 dragToSideStage(webbrowserSurfaceId);
731 dragToSideStage(webbrowserSurfaceId);
867 // will be in sidestage now
732 // will be in sidestage now
868− tabletStage.shellOrientation = Qt.PortraitOrientation;
733+ stage.shellOrientation = Qt.PortraitOrientation;
869 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
734 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
870
735
871 webbrowserCheckBox.checked = false;
736 webbrowserCheckBox.checked = false;
872 tryCompare(ApplicationManager, "count", 1);
737 tryCompare(ApplicationManager, "count", 1);
873
738
874 // back to landscape
739 // back to landscape
875− tabletStage.shellOrientation = Qt.LandscapeOrientation;
740+ stage.shellOrientation = Qt.LandscapeOrientation;
876
741
877 webbrowserSurfaceId = topSurfaceList.nextId;
742 webbrowserSurfaceId = topSurfaceList.nextId;
878 webbrowserCheckBox.checked = true;
743 webbrowserCheckBox.checked = true;
879 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
744 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
880
745
881− appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
746+ appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
882 verify(appDelegate);
747 verify(appDelegate);
883 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
748 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
884 }
749 }
tests/qmltests/Stages/tst_WindowDecoration.qml → tests/qmltests/Stage/tst_WindowDecoration.qmlrenamed+4−3
@@ -24,7 +24,8 @@ import Unity.Test 0.1
24import Utils 0.1
24import Utils 0.1
25import QMenuModel 0.1
25import QMenuModel 0.1
26
26
27−import "../../../qml/Stages"
27+import ".."
28+import "../../../qml/Stage"
28
29
29Item {
30Item {
30 id: root
31 id: root
@@ -46,7 +47,7 @@ Item {
46 property string name: "webbrowser"
47 property string name: "webbrowser"
47 }
48 }
48
49
49− DesktopMenuData { id: desktopMenuData }
50+ ApplicationMenuDataLoader { id: menuData }
50
51
51 Rectangle {
52 Rectangle {
52 anchors {
53 anchors {
@@ -77,7 +78,7 @@ Item {
77 menu: menuBackend
78 menu: menuBackend
78 UnityMenuModel {
79 UnityMenuModel {
79 id: menuBackend
80 id: menuBackend
80− modelData: desktopMenuData.testData
81+ modelData: menuData.generateTestData(5, 3, 3, "menu")
81 onActivated: log.text = "Activated " + action + "\n" + log.text
82 onActivated: log.text = "Activated " + action + "\n" + log.text
82 }
83 }
83
84
tests/qmltests/Stages/tst_WindowResizeArea.qml → tests/qmltests/Stage/tst_WindowResizeArea.qmlrenamed+40−36
@@ -20,7 +20,7 @@ import QtTest 1.0
20import Unity.Test 0.1
20import Unity.Test 0.1
21import ".."
21import ".."
22import "../../../qml/Components/PanelState"
22import "../../../qml/Components/PanelState"
23−import "../../../qml/Stages"
23+import "../../../qml/Stage"
24import Ubuntu.Components 1.3
24import Ubuntu.Components 1.3
25import Ubuntu.Components.ListItems 1.3 as ListItem
25import Ubuntu.Components.ListItems 1.3 as ListItem
26import Unity.Application 0.1
26import Unity.Application 0.1
@@ -34,7 +34,7 @@ Item {
34 Binding {
34 Binding {
35 target: PanelState
35 target: PanelState
36 property: "panelHeight"
36 property: "panelHeight"
37− value: units.gu(2)
37+ value: units.gu(3)
38 }
38 }
39
39
40 Component {
40 Component {
@@ -46,12 +46,16 @@ Item {
46 property alias resizeAreaMinHeight: windowResizeArea.minHeight
46 property alias resizeAreaMinHeight: windowResizeArea.minHeight
47 x: requestedX
47 x: requestedX
48 y: requestedY
48 y: requestedY
49− property real requestedX: units.gu(20)
49+ property real requestedX: windowedX
50− property real requestedY: units.gu(20)
50+ property real requestedY: windowedY
51 width: requestedWidth
51 width: requestedWidth
52 height: requestedHeight
52 height: requestedHeight
53− property real requestedWidth
53+ property real requestedWidth: windowedWidth
54− property real requestedHeight
54+ property real requestedHeight: windowedHeight
55+ property real windowedX: units.gu(20)
56+ property real windowedY: units.gu(20)
57+ property real windowedWidth
58+ property real windowedHeight
55 property real minimumWidth: 0
59 property real minimumWidth: 0
56 property real minimumHeight: 0
60 property real minimumHeight: 0
57 property real maximumWidth: 0
61 property real maximumWidth: 0
@@ -236,10 +240,10 @@ Item {
236 property var fakeWindow: windowLoader.item
240 property var fakeWindow: windowLoader.item
237
241
238 function init() {
242 function init() {
239− fakeWindow.requestedX = units.gu(20)
243+ fakeWindow.windowedX = units.gu(20)
240− fakeWindow.requestedY = units.gu(20)
244+ fakeWindow.windowedY = units.gu(20)
241− fakeWindow.requestedWidth = units.gu(20)
245+ fakeWindow.windowedWidth = units.gu(20)
242− fakeWindow.requestedHeight = units.gu(20)
246+ fakeWindow.windowedHeight = units.gu(20)
243 fakeWindow.resizeAreaMinWidth = units.gu(15);
247 fakeWindow.resizeAreaMinWidth = units.gu(15);
244 fakeWindow.resizeAreaMinHeight = units.gu(10);
248 fakeWindow.resizeAreaMinHeight = units.gu(10);
245 fakeWindow.minimumWidth = 0;
249 fakeWindow.minimumWidth = 0;
@@ -264,8 +268,8 @@ Item {
264 }
268 }
265
269
266 function test_resizeWindowRightBottom(data) {
270 function test_resizeWindowRightBottom(data) {
267− var initialWindowX = fakeWindow.requestedX;
271+ var initialWindowX = fakeWindow.windowedX;
268− var initialWindowY = fakeWindow.requestedY;
272+ var initialWindowY = fakeWindow.windowedY;
269 var initialWindowWidth = fakeWindow.width
273 var initialWindowWidth = fakeWindow.width
270 var initialWindowHeight = fakeWindow.height
274 var initialWindowHeight = fakeWindow.height
271
275
@@ -290,8 +294,8 @@ Item {
290 }
294 }
291
295
292 function test_resizeWindowLeftTop(data) {
296 function test_resizeWindowLeftTop(data) {
293− var initialWindowX = fakeWindow.requestedX;
297+ var initialWindowX = fakeWindow.windowedX;
294− var initialWindowY = fakeWindow.requestedY;
298+ var initialWindowY = fakeWindow.windowedY;
295 var initialWindowWidth = fakeWindow.width
299 var initialWindowWidth = fakeWindow.width
296 var initialWindowHeight = fakeWindow.height
300 var initialWindowHeight = fakeWindow.height
297
301
@@ -309,8 +313,8 @@ Item {
309 }
313 }
310
314
311 function test_saveRestoreSize() {
315 function test_saveRestoreSize() {
312− var initialWindowX = fakeWindow.requestedX;
316+ var initialWindowX = fakeWindow.windowedX;
313− var initialWindowY = fakeWindow.requestedY;
317+ var initialWindowY = fakeWindow.windowedY;
314 var initialWindowWidth = fakeWindow.width
318 var initialWindowWidth = fakeWindow.width
315 var initialWindowHeight = fakeWindow.height
319 var initialWindowHeight = fakeWindow.height
316
320
@@ -342,8 +346,8 @@ Item {
342 }
346 }
343
347
344 function test_resizeSmallerAndLarger(data) {
348 function test_resizeSmallerAndLarger(data) {
345− var initialWindowX = fakeWindow.requestedX;
349+ var initialWindowX = fakeWindow.windowedX;
346− var initialWindowY = fakeWindow.requestedY;
350+ var initialWindowY = fakeWindow.windowedY;
347 var initialWindowWidth = fakeWindow.width
351 var initialWindowWidth = fakeWindow.width
348 var initialWindowHeight = fakeWindow.height
352 var initialWindowHeight = fakeWindow.height
349
353
@@ -358,18 +362,18 @@ Item {
358 }
362 }
359
363
360 function test_saveRestoreMaximized() {
364 function test_saveRestoreMaximized() {
361− var initialWindowX = fakeWindow.requestedX;
365+ var initialWindowX = fakeWindow.windowedX;
362− var initialWindowY = fakeWindow.requestedY;
366+ var initialWindowY = fakeWindow.windowedY;
363
367
364 var moveDelta = units.gu(5);
368 var moveDelta = units.gu(5);
365
369
366− fakeWindow.requestedX = initialWindowX + moveDelta
370+ fakeWindow.windowedX = initialWindowX + moveDelta
367− fakeWindow.requestedY = initialWindowY + moveDelta
371+ fakeWindow.windowedY = initialWindowY + moveDelta
368
372
369 // Now change the state to maximized. The window should not keep updating the stored values
373 // Now change the state to maximized. The window should not keep updating the stored values
370 fakeWindow.maximize()
374 fakeWindow.maximize()
371− fakeWindow.requestedX = 31415 // 0 is too risky to pass the test even when broken
375+ fakeWindow.windowedX = 31415 // 0 is too risky to pass the test even when broken
372− fakeWindow.requestedY = 31415
376+ fakeWindow.windowedY = 31415
373
377
374 // This will destroy the window and recreate it
378 // This will destroy the window and recreate it
375 windowLoader.active = false;
379 windowLoader.active = false;
@@ -399,8 +403,8 @@ Item {
399 }
403 }
400
404
401 function test_restoreMovesIntoBounds(data) {
405 function test_restoreMovesIntoBounds(data) {
402− fakeWindow.requestedX = data.x;
406+ fakeWindow.windowedX = data.x;
403− fakeWindow.requestedY = data.y;
407+ fakeWindow.windowedY = data.y;
404 fakeWindow.width = data.w;
408 fakeWindow.width = data.w;
405 fakeWindow.height = data.h;
409 fakeWindow.height = data.h;
406 waitForRendering(root);
410 waitForRendering(root);
@@ -427,8 +431,8 @@ Item {
427 and height) increment value.
431 and height) increment value.
428 */
432 */
429 function test_sizeIncrement() {
433 function test_sizeIncrement() {
430− var initialWindowX = fakeWindow.requestedX;
434+ var initialWindowX = fakeWindow.windowedX;
431− var initialWindowY = fakeWindow.requestedY;
435+ var initialWindowY = fakeWindow.windowedY;
432 var initialWindowWidth = fakeWindow.width
436 var initialWindowWidth = fakeWindow.width
433 var initialWindowHeight = fakeWindow.height
437 var initialWindowHeight = fakeWindow.height
434
438
@@ -458,12 +462,12 @@ Item {
458 Tests that when dragging a window border you cannot make it bigger than its maximum size
462 Tests that when dragging a window border you cannot make it bigger than its maximum size
459 */
463 */
460 function test_maximumSize() {
464 function test_maximumSize() {
461− fakeWindow.requestedX = units.gu(1);
465+ fakeWindow.windowedX = units.gu(1);
462− fakeWindow.requestedY = units.gu(1);
466+ fakeWindow.windowedY = units.gu(1);
463 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
467 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
464 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
468 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
465− fakeWindow.requestedWidth = units.gu(10);
469+ fakeWindow.windowedWidth = units.gu(10);
466− fakeWindow.requestedHeight = units.gu(10);
470+ fakeWindow.windowedHeight = units.gu(10);
467
471
468 fakeWindow.maximumWidth = units.gu(20);
472 fakeWindow.maximumWidth = units.gu(20);
469 fakeWindow.maximumHeight = units.gu(20);
473 fakeWindow.maximumHeight = units.gu(20);
@@ -488,12 +492,12 @@ Item {
488 Tests that when dragging a window border you cannot make it smaller than its minimum size
492 Tests that when dragging a window border you cannot make it smaller than its minimum size
489 */
493 */
490 function test_minimumSize() {
494 function test_minimumSize() {
491− fakeWindow.requestedX = units.gu(1);
495+ fakeWindow.windowedX = units.gu(1);
492− fakeWindow.requestedY = units.gu(1);
496+ fakeWindow.windowedY = units.gu(1);
493 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
497 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
494 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
498 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
495− fakeWindow.requestedWidth = units.gu(20);
499+ fakeWindow.windowedWidth = units.gu(20);
496− fakeWindow.requestedHeight = units.gu(20);
500+ fakeWindow.windowedHeight = units.gu(20);
497
501
498 fakeWindow.minimumWidth = units.gu(10);
502 fakeWindow.minimumWidth = units.gu(10);
499 fakeWindow.minimumHeight = units.gu(10);
503 fakeWindow.minimumHeight = units.gu(10);
tests/qmltests/Stages/DesktopMenuData.qmldeleted−549
@@ -1,549 +0,0 @@
1−import QtQuick 2.4
2−
3−QtObject {
4−
5− property var dialerData: [{
6− "rowData": { // 1.1
7− "label": "&dialer1",
8− "action": "dialer1"
9− },
10− "submenu": [{
11− "rowData": { // 1.1
12− "label": "&menu1.1",
13− "action": "menu1.1",
14− "shortcut": "Ctrl+m"
15− }}, {
16− "rowData": { // 1.2
17− "label": "m&enu1.2",
18− "action": "menu1.2",
19− "shortcut": "Ctrl+e"
20− },
21− "submenu": [{
22− "rowData": { // 1.2.1
23− "label": "me&nu1.2.1",
24− "action": "menu1.2.1"
25− }}, {
26− "rowData": { // 1.2.2
27− "label": "menu1.2.2",
28− "action": "menu1.2.2"
29− }}, {
30− "rowData": { // 1.2.3
31− "isSeparator": true
32− }}, {
33− "rowData": { // row 1.2.4
34− "label": "menu1.2.4",
35− "action": "menu1.2.4",
36− "isToggled": true
37− }}, {
38− "rowData": { // row 1.2.5
39− "label": "menu1.2.5",
40− "sensitive": false,
41− }}
42− ]}, {
43− "rowData": { // 1.3
44− "sensitive": false,
45− "isSeparator": true
46− }}, {
47− "rowData": { // row 1.4
48− "label": "menu1.4",
49− "action": "menu1.4",
50− "shortcut": "Ctrl+n"
51− }}
52− ]}, {
53− "rowData": { // 2
54− "label": "d&ialer2",
55− "action": "dialer2"
56− },
57− "submenu": [{
58− "rowData": { // 2.1
59− "label": "menu2.1",
60− "action": "menu2.1"
61− }}
62− ]}, {
63− "rowData": { // row 3
64− "label": "di&aler3",
65− "action": "dialer3"
66− },
67− "submenu": [{
68− "rowData": { // 3.1
69− "label": "menu3.1",
70− "action": "menu3.1"
71− }}
72− ]}
73− ]
74−
75− property var cameraData: [{
76− "rowData": { // 1.1
77− "label": "camera1",
78− "sensitive": true,
79− "isSeparator": false,
80− "icon": "",
81− "ext": {},
82− "action": "camera1",
83− "actionState": {},
84− "isCheck": false,
85− "isRadio": false,
86− "isToggled": false,
87− "shortcut": ""
88− },
89− "submenu": [{
90− "rowData": { // 1.1
91− "label": "menu1.1",
92− "sensitive": true,
93− "isSeparator": false,
94− "icon": "",
95− "ext": {},
96− "action": "menu1.1",
97− "actionState": {},
98− "isCheck": false,
99− "isRadio": false,
100− "isToggled": false,
101− "shortcut": ""
102− }}, {
103− "rowData": { // 1.2
104− "label": "menu1.2",
105− "sensitive": true,
106− "isSeparator": false,
107− "icon": "",
108− "ext": {},
109− "action": "menu1.2",
110− "actionState": {},
111− "isCheck": false,
112− "isRadio": false,
113− "isToggled": false,
114− "shortcut": ""
115− }}, {
116− "rowData": { // row 1.2
117− "label": "menu1.2",
118− "sensitive": true,
119− "isSeparator": false,
120− "icon": "",
121− "ext": {},
122− "action": "menu1.2",
123− "actionState": {},
124− "isCheck": false,
125− "isRadio": false,
126− "isToggled": false,
127− "shortcut": ""
128− }}
129− ]}, {
130− "rowData": { // 2
131− "label": "camera2",
132− "sensitive": true,
133− "isSeparator": false,
134− "icon": "",
135− "ext": {},
136− "action": "camera2",
137− "actionState": {},
138− "isCheck": false,
139− "isRadio": false,
140− "isToggled": false,
141− "shortcut": ""
142− }}
143− ]
144−
145− property var galleryData: [{
146− "rowData": { // 1.1
147− "label": "gallery1",
148− "sensitive": true,
149− "isSeparator": false,
150− "icon": "",
151− "ext": {},
152− "action": "gallery1",
153− "actionState": {},
154− "isCheck": false,
155− "isRadio": false,
156− "isToggled": false,
157− "shortcut": ""
158− },
159− "submenu": [{
160− "rowData": { // 1.1
161− "label": "menu0",
162− "sensitive": true,
163− "isSeparator": false,
164− "icon": "",
165− "ext": {},
166− "action": "menu0",
167− "actionState": {},
168− "isCheck": false,
169− "isRadio": false,
170− "isToggled": false,
171− "shortcut": ""
172− }}, {
173− "rowData": { // 1.2
174− "label": "menu1",
175− "sensitive": true,
176− "isSeparator": false,
177− "icon": "",
178− "ext": {},
179− "action": "menu1",
180− "actionState": {},
181− "isCheck": false,
182− "isRadio": false,
183− "isToggled": false,
184− "shortcut": ""
185− }}, {
186− "rowData": { // 1.2
187− "label": "",
188− "sensitive": false,
189− "isSeparator": true,
190− "icon": "",
191− "type": "",
192− "ext": {},
193− "action": "",
194− "actionState": {},
195− "isCheck": false,
196− "isRadio": false,
197− "isToggled": false,
198− "shortcut": ""
199− }}, {
200− "rowData": { // row 1.2
201− "label": "menu2",
202− "sensitive": true,
203− "isSeparator": false,
204− "icon": "",
205− "ext": {},
206− "action": "menu2",
207− "actionState": {},
208− "isCheck": false,
209− "isRadio": false,
210− "isToggled": false,
211− "shortcut": ""
212− }}
213− ]}, {
214− "rowData": { // 2
215− "label": "gallery2",
216− "sensitive": true,
217− "isSeparator": false,
218− "icon": "",
219− "ext": {},
220− "action": "gallery2",
221− "actionState": {},
222− "isCheck": false,
223− "isRadio": false,
224− "isToggled": false,
225− "shortcut": ""
226− }}, {
227− "rowData": { // row 2
228− "label": "gallery3",
229− "sensitive": true,
230− "isSeparator": false,
231− "icon": "",
232− "ext": {},
233− "action": "gallery3",
234− "actionState": {},
235− "isCheck": false,
236− "isRadio": false,
237− "isToggled": false,
238− "shortcut": ""
239− }}
240− ]
241−
242− property var testData: [{
243− "rowData": { // 1
244− "label": "_menu1",
245− "sensitive": true,
246− "isSeparator": false,
247− "icon": "",
248− "ext": {},
249− "action": "menu1",
250− "actionState": {},
251− "isCheck": false,
252− "isRadio": false,
253− "isToggled": false,
254− "shortcut": "Alt+F"
255− },
256− "submenu": [{
257− "rowData": { // 1.1
258− "label": "menu1.1",
259− "sensitive": true,
260− "isSeparator": false,
261− "icon": "",
262− "ext": {},
263− "action": "menu1.1",
264− "actionState": {},
265− "isCheck": false,
266− "isRadio": false,
267− "isToggled": false,
268− "shortcut": "Alt+0"
269− }}, {
270− "rowData": { // 1.2
271− "label": "m_enu1.2",
272− "sensitive": true,
273− "isSeparator": false,
274− "icon": "",
275− "ext": {},
276− "action": "menu1.2",
277− "actionState": {},
278− "isCheck": false,
279− "isRadio": false,
280− "isToggled": false,
281− "shortcut": "Alt+1"
282− },
283− "submenu": [{
284− "rowData": { // 1.2.1
285− "label": "menu1.2.1",
286− "sensitive": true,
287− "isSeparator": false,
288− "icon": "",
289− "ext": {},
290− "action": "menu1.2.1",
291− "actionState": {},
292− "isCheck": false,
293− "isRadio": false,
294− "isToggled": false,
295− "shortcut": ""
296− }}, {
297− "rowData": { // 1.2.2
298− "label": "men_u1.2.2",
299− "sensitive": true,
300− "isSeparator": false,
301− "icon": "",
302− "ext": {},
303− "action": "menu1.2.2",
304− "actionState": {},
305− "isCheck": false,
306− "isRadio": false,
307− "isToggled": false,
308− "shortcut": ""
309− }}, {
310− "rowData": { // 1.2.3
311− "label": "",
312− "sensitive": false,
313− "isSeparator": true,
314− "icon": "",
315− "type": "",
316− "ext": {},
317− "action": "",
318− "actionState": {},
319− "isCheck": false,
320− "isRadio": false,
321− "isToggled": false,
322− "shortcut": ""
323− }}, {
324− "rowData": { // row 1.2.4
325− "label": "menu1.2.4",
326− "sensitive": true,
327− "isSeparator": false,
328− "icon": "",
329− "ext": {},
330− "action": "menu1.2.4",
331− "actionState": {},
332− "isCheck": false,
333− "isRadio": false,
334− "isToggled": true,
335− "shortcut": ""
336− }}
337− ]}, {
338− "rowData": { // 1.3
339− "label": "",
340− "sensitive": false,
341− "isSeparator": true,
342− "icon": "",
343− "type": "",
344− "ext": {},
345− "action": "",
346− "actionState": {},
347− "isCheck": false,
348− "isRadio": false,
349− "isToggled": false,
350− "shortcut": ""
351− }}, {
352− "rowData": { // row 1.4
353− "label": "menu1.4",
354− "sensitive": true,
355− "isSeparator": false,
356− "icon": "",
357− "ext": {},
358− "action": "menu1.4",
359− "actionState": {},
360− "isCheck": true,
361− "isRadio": false,
362− "isToggled": true,
363− "shortcut": "Alt+2"
364− }}
365− ]}, {
366− "rowData": { // 2
367− "label": "menu2",
368− "sensitive": true,
369− "isSeparator": false,
370− "icon": "",
371− "ext": {},
372− "action": "menu2",
373− "actionState": {},
374− "isCheck": false,
375− "isRadio": false,
376− "isToggled": false,
377− "shortcut": "Alt+E"
378− },
379− "submenu": [{
380− "rowData": { // 2.1
381− "label": "menu2.1",
382− "sensitive": true,
383− "isSeparator": false,
384− "icon": "",
385− "ext": {},
386− "action": "menu2.1",
387− "actionState": {},
388− "isCheck": false,
389− "isRadio": false,
390− "isToggled": false,
391− "shortcut": ""
392− }}
393− ]}, {
394− "rowData": { // row 3
395− "label": "me_nu3",
396− "sensitive": true,
397− "isSeparator": false,
398− "icon": "",
399− "ext": {},
400− "action": "dialer3",
401− "actionState": {},
402− "isCheck": false,
403− "isRadio": false,
404− "isToggled": false,
405− "shortcut": ""
406− },
407− "submenu": [{
408− "rowData": { // 3.1
409− "label": "menu3.1",
410− "sensitive": true,
411− "isSeparator": false,
412− "icon": "",
413− "ext": {},
414− "action": "menu3.1",
415− "actionState": {},
416− "isCheck": false,
417− "isRadio": false,
418− "isToggled": false,
419− "shortcut": ""
420− }}
421− ]}
422− ]
423−
424− property var deepTestData: [{
425− "rowData": { // 1
426− "label": "_menu1",
427− "sensitive": true,
428− "isSeparator": false,
429− "icon": "",
430− "ext": {},
431− "action": "menu1",
432− "actionState": {},
433− "isCheck": false,
434− "isRadio": false,
435− "isToggled": false,
436− "shortcut": "Alt+F"
437− },
438− "submenu": [{
439− "rowData": { // 1.1
440− "label": "menu1.1",
441− "sensitive": true,
442− "isSeparator": false,
443− "icon": "",
444− "ext": {},
445− "action": "menu1.1",
446− "actionState": {},
447− "isCheck": false,
448− "isRadio": false,
449− "isToggled": false,
450− "shortcut": ""
451− },
452− "submenu": [{
453− "rowData": { // 1.1.1
454− "label": "menu1.1.1",
455− "sensitive": true,
456− "isSeparator": false,
457− "icon": "",
458− "ext": {},
459− "action": "menu1.1.1",
460− "actionState": {},
461− "isCheck": false,
462− "isRadio": false,
463− "isToggled": false,
464− "shortcut": ""
465− },
466− "submenu": [{
467− "rowData": { // 1.1.1
468− "label": "menu1.1.1.1",
469− "sensitive": true,
470− "isSeparator": false,
471− "icon": "",
472− "ext": {},
473− "action": "menu1.1.1.1",
474− "actionState": {},
475− "isCheck": false,
476− "isRadio": false,
477− "isToggled": false,
478− "shortcut": ""
479− },
480− "submenu": [{
481− "rowData": { // 1.1.1.1
482− "label": "menu1.1.1.1.1",
483− "sensitive": true,
484− "isSeparator": false,
485− "icon": "",
486− "ext": {},
487− "action": "menu1.1.1.1.1",
488− "actionState": {},
489− "isCheck": false,
490− "isRadio": false,
491− "isToggled": false,
492− "shortcut": ""
493− }}
494− ]}
495− ]}
496− ]}
497− ]}
498− ]
499−
500− property var singleCheckable: [{
501− "rowData": { // 1
502− "label": "checkable1",
503− "sensitive": true,
504− "isSeparator": false,
505− "icon": "",
506− "ext": {},
507− "action": "checkable1",
508− "actionState": {},
509− "isCheck": true,
510− "isRadio": false,
511− "isToggled": false,
512− "shortcut": "Alt+F"
513− }
514− }]
515−
516− function generateTestData(length, depth, separatorInterval, prefix) {
517− var data = [];
518−
519− if (prefix === undefined) prefix = "menu"
520−
521− for (var i = 0; i < length; i++) {
522−
523− var menuCode = String.fromCharCode(i+65);
524−
525− var isSeparator = separatorInterval > 0 && ((i+1) % separatorInterval == 0);
526− var row = {
527− "rowData": { // 1
528− "label": prefix + "&" + menuCode,
529− "sensitive": true,
530− "isSeparator": isSeparator,
531− "icon": "",
532− "ext": {},
533− "action": prefix + menuCode,
534− "actionState": {},
535− "isCheck": false,
536− "isRadio": false,
537− "isToggled": false,
538− "shortcut": ""
539− }
540− }
541− if (!isSeparator && depth > 1) {
542− var submenu = generateTestData(length, depth-1, separatorInterval, prefix + menuCode + ".");
543− row["submenu"] = submenu;
544− }
545− data[i] = row;
546− }
547− return data;
548− }
549−}
tests/qmltests/Stages/tst_DecoratedWindow.qmldeleted−82
@@ -1,82 +0,0 @@
1−/*
2− * Copyright (C) 2016 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.4
18−import Ubuntu.Components 1.3
19−import Unity.Application 0.1
20−import Unity.ApplicationMenu 0.1
21−import Unity.Indicators 0.1 as Indicators
22−import Unity.Test 0.1
23−import Utils 0.1
24−import QMenuModel 0.1
25−
26−import "../../../qml/Stages"
27−
28−Item {
29− id: root
30− width: units.gu(70)
31− height: units.gu(50)
32−
33− Component.onCompleted: {
34− QuickUtils.keyboardAttached = true;
35− theme.name = "Ubuntu.Components.Themes.SuruDark"
36−
37− ApplicationMenuRegistry.RegisterSurfaceMenu("dialerAppSurfaceId", "/dialerapp", "/dialerapp", ":2");
38− Indicators.UnityMenuModelCache.setCachedModelData("/dialerapp", appMenuData.dialerData);
39−
40− fakeApplication = ApplicationManager.add("dialer-app");
41− fakeApplication.manualSurfaceCreation = true;
42− fakeApplication.setState(ApplicationInfoInterface.Starting);
43−
44− fakeSurface = SurfaceManager.createSurface("dialerAppSurface",Mir.NormalType, Mir.MaximizedState, fakeApplication);
45− fakeApplication.setState(ApplicationInfoInterface.Running);
46− }
47− property QtObject fakeApplication: null
48− property QtObject fakeSurface: null
49−
50− Binding {
51− target: MouseTouchAdaptor
52− property: "enabled"
53− value: false
54− }
55−
56− DesktopMenuData { id: appMenuData }
57−
58− Item {
59− anchors.fill: parent
60− anchors.margins: units.gu(2)
61−
62− DecoratedWindow {
63− id: window
64− active: true
65− requestedHeight: parent.height
66− requestedWidth: parent.width
67−
68− application: fakeApplication
69− surface: fakeSurface
70− focus: true
71− }
72− }
73−
74− UnityTestCase {
75− id: testCase
76− name: "DecoratedWindow"
77− when: windowShown
78−
79− function init() {
80− }
81− }
82−}
tests/qmltests/tst_OrientedShell.qml+38−198
@@ -29,7 +29,8 @@ import Utils 0.1
29
29
30import "../../qml"
30import "../../qml"
31import "../../qml/Components"
31import "../../qml/Components"
32−import "Stages"
32+import "../../qml/Components/PanelState"
33+import "Stage"
33
34
34Rectangle {
35Rectangle {
35 id: root
36 id: root
@@ -443,7 +444,7 @@ Rectangle {
443 SignalSpy { id: signalSpy2 }
444 SignalSpy { id: signalSpy2 }
444
445
445 Connections {
446 Connections {
446− id: spreadRepeaterConnections
447+ id: appRepeaterConnections
447 ignoreUnknownSignals : true
448 ignoreUnknownSignals : true
448 property var itemAddedCallback: null
449 property var itemAddedCallback: null
449 onItemAdded: {
450 onItemAdded: {
@@ -483,8 +484,8 @@ Rectangle {
483 while (keyboardsModel.count > 0)
484 while (keyboardsModel.count > 0)
484 MockInputDeviceBackend.removeDevice("/kbd" + (keyboardsModel.count - 1))
485 MockInputDeviceBackend.removeDevice("/kbd" + (keyboardsModel.count - 1))
485
486
486− spreadRepeaterConnections.target = null;
487+ appRepeaterConnections.target = null;
487− spreadRepeaterConnections.itemAddedCallback = null;
488+ appRepeaterConnections.itemAddedCallback = null;
488 signalSpy.target = null;
489 signalSpy.target = null;
489 signalSpy.signalName = "";
490 signalSpy.signalName = "";
490
491
@@ -511,7 +512,7 @@ Rectangle {
511
512
512 var primaryAppWindow = findAppWindowForSurfaceId(primarySurfaceId);
513 var primaryAppWindow = findAppWindowForSurfaceId(primarySurfaceId);
513 verify(primaryAppWindow)
514 verify(primaryAppWindow)
514− var primaryDelegate = findChild(shell, "spreadDelegate_" + primarySurfaceId);
515+ var primaryDelegate = findChild(shell, "appDelegate_" + primarySurfaceId);
515
516
516 compare(primaryDelegate.focus, true);
517 compare(primaryDelegate.focus, true);
517 compare(primaryApp.rotatesWindowContents, false);
518 compare(primaryApp.rotatesWindowContents, false);
@@ -559,7 +560,7 @@ Rectangle {
559 compare(ApplicationManager.focusedApplicationId, "primary-oriented-app");
560 compare(ApplicationManager.focusedApplicationId, "primary-oriented-app");
560 compare(primaryApp.rotatesWindowContents, false);
561 compare(primaryApp.rotatesWindowContents, false);
561 compare(primaryApp.supportedOrientations, Qt.PrimaryOrientation);
562 compare(primaryApp.supportedOrientations, Qt.PrimaryOrientation);
562− var primaryDelegate = findChild(shell, "spreadDelegate_" + primarySurfaceId);
563+ var primaryDelegate = findChild(shell, "appDelegate_" + primarySurfaceId);
563 compare(primaryDelegate.stage, ApplicationInfoInterface.MainStage);
564 compare(primaryDelegate.stage, ApplicationInfoInterface.MainStage);
564
565
565 tryCompareFunction(function(){return primaryApp.surfaceList.count > 0;}, true);
566 tryCompareFunction(function(){return primaryApp.surfaceList.count > 0;}, true);
@@ -736,7 +737,7 @@ Rectangle {
736 compare(musicApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
737 compare(musicApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
737 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
738 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
738 if (data.deviceName === "manta" || data.deviceName === "flo") {
739 if (data.deviceName === "manta" || data.deviceName === "flo") {
739− var musicDelegate = findChild(shell, "spreadDelegate_" + musicSurfaceId);
740+ var musicDelegate = findChild(shell, "appDelegate_" + musicSurfaceId);
740 compare(musicDelegate.stage, ApplicationInfoInterface.MainStage);
741 compare(musicDelegate.stage, ApplicationInfoInterface.MainStage);
741 }
742 }
742
743
@@ -873,9 +874,9 @@ Rectangle {
873 var greeter = findChild(shell, "greeter");
874 var greeter = findChild(shell, "greeter");
874 tryCompare(greeter, "animating", false);
875 tryCompare(greeter, "animating", false);
875
876
876− var twitterDelegate = findChild(shell, "spreadDelegate_" + topLevelSurfaceList.idAt(1));
877+ var twitterDelegate = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(1));
877 compare(twitterDelegate.application.appId, "twitter-webapp");
878 compare(twitterDelegate.application.appId, "twitter-webapp");
878− twitterDelegate.clicked();
879+ tap(twitterDelegate, 1, 1);
879
880
880 // now it should finally follow the physical orientation
881 // now it should finally follow the physical orientation
881 tryCompare(shell, "transformRotationAngle", 90);
882 tryCompare(shell, "transformRotationAngle", 90);
@@ -894,24 +895,10 @@ Rectangle {
894 WindowStateStorage.saveStage("twitter-webapp", ApplicationInfoInterface.SideStage)
895 WindowStateStorage.saveStage("twitter-webapp", ApplicationInfoInterface.SideStage)
895 loadShell(data.deviceName);
896 loadShell(data.deviceName);
896
897
897− var twitterDelegate = null;
898−
899− verify(spreadRepeaterConnections.target);
900− spreadRepeaterConnections.itemAddedCallback = function(item) {
901− verify(item.application.appId, "twitter-webapp");
902− twitterDelegate = item;
903− signalSpy.target = findInvisibleChild(item, "orientationChangeAnimation");
904− verify(signalSpy.valid);
905− }
906−
907− signalSpy.clear();
908− signalSpy.target = null;
909− signalSpy.signalName = "runningChanged";
910−
911 var twitterSurfaceId = topLevelSurfaceList.nextId;
898 var twitterSurfaceId = topLevelSurfaceList.nextId;
912 var twitterApp = ApplicationManager.startApplication("twitter-webapp");
899 var twitterApp = ApplicationManager.startApplication("twitter-webapp");
913 verify(twitterApp);
900 verify(twitterApp);
914− var twitterDelegate = findChild(shell, "spreadDelegate_" + twitterSurfaceId);
901+ var twitterDelegate = findChild(shell, "appDelegate_" + twitterSurfaceId);
915 compare(twitterDelegate.stage, ApplicationInfoInterface.SideStage);
902 compare(twitterDelegate.stage, ApplicationInfoInterface.SideStage);
916
903
917 // ensure the mock twitter-webapp is as we expect
904 // ensure the mock twitter-webapp is as we expect
@@ -919,15 +906,11 @@ Rectangle {
919 compare(twitterApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
906 compare(twitterApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
920 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
907 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
921
908
922− // Wait until spreadRepeaterConnections hs caught the new SpreadDelegate and
923− // set up the signalSpy target accordingly.
924− tryCompareFunction(function(){ return signalSpy.target != null && signalSpy.valid; }, true);
925−
926 tryCompare(twitterDelegate, "orientationChangesEnabled", true);
909 tryCompare(twitterDelegate, "orientationChangesEnabled", true);
927
910
928− var appWindowWithShadow = findChild(twitterDelegate, "appWindowWithShadow");
911+ var decoratedWindow = findChild(twitterDelegate, "decoratedWindow");
929− verify(appWindowWithShadow);
912+ verify(decoratedWindow);
930− tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
913+ tryCompare(decoratedWindow, "counterRotate", false);
931
914
932 // no reason for any rotation animation to have taken place
915 // no reason for any rotation animation to have taken place
933 compare(signalSpy.count, 0);
916 compare(signalSpy.count, 0);
@@ -943,8 +926,8 @@ Rectangle {
943 loadShell(data.deviceName);
926 loadShell(data.deviceName);
944
927
945 var dialerDelegate = null;
928 var dialerDelegate = null;
946− verify(spreadRepeaterConnections.target);
929+ verify(appRepeaterConnections.target);
947− spreadRepeaterConnections.itemAddedCallback = function(item) {
930+ appRepeaterConnections.itemAddedCallback = function(item) {
948 dialerDelegate = item;
931 dialerDelegate = item;
949 verify(item.application.appId, "dialer-app");
932 verify(item.application.appId, "dialer-app");
950 }
933 }
@@ -960,16 +943,12 @@ Rectangle {
960 tryCompareFunction(function(){ return dialerDelegate != null; }, true);
943 tryCompareFunction(function(){ return dialerDelegate != null; }, true);
961 tryCompare(dialerDelegate, "orientationChangesEnabled", true);
944 tryCompare(dialerDelegate, "orientationChangesEnabled", true);
962
945
963− var appWindowWithShadow = findChild(dialerDelegate, "appWindowWithShadow");
946+ var decoratedWindow = findChild(dialerDelegate, "decoratedWindow");
964− verify(appWindowWithShadow);
947+ verify(decoratedWindow);
965− tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
948+ tryCompare(decoratedWindow, "counterRotate", false);
966
949
967 // app must have portrait aspect ratio
950 // app must have portrait aspect ratio
968− verify(appWindowWithShadow.width < appWindowWithShadow.height);
951+ verify(decoratedWindow.width < decoratedWindow.height);
969−
970− compare(appWindowWithShadow.rotation, 0);
971−
972− verifyAppWindowWithinSpreadDelegateBoundaries(dialerDelegate);
973
952
974 // shell should remain in its primery orientation as the app in the main stage
953 // shell should remain in its primery orientation as the app in the main stage
975 // is the one that dictates its orientation. In this case it's unity8-dash
954 // is the one that dictates its orientation. In this case it's unity8-dash
@@ -977,83 +956,6 @@ Rectangle {
977 compare(shell.orientation, orientedShell.orientations.primary);
956 compare(shell.orientation, orientedShell.orientations.primary);
978 }
957 }
979
958
980− function test_sideStageAppsRemainPortraitInSpread_data() {
981− return [
982− {tag: "manta", deviceName: "manta"},
983− {tag: "flo", deviceName: "flo"}
984− ];
985− }
986− function test_sideStageAppsRemainPortraitInSpread(data) {
987− loadShell(data.deviceName);
988−
989−
990− ////
991− // Launch dialer
992− var dialerDelegate = null;
993− verify(spreadRepeaterConnections.target);
994− spreadRepeaterConnections.itemAddedCallback = function(item) {
995− dialerDelegate = item;
996− verify(item.application.appId, "dialer-app");
997− }
998−
999− WindowStateStorage.saveStage("dialer-app", ApplicationInfoInterface.SideStage)
1000− var dialerApp = ApplicationManager.startApplication("dialer-app");
1001− verify(dialerApp);
1002−
1003− // ensure the mock dialer-app is as we expect
1004− compare(dialerApp.rotatesWindowContents, false);
1005− compare(dialerApp.supportedOrientations, Qt.PortraitOrientation | Qt.InvertedPortraitOrientation);
1006−
1007− tryCompareFunction(function(){ return dialerDelegate != null; }, true);
1008− waitUntilAppDelegateIsFullyInit(dialerDelegate);
1009−
1010−
1011− ////
1012− // Launch twitter
1013− var twitterDelegate = null;
1014− spreadRepeaterConnections.itemAddedCallback = function(item) {
1015− twitterDelegate = item;
1016− verify(item.application.appId, "twitter-webapp");
1017− }
1018−
1019− var twitterApp = ApplicationManager.startApplication("twitter-webapp");
1020− verify(twitterApp);
1021− twitterApp.stage = ApplicationInfoInterface.SideStage;
1022−
1023− // ensure the mock twitter-webapp is as we expect
1024− compare(twitterApp.rotatesWindowContents, false);
1025− compare(twitterApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
1026− | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
1027−
1028− tryCompareFunction(function(){ return twitterDelegate != null; }, true);
1029− waitUntilAppDelegateIsFullyInit(twitterDelegate);
1030−
1031− ////
1032− // Edge swipe to show spread and check orientations
1033−
1034− performEdgeSwipeToShowAppSpread();
1035−
1036− {
1037− var appWindowWithShadow = findChild(dialerDelegate, "appWindowWithShadow");
1038− verify(appWindowWithShadow);
1039− tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
1040− compare(appWindowWithShadow.width, dialerDelegate.width);
1041− compare(appWindowWithShadow.height, dialerDelegate.height);
1042− compare(appWindowWithShadow.rotation, 0);
1043− }
1044− {
1045− var appWindowWithShadow = findChild(twitterDelegate, "appWindowWithShadow");
1046− verify(appWindowWithShadow);
1047− tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
1048− compare(appWindowWithShadow.width, twitterDelegate.width);
1049− compare(appWindowWithShadow.height, twitterDelegate.height);
1050− compare(appWindowWithShadow.rotation, 0);
1051− }
1052−
1053− verifyAppWindowWithinSpreadDelegateBoundaries(dialerDelegate);
1054− verifyAppWindowWithinSpreadDelegateBoundaries(twitterDelegate);
1055− }
1056−
1057 function test_launchedAppHasActiveFocus_data() {
959 function test_launchedAppHasActiveFocus_data() {
1058 return [
960 return [
1059 {tag: "mako", deviceName: "mako"},
961 {tag: "mako", deviceName: "mako"},
@@ -1449,11 +1351,10 @@ Rectangle {
1449 function waitUntilAppDelegateIsFullyInit(spreadDelegate) {
1351 function waitUntilAppDelegateIsFullyInit(spreadDelegate) {
1450 tryCompare(spreadDelegate, "orientationChangesEnabled", true);
1352 tryCompare(spreadDelegate, "orientationChangesEnabled", true);
1451
1353
1452− var appWindowWithShadow = findChild(spreadDelegate, "appWindowWithShadow");
1354+ var decoratedWindow = findChild(spreadDelegate, "decoratedWindow");
1453− verify(appWindowWithShadow);
1355+ tryCompare(decoratedWindow, "counterRotate", false);
1454− tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
1455
1356
1456− var appWindowStates = findInvisibleChild(appWindowWithShadow, "applicationWindowStateGroup");
1357+ var appWindowStates = findInvisibleChild(decoratedWindow, "applicationWindowStateGroup");
1457 verify(appWindowStates);
1358 verify(appWindowStates);
1458 tryCompare(appWindowStates, "state", "surface");
1359 tryCompare(appWindowStates, "state", "surface");
1459 }
1360 }
@@ -1491,8 +1392,7 @@ Rectangle {
1491 }
1392 }
1492
1393
1493 function performLeftEdgeSwipeToSwitchToDash() {
1394 function performLeftEdgeSwipeToSwitchToDash() {
1494− var spreadView = findChild(shell, "spreadView");
1495− var swipeLength = spreadView.width * 0.7;
1395+ var swipeLength = shell.width * 0.7;
1496
1396
1497 var touchStartX = 1;
1397 var touchStartX = 1;
1498 var touchStartY = shell.height / 2;
1398 var touchStartY = shell.height / 2;
@@ -1507,35 +1407,13 @@ Rectangle {
1507 // swipe just enough to ensure an app switch action.
1407 // swipe just enough to ensure an app switch action.
1508 // If we swipe too much we will trigger the spread mode
1408 // If we swipe too much we will trigger the spread mode
1509 // and we don't want that.
1409 // and we don't want that.
1510− var spreadView = findChild(shell, "spreadView");
1511− verify(spreadView);
1512−
1513 verify(topLevelSurfaceList.count >= 2);
1410 verify(topLevelSurfaceList.count >= 2);
1514 var previousSurfaceId = topLevelSurfaceList.idAt(1);
1411 var previousSurfaceId = topLevelSurfaceList.idAt(1);
1515
1412
1516 var touchStartX = shell.width - 1;
1413 var touchStartX = shell.width - 1;
1517 var touchStartY = shell.height / 2;
1414 var touchStartY = shell.height / 2;
1518
1415
1519− var condition;
1520− if (applicationArguments.deviceName === "phone") {
1521− condition = function() {
1522− return spreadView.shiftedContentX > units.gu(2) &&
1523− spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width;
1524− };
1525− } else {
1526− condition = function() {
1527− return spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker1
1528− && spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2;
1529− };
1530− }
1531−
1532− touchDragUntil(shell,
1533− touchStartX, touchStartY,
1416+ touchFlick(shell, touchStartX, touchStartY, touchStartX - units.gu(8), touchStartY, units.gu(4), 10);
1534− -units.gu(1), 0,
1535− condition);
1536−
1537− // ensure the app switch animation has ended
1538− tryCompare(spreadView, "shiftedContentX", 0);
1539
1417
1540 tryCompareFunction(function(){ return topLevelSurfaceList.idAt(0); }, previousSurfaceId);
1418 tryCompareFunction(function(){ return topLevelSurfaceList.idAt(0); }, previousSurfaceId);
1541 }
1419 }
@@ -1546,11 +1424,9 @@ Rectangle {
1546 shell.width - 1, touchStartY,
1424 shell.width - 1, touchStartY,
1547 0, touchStartY);
1425 0, touchStartY);
1548
1426
1549− var spreadView = findChild(shell, "spreadView");
1427+ var stage = findChild(shell, "stage");
1550− verify(spreadView);
1428+ tryCompare(stage, "state", "spread");
1551− tryCompare(spreadView, "phase", 2);
1429+ waitForRendering(stage);
1552− tryCompare(spreadView, "flicking", false);
1553− tryCompare(spreadView, "moving", false);
1554 }
1430 }
1555
1431
1556 function showPowerDialog() {
1432 function showPowerDialog() {
@@ -1559,19 +1435,6 @@ Rectangle {
1559 dialogsPrivate.showPowerDialog();
1435 dialogsPrivate.showPowerDialog();
1560 }
1436 }
1561
1437
1562− function verifyAppWindowWithinSpreadDelegateBoundaries(spreadDelegate) {
1563− var appWindowWithShadow = findChild(spreadDelegate, "appWindowWithShadow");
1564− verify(appWindowWithShadow);
1565−
1566− var windowInDelegateCoords = appWindowWithShadow.mapToItem(spreadDelegate, 0, 0,
1567− appWindowWithShadow.width, appWindowWithShadow.height);
1568−
1569− compare(windowInDelegateCoords.x, 0);
1570− compare(windowInDelegateCoords.y, 0);
1571− compare(windowInDelegateCoords.width, spreadDelegate.width);
1572− compare(windowInDelegateCoords.height, spreadDelegate.height);
1573− }
1574−
1575 function swipeAwayGreeter() {
1438 function swipeAwayGreeter() {
1576 var greeter = findChild(shell, "greeter");
1439 var greeter = findChild(shell, "greeter");
1577 tryCompare(greeter, "fullyShown", true);
1440 tryCompare(greeter, "fullyShown", true);
@@ -1606,9 +1469,6 @@ Rectangle {
1606 topLevelSurfaceList = findInvisibleChild(shell, "topLevelSurfaceList");
1469 topLevelSurfaceList = findInvisibleChild(shell, "topLevelSurfaceList");
1607 verify(topLevelSurfaceList);
1470 verify(topLevelSurfaceList);
1608
1471
1609− var stageLoader = findChild(shell, "applicationsDisplayLoader");
1610− verify(stageLoader);
1611−
1612 tryCompare(shell, "waitingOnGreeter", false); // reset by greeter when ready
1472 tryCompare(shell, "waitingOnGreeter", false); // reset by greeter when ready
1613
1473
1614 waitUntilShellIsInOrientation(root.physicalOrientation0);
1474 waitUntilShellIsInOrientation(root.physicalOrientation0);
@@ -1617,9 +1477,9 @@ Rectangle {
1617
1477
1618 swipeAwayGreeter();
1478 swipeAwayGreeter();
1619
1479
1620− var spreadRepeater = findChild(stageLoader, "spreadRepeater");
1480+ var appRepeater = findChild(shell, "appRepeater");
1621− if (spreadRepeater) {
1481+ if (appRepeater) {
1622− spreadRepeaterConnections.target = spreadRepeater;
1482+ appRepeaterConnections.target = appRepeater;
1623 }
1483 }
1624 }
1484 }
1625
1485
@@ -1644,15 +1504,6 @@ Rectangle {
1644 return false;
1504 return false;
1645 }
1505 }
1646
1506
1647− var topMargin = 0.;
1648− if (!app.fullscreen) {
1649− var appsDisplayLoader = findChild(shell, "applicationsDisplayLoader");
1650− verify(appsDisplayLoader);
1651− verify(appsDisplayLoader.item);
1652− verify(appsDisplayLoader.item.maximizedAppTopMargin !== undefined);
1653− topMargin = appsDisplayLoader.item.maximizedAppTopMargin;
1654− }
1655−
1656 var surfaceItem = findSurfaceItem(item, surface);
1507 var surfaceItem = findSurfaceItem(item, surface);
1657 if (!surfaceItem) {
1508 if (!surfaceItem) {
1658 console.warn("no surfaceItem rendering app surface");
1509 console.warn("no surfaceItem rendering app surface");
@@ -1660,15 +1511,16 @@ Rectangle {
1660 }
1511 }
1661 var point = surfaceItem.mapToItem(orientedShell, 0, 0);
1512 var point = surfaceItem.mapToItem(orientedShell, 0, 0);
1662
1513
1514+ print("exptectedAngle", expectedAngle, point.x, point.y)
1663 switch (expectedAngle) {
1515 switch (expectedAngle) {
1664 case 0:
1516 case 0:
1665− return point.x === 0. && point.y === topMargin;
1517+ return point.x === 0 && point.y === PanelState.panelHeight;
1666 case 90:
1518 case 90:
1667− return point.x === orientedShell.width - topMargin && point.y === 0;
1519+ return point.x === orientedShell.width - PanelState.panelHeight && point.y === 0;
1668 case 180:
1520 case 180:
1669− return point.x === orientedShell.width && point.y === orientedShell.height - topMargin;
1521+ return point.x === orientedShell.width && point.y === orientedShell.height - PanelState.panelHeight;
1670 default: // 270
1522 default: // 270
1671− return point.x === topMargin && point.y === orientedShell.height;
1523+ return point.x === PanelState.panelHeight && point.y === orientedShell.height;
1672 }
1524 }
1673 }
1525 }
1674
1526
@@ -1690,24 +1542,12 @@ Rectangle {
1690 }
1542 }
1691
1543
1692 function swipeToCloseCurrentAppInSpread() {
1544 function swipeToCloseCurrentAppInSpread() {
1693− var spreadView = findChild(shell, "spreadView");
1694− verify(spreadView);
1695−
1696− var delegateToClose = findChild(spreadView, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
1545+ var delegateToClose = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(0));
1697 verify(delegateToClose);
1546 verify(delegateToClose);
1698
1547
1699− var appIdToClose = ApplicationManager.get(0).appId;;
1548+ var appIdToClose = ApplicationManager.get(0).appId;
1700 var appCountBefore = ApplicationManager.count;
1549 var appCountBefore = ApplicationManager.count;
1701
1550
1702− // ensure the current app is widely visible by swiping to the right,
1703− // which will move the app windows accordingly
1704− touchFlick(shell,
1705− shell.width * 0.25, shell.width / 2,
1706− shell.width, shell.width / 2);
1707−
1708− tryCompare(spreadView, "flicking", false);
1709− tryCompare(spreadView, "moving", false);
1710−
1711 // Swipe up close to its left edge, as it is the only area of it guaranteed to be exposed
1551 // Swipe up close to its left edge, as it is the only area of it guaranteed to be exposed
1712 // in the spread. Eg: its center could be covered by some other delegate.
1552 // in the spread. Eg: its center could be covered by some other delegate.
1713 touchFlick(delegateToClose,
1553 touchFlick(delegateToClose,
tests/qmltests/tst_Shell.qml+182−172
@@ -38,7 +38,7 @@ import Unity.Indicators 0.1 as Indicators
38import "../../qml"
38import "../../qml"
39import "../../qml/Components"
39import "../../qml/Components"
40import "../../qml/Components/PanelState"
40import "../../qml/Components/PanelState"
41−import "Stages"
41+import "Stage"
42
42
43Rectangle {
43Rectangle {
44 id: root
44 id: root
@@ -51,21 +51,14 @@ Rectangle {
51 LightDM.Greeter.mockMode = "single";
51 LightDM.Greeter.mockMode = "single";
52 LightDM.Users.mockMode = "single";
52 LightDM.Users.mockMode = "single";
53 shellLoader.active = true;
53 shellLoader.active = true;
54−
55− ApplicationMenuRegistry.RegisterSurfaceMenu("DialerId", "/dialerapp", "/dialerapp", ":0");
56− Indicators.UnityMenuModelCache.setCachedModelData("/dialerapp", appMenuData.dialerData);
57−
58− ApplicationMenuRegistry.RegisterSurfaceMenu("CameraId", "/cameraapp", "/cameraapp", ":1");
59− Indicators.UnityMenuModelCache.setCachedModelData("/cameraapp", appMenuData.cameraData);
60−
61− ApplicationMenuRegistry.RegisterSurfaceMenu("GalleryId", "/galleryapp", "/galleryapp", ":2");
62− Indicators.UnityMenuModelCache.setCachedModelData("/galleryapp", appMenuData.galleryData);
63 }
54 }
64
55
65 DesktopMenuData {
56 DesktopMenuData {
66 id: appMenuData
57 id: appMenuData
67 }
58 }
68
59
60+ property var shell: shellLoader.item ? shellLoader.item : null
61+
69 Item {
62 Item {
70 id: shellContainer
63 id: shellContainer
71 anchors.left: root.left
64 anchors.left: root.left
@@ -123,6 +116,7 @@ Rectangle {
123 sourceComponent: Component {
116 sourceComponent: Component {
124 Shell {
117 Shell {
125 id: __shell
118 id: __shell
119+ objectName: "shell"
126 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
120 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
127 nativeWidth: width
121 nativeWidth: width
128 nativeHeight: height
122 nativeHeight: height
@@ -199,22 +193,44 @@ Rectangle {
199 callManager.foregroundCall = callManager.foregroundCall ? null : phoneCall;
193 callManager.foregroundCall = callManager.foregroundCall ? null : phoneCall;
200 }
194 }
201 }
195 }
202− }
203− Button {
196+ Button {
204− text: "Show Launcher"
197+ text: "Show Launcher"
205− activeFocusOnPress: false
198+ activeFocusOnPress: false
206− onClicked: {
199+ onClicked: {
207− if (shellLoader.status !== Loader.Ready)
200+ if (shellLoader.status !== Loader.Ready)
208− return;
201+ return;
209
202
210− var launcher = testCase.findChild(shellLoader.item, "launcher");
203+ var launcher = testCase.findChild(shellLoader.item, "launcher");
211− launcher.state = "visible";
204+ launcher.state = "visible";
205+ }
212 }
206 }
207+ Button {
208+ text: "Print focused"
209+ activeFocusOnPress: false
210+ onClicked: {
211+ var childs = new Array(0);
212+ childs.push(shellLoader.item)
213+ while (childs.length > 0) {
214+ if (childs[0].activeFocus && childs[0].focus && childs[0].objectName != "shell") {
215+ console.log("Active focus is on item:", childs[0]);
216+ return;
217+ }
218+ for (var i in childs[0].children) {
219+ childs.push(childs[0].children[i])
220+ }
221+ childs.splice(0, 1);
222+ }
223+ console.log("No active focused item found within shell.")
224+ }
225+ }
226+ }
227+ Label {
228+ text: "LightDM mock mode"
213 }
229 }
230+
214 ListItem.ItemSelector {
231 ListItem.ItemSelector {
215 anchors { left: parent.left; right: parent.right }
232 anchors { left: parent.left; right: parent.right }
216 activeFocusOnPress: false
233 activeFocusOnPress: false
217− text: "LightDM mock mode"
218 model: ["single", "single-passphrase", "single-pin", "full"]
234 model: ["single", "single-passphrase", "single-pin", "full"]
219 onSelectedIndexChanged: {
235 onSelectedIndexChanged: {
220 shellLoader.active = false;
236 shellLoader.active = false;
@@ -223,33 +239,41 @@ Rectangle {
223 shellLoader.active = true;
239 shellLoader.active = true;
224 }
240 }
225 }
241 }
242+ Label {
243+ text: "Size"
244+ }
245+
226 ListItem.ItemSelector {
246 ListItem.ItemSelector {
247+ id: sizeSelector
227 anchors { left: parent.left; right: parent.right }
248 anchors { left: parent.left; right: parent.right }
228 activeFocusOnPress: false
249 activeFocusOnPress: false
229− text: "Size"
230 model: ["phone", "tablet", "desktop"]
250 model: ["phone", "tablet", "desktop"]
231 onSelectedIndexChanged: {
251 onSelectedIndexChanged: {
232− shellLoader.active = false;
233 shellLoader.state = model[selectedIndex];
252 shellLoader.state = model[selectedIndex];
234− shellLoader.active = true;
235 }
253 }
236 }
254 }
255+ Label {
256+ text: "Usage scenario"
257+ }
258+
237 ListItem.ItemSelector {
259 ListItem.ItemSelector {
238 id: usageScenarioSelector
260 id: usageScenarioSelector
239 anchors { left: parent.left; right: parent.right }
261 anchors { left: parent.left; right: parent.right }
240 activeFocusOnPress: false
262 activeFocusOnPress: false
241− text: "Usage scenario"
242 model: ["phone", "tablet", "desktop"]
263 model: ["phone", "tablet", "desktop"]
243 }
264 }
244 MouseTouchEmulationCheckbox {
265 MouseTouchEmulationCheckbox {
245 id: mouseEmulation
266 id: mouseEmulation
246 checked: true
267 checked: true
247 }
268 }
269+ Label {
270+ text: "Ctrl key as"
271+ }
272+
248 ListItem.ItemSelector {
273 ListItem.ItemSelector {
249 id: ctrlModifier
274 id: ctrlModifier
250 anchors { left: parent.left; right: parent.right }
275 anchors { left: parent.left; right: parent.right }
251 activeFocusOnPress: false
276 activeFocusOnPress: false
252− text: "Ctrl key as"
253 model: ["Ctrl", "Alt", "Super"]
277 model: ["Ctrl", "Alt", "Super"]
254 onSelectedIndexChanged: {
278 onSelectedIndexChanged: {
255 var keyMapper = testCase.findChild(shellContainer, "physicalKeysMapper");
279 var keyMapper = testCase.findChild(shellContainer, "physicalKeysMapper");
@@ -276,6 +300,7 @@ Rectangle {
276 Button {
300 Button {
277 text: "Start all apps"
301 text: "Start all apps"
278 width: parent.width
302 width: parent.width
303+ activeFocusOnPress: false
279 onClicked: {
304 onClicked: {
280 for (var i = 0; i < ApplicationManager.availableApplications.length; i++) {
305 for (var i = 0; i < ApplicationManager.availableApplications.length; i++) {
281 var appId = ApplicationManager.availableApplications[i];
306 var appId = ApplicationManager.availableApplications[i];
@@ -285,7 +310,7 @@ Rectangle {
285 }
310 }
286
311
287 Repeater {
312 Repeater {
288− id: appRepeater
313+ id: appCheckBoxRepeater
289 model: ApplicationManager.availableApplications
314 model: ApplicationManager.availableApplications
290 ApplicationCheckBox {
315 ApplicationCheckBox {
291 appId: modelData
316 appId: modelData
@@ -586,6 +611,38 @@ Rectangle {
586 compare(ApplicationManager.get(0).appId, "unity8-dash");
611 compare(ApplicationManager.get(0).appId, "unity8-dash");
587 }
612 }
588
613
614+ function test_phoneLeftEdgeDrag_data() {
615+ return [
616+ {tag: "without launcher",
617+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
618+ launcherHides: true, greeterShown: false},
619+
620+ {tag: "with launcher",
621+ revealLauncher: true, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
622+ launcherHides: true, greeterShown: false},
623+
624+ {tag: "small swipe",
625+ revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
626+ launcherHides: false, greeterShown: false},
627+
628+ {tag: "long swipe",
629+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
630+ launcherHides: true, greeterShown: false},
631+
632+ {tag: "small swipe with greeter",
633+ revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
634+ launcherHides: false, greeterShown: true},
635+
636+ {tag: "long swipe with greeter",
637+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
638+ launcherHides: true, greeterShown: true},
639+
640+ {tag: "swipe over dash",
641+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "unity8-dash",
642+ launcherHides: false, greeterShown: false},
643+ ];
644+ }
645+
589 function test_snapDecisionDismissalReturnsFocus() {
646 function test_snapDecisionDismissalReturnsFocus() {
590 loadShell("phone");
647 loadShell("phone");
591 swipeAwayGreeter();
648 swipeAwayGreeter();
@@ -650,38 +707,6 @@ Rectangle {
650 mockNotificationsModel.append(n)
707 mockNotificationsModel.append(n)
651 }
708 }
652
709
653− function test_phoneLeftEdgeDrag_data() {
654− return [
655− {tag: "without launcher",
656− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
657− launcherHides: true, greeterShown: false},
658−
659− {tag: "with launcher",
660− revealLauncher: true, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
661− launcherHides: true, greeterShown: false},
662−
663− {tag: "small swipe",
664− revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
665− launcherHides: false, greeterShown: false},
666−
667− {tag: "long swipe",
668− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
669− launcherHides: true, greeterShown: false},
670−
671− {tag: "small swipe with greeter",
672− revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
673− launcherHides: false, greeterShown: true},
674−
675− {tag: "long swipe with greeter",
676− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
677− launcherHides: true, greeterShown: true},
678−
679− {tag: "swipe over dash",
680− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "unity8-dash",
681− launcherHides: false, greeterShown: false},
682− ];
683− }
684−
685 function test_phoneLeftEdgeDrag(data) {
710 function test_phoneLeftEdgeDrag(data) {
686 loadShell("phone");
711 loadShell("phone");
687 swipeAwayGreeter();
712 swipeAwayGreeter();
@@ -1380,7 +1405,7 @@ Rectangle {
1380 function test_tapOnRightEdgeReachesApplicationSurface() {
1405 function test_tapOnRightEdgeReachesApplicationSurface() {
1381 loadShell("phone");
1406 loadShell("phone");
1382 swipeAwayGreeter();
1407 swipeAwayGreeter();
1383− var topmostSpreadDelegate = findChild(shell, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
1408+ var topmostSpreadDelegate = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(0));
1384 verify(topmostSpreadDelegate);
1409 verify(topmostSpreadDelegate);
1385
1410
1386 waitUntilFocusedApplicationIsShowingItsSurface();
1411 waitUntilFocusedApplicationIsShowingItsSurface();
@@ -1388,7 +1413,7 @@ Rectangle {
1388 var topmostSurfaceItem = findChild(topmostSpreadDelegate, "surfaceItem");
1413 var topmostSurfaceItem = findChild(topmostSpreadDelegate, "surfaceItem");
1389 verify(topmostSurfaceItem);
1414 verify(topmostSurfaceItem);
1390
1415
1391− var rightEdgeDragArea = findChild(shell, "spreadDragArea");
1416+ var rightEdgeDragArea = findChild(shell, "rightEdgeDragArea");
1392 topmostSurfaceItem.touchPressCount = 0;
1417 topmostSurfaceItem.touchPressCount = 0;
1393 topmostSurfaceItem.touchReleaseCount = 0;
1418 topmostSurfaceItem.touchReleaseCount = 0;
1394
1419
@@ -1409,9 +1434,9 @@ Rectangle {
1409 function test_rightEdgeDragDoesNotReachApplicationSurface() {
1434 function test_rightEdgeDragDoesNotReachApplicationSurface() {
1410 loadShell("phone");
1435 loadShell("phone");
1411 swipeAwayGreeter();
1436 swipeAwayGreeter();
1412− var topmostSpreadDelegate = findChild(shell, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
1437+ var topmostSpreadDelegate = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(0));
1413 var topmostSurfaceItem = findChild(topmostSpreadDelegate, "surfaceItem");
1438 var topmostSurfaceItem = findChild(topmostSpreadDelegate, "surfaceItem");
1414− var rightEdgeDragArea = findChild(shell, "spreadDragArea");
1439+ var rightEdgeDragArea = findChild(shell, "rightEdgeDragArea");
1415
1440
1416 topmostSurfaceItem.touchPressCount = 0;
1441 topmostSurfaceItem.touchPressCount = 0;
1417 topmostSurfaceItem.touchReleaseCount = 0;
1442 topmostSurfaceItem.touchReleaseCount = 0;
@@ -1429,7 +1454,7 @@ Rectangle {
1429
1454
1430 function waitUntilFocusedApplicationIsShowingItsSurface()
1455 function waitUntilFocusedApplicationIsShowingItsSurface()
1431 {
1456 {
1432− var spreadDelegate = findChild(shell, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
1457+ var spreadDelegate = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(0));
1433 var appState = findInvisibleChild(spreadDelegate, "applicationWindowStateGroup");
1458 var appState = findInvisibleChild(spreadDelegate, "applicationWindowStateGroup");
1434 tryCompare(appState, "state", "surface");
1459 tryCompare(appState, "state", "surface");
1435 var transitions = appState.transitions;
1460 var transitions = appState.transitions;
@@ -1448,8 +1473,7 @@ Rectangle {
1448
1473
1449 // check if it's indeed showing the spread
1474 // check if it's indeed showing the spread
1450 var stage = findChild(shell, "stage");
1475 var stage = findChild(shell, "stage");
1451− var spreadView = findChild(stage, "spreadView");
1476+ tryCompare(stage, "state", "spread");
1452− tryCompare(spreadView, "phase", 2);
1453 }
1477 }
1454
1478
1455 function test_tapUbuntuIconInLauncherOverAppSpread() {
1479 function test_tapUbuntuIconInLauncherOverAppSpread() {
@@ -1485,8 +1509,7 @@ Rectangle {
1485 // check that the stage has left spread mode.
1509 // check that the stage has left spread mode.
1486 {
1510 {
1487 var stage = findChild(shell, "stage");
1511 var stage = findChild(shell, "stage");
1488− var spreadView = findChild(stage, "spreadView");
1512+ tryCompare(stage, "state", "staged");
1489− tryCompare(spreadView, "phase", 0);
1490 }
1513 }
1491
1514
1492 // check that the launcher got dismissed
1515 // check that the launcher got dismissed
@@ -1553,21 +1576,6 @@ Rectangle {
1553 }
1576 }
1554 }
1577 }
1555
1578
1556− function test_stageLoader_data() {
1557− return [
1558− {tag: "phone", source: "Stages/PhoneStage.qml", formFactor: "phone", usageScenario: "phone"},
1559− {tag: "tablet", source: "Stages/TabletStage.qml", formFactor: "tablet", usageScenario: "tablet"},
1560− {tag: "desktop", source: "Stages/DesktopStage.qml", formFactor: "tablet", usageScenario: "desktop"}
1561− ]
1562− }
1563−
1564− function test_stageLoader(data) {
1565− loadShell(data.formFactor);
1566− shell.usageScenario = data.usageScenario;
1567− var stageLoader = findChild(shell, "applicationsDisplayLoader");
1568− verify(String(stageLoader.source).indexOf(data.source) >= 0);
1569− }
1570−
1571 function test_launcherInverted_data() {
1579 function test_launcherInverted_data() {
1572 return [
1580 return [
1573 {tag: "phone", formFactor: "phone", usageScenario: "phone", launcherInverted: true},
1581 {tag: "phone", formFactor: "phone", usageScenario: "phone", launcherInverted: true},
@@ -1681,47 +1689,41 @@ Rectangle {
1681 function test_altTabWrapAround() {
1689 function test_altTabWrapAround() {
1682 loadDesktopShellWithApps();
1690 loadDesktopShellWithApps();
1683
1691
1684− var desktopStage = findChild(shell, "stage");
1685− verify(desktopStage !== null)
1686−
1687− var desktopSpread = findChild(shell, "spread");
1692+ var stage = findChild(shell, "stage");
1688− verify(desktopSpread !== null)
1693+ verify(stage !== null)
1689−
1690− var spreadContainer = findInvisibleChild(shell, "spreadContainer")
1691− verify(spreadContainer !== null)
1692
1694
1693− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater")
1695+ var spread = findChild(shell, "spreadItem");
1694− verify(spreadRepeater !== null)
1696+ verify(spread !== null)
1695
1697
1696 // remember the focused appId
1698 // remember the focused appId
1697 var focused = ApplicationManager.get(ApplicationManager.findApplication(ApplicationManager.focusedApplicationId));
1699 var focused = ApplicationManager.get(ApplicationManager.findApplication(ApplicationManager.focusedApplicationId));
1698
1700
1699− tryCompare(desktopSpread, "state", "")
1701+ tryCompare(stage, "state", "windowed")
1700
1702
1701 // Just press Alt, make sure the spread comes up
1703 // Just press Alt, make sure the spread comes up
1702 keyPress(Qt.Key_Alt);
1704 keyPress(Qt.Key_Alt);
1703 keyClick(Qt.Key_Tab);
1705 keyClick(Qt.Key_Tab);
1704− tryCompare(desktopSpread, "state", "altTab")
1706+ tryCompare(stage, "state", "spread")
1705− tryCompare(spreadRepeater, "highlightedIndex", 1)
1707+ tryCompare(spread, "highlightedIndex", 1)
1706 waitForRendering(shell)
1708 waitForRendering(shell)
1707
1709
1708 // Now press and hold Tab, make sure the highlight moves all the way but stops at the last one
1710 // Now press and hold Tab, make sure the highlight moves all the way but stops at the last one
1709 // We can't simulate a pressed key with keyPress() currently, so let's inject the events
1711 // We can't simulate a pressed key with keyPress() currently, so let's inject the events
1710 // at API level. Jump for 10 times, verify that it's still at the last one and didn't wrap around.
1712 // at API level. Jump for 10 times, verify that it's still at the last one and didn't wrap around.
1711 for (var i = 0; i < 10; i++) {
1713 for (var i = 0; i < 10; i++) {
1712− desktopSpread.selectNext(true); // true == isAutoRepeat
1714+ spread.selectNext(true); // true == isAutoRepeat
1713 wait(0); // Trigger the event loop to make sure all the things happen
1715 wait(0); // Trigger the event loop to make sure all the things happen
1714 }
1716 }
1715− tryCompare(spreadRepeater, "highlightedIndex", 6)
1717+ tryCompare(spread, "highlightedIndex", 6)
1716
1718
1717 // Now release it once, and verify that it does wrap around with an additional Tab press
1719 // Now release it once, and verify that it does wrap around with an additional Tab press
1718 keyRelease(Qt.Key_Tab);
1720 keyRelease(Qt.Key_Tab);
1719 keyClick(Qt.Key_Tab);
1721 keyClick(Qt.Key_Tab);
1720− tryCompare(spreadRepeater, "highlightedIndex", 0)
1722+ tryCompare(spread, "highlightedIndex", 0)
1721
1723
1722 // Release control, check if spread disappears
1724 // Release control, check if spread disappears
1723 keyRelease(Qt.Key_Alt)
1725 keyRelease(Qt.Key_Alt)
1724− tryCompare(desktopSpread, "state", "")
1726+ tryCompare(stage, "state", "windowed")
1725
1727
1726 // Make sure that after wrapping around once, we have the same one focused as at the beginning
1728 // Make sure that after wrapping around once, we have the same one focused as at the beginning
1727 var focusedAppSurface = focused.surfaceList.get(0);
1729 var focusedAppSurface = focused.surfaceList.get(0);
@@ -1732,30 +1734,30 @@ Rectangle {
1732 function test_altBackTabNavigation() {
1734 function test_altBackTabNavigation() {
1733 loadDesktopShellWithApps();
1735 loadDesktopShellWithApps();
1734
1736
1735− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1737+ var spreadItem = findChild(shell, "spreadItem");
1736− verify(spreadRepeater !== null);
1738+ verify(spreadItem !== null);
1737
1739
1738 keyPress(Qt.Key_Alt)
1740 keyPress(Qt.Key_Alt)
1739 keyClick(Qt.Key_Tab);
1741 keyClick(Qt.Key_Tab);
1740− tryCompare(spreadRepeater, "highlightedIndex", 1);
1742+ tryCompare(spreadItem, "highlightedIndex", 1);
1741
1743
1742 keyClick(Qt.Key_Tab);
1744 keyClick(Qt.Key_Tab);
1743− tryCompare(spreadRepeater, "highlightedIndex", 2);
1745+ tryCompare(spreadItem, "highlightedIndex", 2);
1744
1746
1745 keyClick(Qt.Key_Tab);
1747 keyClick(Qt.Key_Tab);
1746− tryCompare(spreadRepeater, "highlightedIndex", 3);
1748+ tryCompare(spreadItem, "highlightedIndex", 3);
1747
1749
1748 keyClick(Qt.Key_Tab);
1750 keyClick(Qt.Key_Tab);
1749− tryCompare(spreadRepeater, "highlightedIndex", 4);
1751+ tryCompare(spreadItem, "highlightedIndex", 4);
1750
1752
1751 keyClick(Qt.Key_Backtab);
1753 keyClick(Qt.Key_Backtab);
1752− tryCompare(spreadRepeater, "highlightedIndex", 3);
1754+ tryCompare(spreadItem, "highlightedIndex", 3);
1753
1755
1754 keyClick(Qt.Key_Backtab);
1756 keyClick(Qt.Key_Backtab);
1755− tryCompare(spreadRepeater, "highlightedIndex", 2);
1757+ tryCompare(spreadItem, "highlightedIndex", 2);
1756
1758
1757 keyClick(Qt.Key_Backtab);
1759 keyClick(Qt.Key_Backtab);
1758− tryCompare(spreadRepeater, "highlightedIndex", 1);
1760+ tryCompare(spreadItem, "highlightedIndex", 1);
1759
1761
1760 keyRelease(Qt.Key_Alt);
1762 keyRelease(Qt.Key_Alt);
1761 }
1763 }
@@ -1791,21 +1793,24 @@ Rectangle {
1791 function test_closeFromSpread() {
1793 function test_closeFromSpread() {
1792 loadDesktopShellWithApps()
1794 loadDesktopShellWithApps()
1793
1795
1794− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1796+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1797+ verify(appRepeater !== null);
1798+
1799+ var spreadItem = findChild(shell, "spreadItem");
1795− verify(spreadRepeater !== null);
1800+ verify(spreadItem !== null);
1796
1801
1797 keyPress(Qt.Key_Alt)
1802 keyPress(Qt.Key_Alt)
1798 keyClick(Qt.Key_Tab);
1803 keyClick(Qt.Key_Tab);
1799
1804
1800 var surfaceId = topLevelSurfaceList.idAt(2);
1805 var surfaceId = topLevelSurfaceList.idAt(2);
1801− var spreadDelegate2 = spreadRepeater.itemAt(2);
1806+ var spreadDelegate2 = appRepeater.itemAt(2);
1802 var closeMouseArea = findChild(spreadDelegate2, "closeMouseArea");
1807 var closeMouseArea = findChild(spreadDelegate2, "closeMouseArea");
1803
1808
1804 // Move the mosue over tile 2 and verify the close button becomes visible
1809 // Move the mosue over tile 2 and verify the close button becomes visible
1805 var x = 0;
1810 var x = 0;
1806 var y = shell.height * .5;
1811 var y = shell.height * .5;
1807 mouseMove(shell, x, y)
1812 mouseMove(shell, x, y)
1808− while (spreadRepeater.highlightedIndex !== 2 && x <= 4000) {
1813+ while (spreadItem.highlightedIndex !== 2 && x <= 4000) {
1809 x+=10;
1814 x+=10;
1810 mouseMove(shell, x, y)
1815 mouseMove(shell, x, y)
1811 wait(0); // spin the loop so bindings get evaluated
1816 wait(0); // spin the loop so bindings get evaluated
@@ -1835,37 +1840,37 @@ Rectangle {
1835 loadDesktopShellWithApps()
1840 loadDesktopShellWithApps()
1836
1841
1837 var stage = findChild(shell, "stage");
1842 var stage = findChild(shell, "stage");
1838− var spread = findChild(stage, "spread");
1843+ var spreadItem = findChild(stage, "spreadItem");
1839− waitForRendering(spread)
1844+// waitForRendering(spread)
1840
1845
1841− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1846+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1842− verify(spreadRepeater !== null);
1847+ verify(appRepeater !== null);
1843
1848
1844 keyPress(Qt.Key_Alt)
1849 keyPress(Qt.Key_Alt)
1845 keyClick(Qt.Key_Tab);
1850 keyClick(Qt.Key_Tab);
1846
1851
1847 var surface = topLevelSurfaceList.surfaceAt(2);
1852 var surface = topLevelSurfaceList.surfaceAt(2);
1848− var spreadDelegate2 = spreadRepeater.itemAt(2);
1853+ var spreadDelegate2 = appRepeater.itemAt(2);
1849− var clippedSpreadDelegate = findChild(spreadDelegate2, "clippedSpreadDelegate");
1854+ var decoratedWindow = findChild(spreadDelegate2, "decoratedWindow");
1850
1855
1851− tryCompare(spread, "state", "altTab");
1856+ tryCompare(stage, "state", "spread");
1852
1857
1853 // Move the mouse over tile 2 and verify the highlight becomes visible
1858 // Move the mouse over tile 2 and verify the highlight becomes visible
1854 var x = 0;
1859 var x = 0;
1855− var y = shell.height * (data.tileInfo ? .95 : 0.5)
1860+ var y = shell.height * (data.tileInfo ? .9 : 0.5)
1856 mouseMove(shell, x, y)
1861 mouseMove(shell, x, y)
1857− while (spreadRepeater.highlightedIndex !== 2 && x <= 4000) {
1862+ while (spreadItem.highlightedIndex !== 2 && x <= 4000) {
1858 x+=10;
1863 x+=10;
1859 mouseMove(shell, x, y)
1864 mouseMove(shell, x, y)
1860 wait(0); // spin the loop so bindings get evaluated
1865 wait(0); // spin the loop so bindings get evaluated
1861 }
1866 }
1862− tryCompare(clippedSpreadDelegate, "highlightShown", true);
1867+ tryCompare(decoratedWindow, "showHighlight", true);
1863
1868
1864 // Click the tile
1869 // Click the tile
1865− mouseClick(clippedSpreadDelegate, clippedSpreadDelegate.width / 2, clippedSpreadDelegate.height / 2)
1870+ mouseClick(decoratedWindow, units.gu(2), decoratedWindow.height / 2)
1866
1871
1867 // Verify that we left the spread and app2 is the focused one now
1872 // Verify that we left the spread and app2 is the focused one now
1868− tryCompare(stage, "state", "");
1873+ tryCompare(stage, "state", "windowed");
1869 tryCompare(surface, "focused", true);
1874 tryCompare(surface, "focused", true);
1870
1875
1871 keyRelease(Qt.Key_Alt);
1876 keyRelease(Qt.Key_Alt);
@@ -1927,41 +1932,6 @@ Rectangle {
1927 tryCompare(hoverMouseArea, "visible", false)
1932 tryCompare(hoverMouseArea, "visible", false)
1928 }
1933 }
1929
1934
1930− function test_workspacePreviewsHighlightedApp() {
1931− loadDesktopShellWithApps()
1932−
1933− var targetZ = topLevelSurfaceList.count + 1;
1934−
1935− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1936− verify(spreadRepeater !== null);
1937−
1938− var appRepeater = findInvisibleChild(shell, "appRepeater");
1939− verify(appRepeater !== null);
1940−
1941− keyPress(Qt.Key_Alt)
1942− keyClick(Qt.Key_Tab);
1943−
1944− tryCompare(spreadRepeater, "highlightedIndex", 1);
1945− tryCompare(appRepeater.itemAt(1), "z", targetZ)
1946−
1947− var x = 0;
1948− var y = shell.height * .75;
1949− mouseMove(shell, x, y)
1950−
1951− for (var i = 0; i < 7; i++) {
1952− while (spreadRepeater.highlightedIndex != i && x <= 4000) {
1953− tryCompare(appRepeater.itemAt(spreadRepeater.highlightedIndex), "z", targetZ)
1954− x+=10;
1955− mouseMove(shell, x, y)
1956− wait(0); // spin the loop so bindings get evaluated
1957− }
1958− }
1959−
1960− verify(y < 4000);
1961−
1962− keyRelease(Qt.Key_Alt);
1963− }
1964−
1965 function test_focusAppFromLauncherExitsSpread_data() {
1935 function test_focusAppFromLauncherExitsSpread_data() {
1966 return [
1936 return [
1967 {tag: "autohide launcher", launcherLocked: false },
1937 {tag: "autohide launcher", launcherLocked: false },
@@ -1972,7 +1942,7 @@ Rectangle {
1972 function test_focusAppFromLauncherExitsSpread(data) {
1942 function test_focusAppFromLauncherExitsSpread(data) {
1973 loadDesktopShellWithApps()
1943 loadDesktopShellWithApps()
1974 var launcher = findChild(shell, "launcher");
1944 var launcher = findChild(shell, "launcher");
1975− var desktopSpread = findChild(shell, "spread");
1945+ var stage = findChild(shell, "stage");
1976 var bfb = findChild(launcher, "buttonShowDashHome");
1946 var bfb = findChild(launcher, "buttonShowDashHome");
1977
1947
1978 GSettingsController.setAutohideLauncher(!data.launcherLocked);
1948 GSettingsController.setAutohideLauncher(!data.launcherLocked);
@@ -1981,7 +1951,7 @@ Rectangle {
1981 keyPress(Qt.Key_Alt)
1951 keyPress(Qt.Key_Alt)
1982 keyClick(Qt.Key_Tab);
1952 keyClick(Qt.Key_Tab);
1983
1953
1984− tryCompare(desktopSpread, "state", "altTab")
1954+ tryCompare(stage, "state", "spread")
1985
1955
1986 if (!data.launcherLocked) {
1956 if (!data.launcherLocked) {
1987 revealLauncherByEdgePushWithMouse();
1957 revealLauncherByEdgePushWithMouse();
@@ -1994,7 +1964,7 @@ Rectangle {
1994 if (!data.launcherLocked) {
1964 if (!data.launcherLocked) {
1995 tryCompare(launcher, "state", "")
1965 tryCompare(launcher, "state", "")
1996 }
1966 }
1997− tryCompare(desktopSpread, "state", "")
1967+ tryCompare(stage, "state", "windowed")
1998
1968
1999 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash")
1969 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash")
2000
1970
@@ -2164,10 +2134,10 @@ Rectangle {
2164
2134
2165 // Sanity checking
2135 // Sanity checking
2166 if (data.usageScenario === "tablet") {
2136 if (data.usageScenario === "tablet") {
2167− var app1Delegate = findChild(shell, "spreadDelegate_" + app1SurfaceId);
2137+ var app1Delegate = findChild(shell, "appDelegate_" + app1SurfaceId);
2168 compare(app1Delegate.stage, ApplicationInfoInterface.MainStage);
2138 compare(app1Delegate.stage, ApplicationInfoInterface.MainStage);
2169
2139
2170− var app2Delegate = findChild(shell, "spreadDelegate_" + app2SurfaceId);
2140+ var app2Delegate = findChild(shell, "appDelegate_" + app2SurfaceId);
2171 compare(app2Delegate.stage, ApplicationInfoInterface.MainStage);
2141 compare(app2Delegate.stage, ApplicationInfoInterface.MainStage);
2172 }
2142 }
2173 verify(!app1.isTouchApp);
2143 verify(!app1.isTouchApp);
@@ -2205,10 +2175,10 @@ Rectangle {
2205
2175
2206 // Sanity checking
2176 // Sanity checking
2207 if (data.usageScenario === "tablet") {
2177 if (data.usageScenario === "tablet") {
2208− var app1Delegate = findChild(shell, "spreadDelegate_" + app1SurfaceId);
2178+ var app1Delegate = findChild(shell, "appDelegate_" + app1SurfaceId);
2209 compare(app1Delegate.stage, ApplicationInfoInterface.MainStage);
2179 compare(app1Delegate.stage, ApplicationInfoInterface.MainStage);
2210
2180
2211− var app2Delegate = findChild(shell, "spreadDelegate_" + app2SurfaceId);
2181+ var app2Delegate = findChild(shell, "appDelegate_" + app2SurfaceId);
2212 compare(app2Delegate.stage, ApplicationInfoInterface.MainStage);
2182 compare(app2Delegate.stage, ApplicationInfoInterface.MainStage);
2213 }
2183 }
2214
2184
@@ -2295,19 +2265,19 @@ Rectangle {
2295 function test_superTabToCycleLauncher(data) {
2265 function test_superTabToCycleLauncher(data) {
2296 loadShell("desktop");
2266 loadShell("desktop");
2297 shell.usageScenario = "desktop";
2267 shell.usageScenario = "desktop";
2268+ waitForRendering(shell);
2298 GSettingsController.setAutohideLauncher(!data.launcherLocked);
2269 GSettingsController.setAutohideLauncher(!data.launcherLocked);
2299 waitForRendering(shell);
2270 waitForRendering(shell);
2300
2271
2272+ var stage = findChild(shell, "stage");
2301 var launcher = findChild(shell, "launcher");
2273 var launcher = findChild(shell, "launcher");
2302 var launcherPanel = findChild(launcher, "launcherPanel");
2274 var launcherPanel = findChild(launcher, "launcherPanel");
2303 var firstAppInLauncher = LauncherModel.get(0).appId;
2275 var firstAppInLauncher = LauncherModel.get(0).appId;
2304−
2305 compare(launcher.state, data.launcherLocked ? "visible": "");
2276 compare(launcher.state, data.launcherLocked ? "visible": "");
2306 compare(launcherPanel.highlightIndex, -2);
2277 compare(launcherPanel.highlightIndex, -2);
2307 compare(ApplicationManager.focusedApplicationId, "unity8-dash");
2278 compare(ApplicationManager.focusedApplicationId, "unity8-dash");
2308
2279
2309 // Use Super + Tab Tab to cycle to the first entry in the launcher
2280 // Use Super + Tab Tab to cycle to the first entry in the launcher
2310− wait(1000);
2311 keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2281 keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2312 keyClick(Qt.Key_Tab);
2282 keyClick(Qt.Key_Tab);
2313 tryCompare(launcher, "state", "visible");
2283 tryCompare(launcher, "state", "visible");
@@ -2328,6 +2298,7 @@ Rectangle {
2328 tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
2298 tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
2329 tryCompare(launcherPanel, "highlightIndex", -2);
2299 tryCompare(launcherPanel, "highlightIndex", -2);
2330 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2300 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2301+ tryCompare(stage, "focus", true)
2331 }
2302 }
2332
2303
2333 function test_longpressSuperOpensLauncherAndShortcutsOverlay() {
2304 function test_longpressSuperOpensLauncherAndShortcutsOverlay() {
@@ -2388,6 +2359,7 @@ Rectangle {
2388 waitForRendering(shell);
2359 waitForRendering(shell);
2389 var appContainer = findChild(shell, "appContainer");
2360 var appContainer = findChild(shell, "appContainer");
2390 var launcher = findChild(shell, "launcher");
2361 var launcher = findChild(shell, "launcher");
2362+ var launcherPanel = findChild(launcher, "launcherPanel");
2391
2363
2392 var appSurfaceId = topLevelSurfaceList.nextId;
2364 var appSurfaceId = topLevelSurfaceList.nextId;
2393 var app = ApplicationManager.startApplication("music-app");
2365 var app = ApplicationManager.startApplication("music-app");
@@ -2398,10 +2370,12 @@ Rectangle {
2398 waitForRendering(shell);
2370 waitForRendering(shell);
2399
2371
2400 GSettingsController.setAutohideLauncher(true);
2372 GSettingsController.setAutohideLauncher(true);
2373+ tryCompare(launcherPanel, "x", -launcher.panelWidth)
2401 waitForRendering(shell)
2374 waitForRendering(shell)
2402 var hiddenSize = appDelegate.width;
2375 var hiddenSize = appDelegate.width;
2403
2376
2404 GSettingsController.setAutohideLauncher(false);
2377 GSettingsController.setAutohideLauncher(false);
2378+ tryCompare(launcherPanel, "x", 0)
2405 waitForRendering(shell)
2379 waitForRendering(shell)
2406 var shownSize = appDelegate.width;
2380 var shownSize = appDelegate.width;
2407
2381
@@ -2439,9 +2413,9 @@ Rectangle {
2439
2413
2440 function test_inputEventsOnEdgesEndUpInAppSurface_data() {
2414 function test_inputEventsOnEdgesEndUpInAppSurface_data() {
2441 return [
2415 return [
2442− { tag: "phone", repeaterName: "spreadRepeater" },
2416+ { tag: "phone" },
2443− { tag: "tablet", repeaterName: "spreadRepeater" },
2417+ { tag: "tablet" },
2444− { tag: "desktop", repeaterName: "appRepeater" },
2418+ { tag: "desktop" },
2445 ]
2419 ]
2446 }
2420 }
2447
2421
@@ -2456,7 +2430,7 @@ Rectangle {
2456 var app = ApplicationManager.startApplication("camera-app");
2430 var app = ApplicationManager.startApplication("camera-app");
2457 waitUntilAppWindowIsFullyLoaded(appSurfaceId);
2431 waitUntilAppWindowIsFullyLoaded(appSurfaceId);
2458
2432
2459− var appRepeater = findChild(shell, data.repeaterName);
2433+ var appRepeater = findChild(shell, "appRepeater");
2460 var topmostAppDelegate = appRepeater.itemAt(0);
2434 var topmostAppDelegate = appRepeater.itemAt(0);
2461 verify(topmostAppDelegate);
2435 verify(topmostAppDelegate);
2462
2436
@@ -2731,5 +2705,41 @@ Rectangle {
2731 tryCompare(topLevelSurfaceList, "count", countBeforeClose - 1);
2705 tryCompare(topLevelSurfaceList, "count", countBeforeClose - 1);
2732 tryCompareFunction(function() { return ApplicationManager.focusedApplicationId; }, "calendar-app");
2706 tryCompareFunction(function() { return ApplicationManager.focusedApplicationId; }, "calendar-app");
2733 }
2707 }
2708+
2709+ function test_oskDisplacesWindow_data() {
2710+ return [
2711+ {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5), oskEnabled: true},
2712+ {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
2713+ {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
2714+ {tag: "osk not on this screen", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: units.gu(10), oskEnabled: false},
2715+ ]
2716+ }
2717+
2718+ function test_oskDisplacesWindow(data) {
2719+ loadShell("desktop");
2720+ shell.usageScenario = "desktop";
2721+ waitForRendering(shell);
2722+ swipeAwayGreeter();
2723+ shell.oskEnabled = data.oskEnabled;
2724+
2725+ var oldOSKState = SurfaceManager.inputMethodSurface.state;
2726+ SurfaceManager.inputMethodSurface.state = Mir.RestoredState;
2727+ var appRepeater = findChild(shell, "appRepeater");
2728+ var dashAppDelegate = appRepeater.itemAt(0);
2729+ verify(dashAppDelegate);
2730+ dashAppDelegate.requestedHeight = data.windowHeight;
2731+ dashAppDelegate.requestedY = data.windowY;
2732+ SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
2733+ var initialY = dashAppDelegate.y;
2734+ print("intial", initialY, "panel", PanelState.panelHeight);
2735+ verify(initialY > PanelState.panelHeight);
2736+
2737+ SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));
2738+ tryCompare(dashAppDelegate, "y", data.targetDisplacement);
2739+
2740+ SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
2741+ tryCompare(dashAppDelegate, "y", initialY);
2742+ SurfaceManager.inputMethodSurface.state = oldOSKState;
2743+ }
2734 }
2744 }
2735}
2745}
tests/qmltests/tst_ShellWithPin.qml+9−11
@@ -393,24 +393,23 @@ Item {
393 // dialer to a side stage and give access to other apps. So just
393 // dialer to a side stage and give access to other apps. So just
394 // confirm that such an attack doesn't work.
394 // confirm that such an attack doesn't work.
395
395
396− var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader")
396+ var stage = findChild(shell, "stage")
397
397
398 // We start in phone mode
398 // We start in phone mode
399− compare(shell.usageScenario, "phone");
400− compare(applicationsDisplayLoader.usageScenario, "phone");
399+ compare(stage.usageScenario, "phone");
401
400
402 tap(findChild(shell, "emergencyCallLabel"));
401 tap(findChild(shell, "emergencyCallLabel"));
403 confirmLockedApp("dialer-app")
402 confirmLockedApp("dialer-app")
404
403
405 // OK, we're in. Now try (but fail) to switch to tablet mode
404 // OK, we're in. Now try (but fail) to switch to tablet mode
406 shell.usageScenario = "tablet";
405 shell.usageScenario = "tablet";
407− compare(applicationsDisplayLoader.usageScenario, "phone");
406+ compare(stage.usageScenario, "phone");
408
407
409 // And when we kill the app, we go back to locked tablet mode
408 // And when we kill the app, we go back to locked tablet mode
410 killApps()
409 killApps()
411 var greeter = findChild(shell, "greeter")
410 var greeter = findChild(shell, "greeter")
412 tryCompare(greeter, "fullyShown", true)
411 tryCompare(greeter, "fullyShown", true)
413− compare(applicationsDisplayLoader.usageScenario, "tablet");
412+ compare(stage.usageScenario, "tablet");
414 }
413 }
415
414
416 function test_emergencyDialerIncoming() {
415 function test_emergencyDialerIncoming() {
@@ -497,13 +496,13 @@ Item {
497
496
498 function test_suspend() {
497 function test_suspend() {
499 var greeter = findChild(shell, "greeter");
498 var greeter = findChild(shell, "greeter");
500− var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader")
499+ var stage = findChild(shell, "stage")
501
500
502 // Put it to sleep
501 // Put it to sleep
503 Powerd.setStatus(Powerd.Off, Powerd.Unknown);
502 Powerd.setStatus(Powerd.Off, Powerd.Unknown);
504
503
505− // If locked, applicationsDisplayLoader.item.suspended should be true
504+ // If locked, stage.suspended should be true
506− tryCompare(applicationsDisplayLoader.item, "suspended", true);
505+ tryCompare(stage, "suspended", true);
507
506
508 // And wake up
507 // And wake up
509 Powerd.setStatus(Powerd.On, Powerd.Unknown);
508 Powerd.setStatus(Powerd.On, Powerd.Unknown);
@@ -513,13 +512,12 @@ Item {
513 swipeAwayGreeter(true);
512 swipeAwayGreeter(true);
514
513
515 // We have a lockscreen, make sure we're still suspended
514 // We have a lockscreen, make sure we're still suspended
516− tryCompare(applicationsDisplayLoader.item, "suspended", true);
515+ tryCompare(stage, "suspended", true);
517
516
518 enterPin("1234")
517 enterPin("1234")
519
518
520 // Now that the lockscreen has gone too, make sure we're waking up
519 // Now that the lockscreen has gone too, make sure we're waking up
521− tryCompare(applicationsDisplayLoader.item, "suspended", false);
520+ tryCompare(stage, "suspended", false);
522−
523 }
521 }
524
522
525 /* We had a bug (1395075) where if a user kept swiping as the greeter
523 /* We had a bug (1395075) where if a user kept swiping as the greeter